diff --git a/DEPS b/DEPS
index 8bbf1879..ef3efb4 100644
--- a/DEPS
+++ b/DEPS
@@ -220,7 +220,7 @@
   #
   # CQ_INCLUDE_TRYBOTS=luci.chrome.try:lacros-amd64-generic-chrome-skylab
   # CQ_INCLUDE_TRYBOTS=luci.chrome.try:lacros-arm-generic-chrome-skylab
-  'lacros_sdk_version': '15399.0.0',
+  'lacros_sdk_version': '15419.0.0',
 
   # Generate location tag metadata to include in tests result data uploaded
   # to ResultDB. This isn't needed on some configs and the tool that generates
@@ -285,15 +285,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '06e448c556c49188b430e165e7ebe6c85fbcc830',
+  'skia_revision': '2d0b05335104bfe49bb219af1ba111ee0e9a6b03',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '42d4695bb00990c1111176dae0b2f9c68dc542d1',
+  'v8_revision': 'def49d3eed33221e91ffb11d45a2a8f33f7eebf6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'e553b901569db72c4afc7b432e772c283b6ef967',
+  'angle_revision': 'd0148f12bc1226a045b1b28e1a4be89e5012ef12',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -312,7 +312,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
-  'fuchsia_version': 'version:12.20230414.2.1',
+  'fuchsia_version': 'version:12.20230416.0.1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -372,7 +372,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '5f31e66dbf881b8021705ee089186c47bdde5e23',
+  'devtools_frontend_revision': 'f3de8a4541393a1253b29a2613c6f3af7802a104',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -412,7 +412,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'a20c1ee82d29948c029b60af5ec3da2ffee34af4',
+  'dawn_revision': '4bfdd18e7dd444d27fb439c4888d87b86281c03d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -436,7 +436,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nearby
   # and whatever else without interference from each other.
-  'nearby_revision': '00bba362199fbe4d462775e10d2e825a9ee772ce',
+  'nearby_revision': '6cdc9890b5f83ff731a6363a785272bd1a75f87e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling securemessage
   # and whatever else without interference from each other.
@@ -456,11 +456,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'libcxxabi_revision':    '46d77edb733d1941b7650a8198ac1beff20a157a',
+  'libcxxabi_revision':    'e33143c8c06000c3fe12fe3cf88d775f5f3f5b5a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'libunwind_revision':    'a2c40b7ecbf068e3d3cc74b3bf0f7bfc6ef54f62',
+  'libunwind_revision':    'f2d62ea5af23f5d734725a7b11ea17ad961fa5d7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -476,7 +476,7 @@
 
   # If you change this, also update the libc++ revision in
   # //buildtools/deps_revisions.gni.
-  'libcxx_revision':       '5488b5c294dd4b9640adbef628f2dcd6f85a6c09',
+  'libcxx_revision':       '7df372d6fd11d11382866df8f549b352ef2a6520',
 
   # GN CIPD package version.
   'gn_version': 'git_revision:ffeea1b1fd070cb6a8d47154a03f8523486b50a7',
@@ -771,7 +771,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '9b822fbdde20e377a72a5d6da4d3beb7fc9288c0',
+    'fa13b0a4f62ca82ff90a2db4d5fec12899673ef9',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -800,7 +800,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '45dcfdfb001bcc653976179a2b727506564e6188',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '94a060f87d45c2e4192b3d12034d48f55f209c03',
       'condition': 'checkout_ios',
   },
 
@@ -870,7 +870,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/linux-amd64',
-          'version': 'aToaFX6duMI65ekJDh7a986ZDpYdoxWpvSqSUJZncHgC',
+          'version': 'GTmhew7QPPd8PV-NrJuk7NbwCKhD-vhMvF4c9EsL8yAC',
         },
       ],
       'dep_type': 'cipd',
@@ -881,7 +881,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/mac-amd64',
-          'version': '6wkuKzlWCOKuxuvCh9NieBgQl29Z_OIJ6vQLlP9EasQC',
+          'version': 'qdlIw---NekxjCVzcQkHyAB-aHZrbOSpotGBi4UjQMIC',
         },
       ],
       'dep_type': 'cipd',
@@ -892,7 +892,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/windows-amd64',
-          'version': 'pDELQXLX16X8uuFXC4HFWzYgbUDLM6F1bUc3mdIqjkMC',
+          'version': 'wcp-1v5v8-TF1AdRRo-QZ6MHBqErxIWXhFCO3WKXqrQC',
         },
       ],
       'dep_type': 'cipd',
@@ -960,7 +960,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'lFc_klEJZUxS7DOOp7ntguh9s_BntjOYTGFeDi9HIwQC',
+          'version': 'JJlbXbw6nZkaTao3F4UKPt4gAbq_CL7ge2ZKCaWuaZIC',
       },
     ],
     'condition': 'checkout_android',
@@ -1009,7 +1009,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/bundletool',
-               'version': 'TpDdbF-PPgwL0iOVsdLM07L-DUp2DV3hgzCMmPd2_GUC',
+               'version': 'xnKkaX2u7XVfsUzExic0KW3jYMINpI16Ll9QYESBoI8C',
           },
       ],
       'condition': 'checkout_android',
@@ -1081,7 +1081,7 @@
     Var('chromium_git') + '/angle/angle.git' + '@' +  Var('angle_revision'),
 
   'src/third_party/content_analysis_sdk/src':
-    Var('chromium_git') + '/external/github.com/chromium/content_analysis_sdk.git' + '@' + 'c479cb95affdcb14bab7f20a10eeade0cc449c04',
+    Var('chromium_git') + '/external/github.com/chromium/content_analysis_sdk.git' + '@' + 'b8744f00646d175057f0be7443c7c72a311b5381',
 
   'src/third_party/dav1d/libdav1d':
     Var('chromium_git') + '/external/github.com/videolan/dav1d.git' + '@' + 'd426d1c91075b9c552b12dd052af1cd0368f05a2',
@@ -1163,7 +1163,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '530a1bcfd20a273cc5cc0589c0b9fbd9071d7fcb',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '59f0834b8a394a8ac2faa727645cd50423e10362',
       'condition': 'checkout_chromeos',
   },
 
@@ -1195,13 +1195,13 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4a2243196c2b9c2fc1a040429dad67cbff5aa703',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '97dadd025f541f67af48417cc12ebdc00c1ad29c',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '47383c1bf9d47c7c2a7b1514881f2e9ff58357a5',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '386544b8650fe6565f663e74c28ff8d5395345bd',
     'condition': 'checkout_src_internal',
   },
 
@@ -1676,7 +1676,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '7c24af6f73e50d66dc0d9ac866fb4a4d788e8822',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '52e8dd233b135f87fbe2495ff36d6ae30be124c4',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1716,7 +1716,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/r8',
-              'version': 'OJEhACoTcZTFN4k6C2BsgW7xzXm818cNOV_6yhZZHwkC',
+              'version': 'bkihvyDExjKlMVd5GRx1Dxfyp94xqRmUDHHQW3ZUtmAC',
           },
       ],
       'condition': 'checkout_android',
@@ -1858,10 +1858,10 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '3171daccdd89ae5c693399bc0c18db4c381527a1',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'c7d833badcd37dc46a999ebeebbbde1368ff15b5',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'fa6da49db39d759f141c528deaf6b1cdc80fc30f',
+    Var('webrtc_git') + '/src.git' + '@' + '0774b8f4fe5a439483cfd3c31b96267146ca9e52',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -1951,7 +1951,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': Var('chrome_git') + '/chrome/src-internal.git@eb97223d117f7cd788b68c9c3127904eddbc8315',
+    'url': Var('chrome_git') + '/chrome/src-internal.git@64529753f43f862e96c0bae560f70056dcd0f952',
     'condition': 'checkout_src_internal',
   },
 
@@ -1981,7 +1981,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': '7lwh3CEwHoCR_Ill7TsFUDxeV2CpxxrHECs4AzVCYGkC',
+        'version': 'c9vTnBYaO1ijEB63xHRis-5XaA1myiMRIO8vCuYTvS8C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -2014,7 +2014,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 't2FOm58CRa6T2UYTnWpzi2VBUiuJHMgO8qoIQw7Ag_gC',
+        'version': 'oTQaM4-sJj85sRANLSJZ2kF3S5oEK-07Jj0GQUD8uTsC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/lib/BUILD.gn b/android_webview/lib/BUILD.gn
index 5174037..c1e003a4 100644
--- a/android_webview/lib/BUILD.gn
+++ b/android_webview/lib/BUILD.gn
@@ -74,6 +74,6 @@
 
   if (webview_includes_weblayer) {
     defines += [ "WEBVIEW_INCLUDES_WEBLAYER" ]
-    deps += [ "//weblayer:weblayer_lib_webview" ]
+    deps += [ "//weblayer:weblayer_lib" ]
   }
 }
diff --git a/android_webview/lib/webview_entry_point.cc b/android_webview/lib/webview_entry_point.cc
index 221fbce..6443530 100644
--- a/android_webview/lib/webview_entry_point.cc
+++ b/android_webview/lib/webview_entry_point.cc
@@ -12,7 +12,6 @@
 #endif
 #if defined(WEBVIEW_INCLUDES_WEBLAYER)
 #include "weblayer/app/jni_onload.h"
-#include "weblayer/browser/web_view_compatibility_helper_impl.h"
 #endif
 
 namespace {
@@ -49,10 +48,6 @@
 // Most of the initialization is done in LibraryLoadedOnMainThread(), not here.
 JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
   base::android::InitVM(vm);
-#if defined(WEBVIEW_INCLUDES_WEBLAYER)
-  if (!weblayer::MaybeRegisterNatives())
-    return -1;
-#endif
   base::android::SetNativeInitializationHook(&NativeInit);
   return JNI_VERSION_1_4;
 }
diff --git a/android_webview/nonembedded/java/AndroidManifest.xml b/android_webview/nonembedded/java/AndroidManifest.xml
index ef918ea..70b71fe 100644
--- a/android_webview/nonembedded/java/AndroidManifest.xml
+++ b/android_webview/nonembedded/java/AndroidManifest.xml
@@ -45,6 +45,10 @@
                  {% if force_32_bit is defined and force_32_bit == 'true' %}
                  android:use32bitAbi="true"
                  {% endif %}
+                 {# TODO(crbug.com/1411557): Remove #}
+                 {% if force_32_bit is not defined %}
+                 {{ use32bitAbi|default('android:use32bitAbi="true"') }}
+                 {% endif %}
                  android:extractNativeLibs="false">
         {# This part is shared between stand-alone WebView and Monochrome #}
         {% macro common(manifest_package, webview_lib) %}
diff --git a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/JsReplyProxyBoundaryInterface.java b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/JsReplyProxyBoundaryInterface.java
index 046b157..d8ad2b1 100644
--- a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/JsReplyProxyBoundaryInterface.java
+++ b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/JsReplyProxyBoundaryInterface.java
@@ -4,9 +4,14 @@
 
 package org.chromium.support_lib_boundary;
 
+import java.lang.reflect.InvocationHandler;
+
 /**
  * Boundary interface for org.chromium.android_webview.WebMessageListener.
  */
 public interface JsReplyProxyBoundaryInterface extends IsomorphicObjectBoundaryInterface {
+    @Deprecated
     void postMessage(String message);
+
+    void postMessageWithPayload(/* MessagePayload */ InvocationHandler payload);
 }
diff --git a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java
index a0e17e5..19552a1 100644
--- a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java
+++ b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/Features.java
@@ -105,11 +105,12 @@
     public static final String SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL =
             "SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL";
 
+    // JsReplyProxy.postMessageWithPayload
     // WebMessage.getMessagePayload
-    // WebMessagePayload.getType
-    // WebMessagePayload.getAsString
     // WebMessagePayload.getAsArrayBuffer
-    public static final String WEB_MESSAGE_GET_MESSAGE_PAYLOAD = "WEB_MESSAGE_GET_MESSAGE_PAYLOAD";
+    // WebMessagePayload.getAsString
+    // WebMessagePayload.getType
+    public static final String WEB_MESSAGE_ARRAY_BUFFER = "WEB_MESSAGE_ARRAY_BUFFER";
 
     // WebMessagePortCompat.postMessage
     public static final String WEB_MESSAGE_PORT_POST_MESSAGE = "WEB_MESSAGE_PORT_POST_MESSAGE";
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibJsReplyProxyAdapter.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibJsReplyProxyAdapter.java
index 3d6b886..76355041 100644
--- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibJsReplyProxyAdapter.java
+++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibJsReplyProxyAdapter.java
@@ -12,6 +12,8 @@
 import org.chromium.support_lib_boundary.JsReplyProxyBoundaryInterface;
 import org.chromium.support_lib_glue.SupportLibWebViewChromiumFactory.ApiCall;
 
+import java.lang.reflect.InvocationHandler;
+
 /**
  * Adapter between JsReplyProxyBoundaryInterface and JsReplyProxy.
  */
@@ -26,11 +28,16 @@
     @Override
     public void postMessage(String message) {
         recordApiCall(ApiCall.JS_REPLY_POST_MESSAGE);
-        // TODO(crbug.com/1374142): Adopt MessagePayload in AndroidX.
         mReplyProxy.postMessage(new MessagePayload(message));
     }
 
     @Override
+    public void postMessageWithPayload(/* MessagePayload */ InvocationHandler payload) {
+        recordApiCall(ApiCall.JS_REPLY_POST_MESSAGE_WITH_PAYLOAD);
+        mReplyProxy.postMessage(SupportLibWebMessagePayloadAdapter.toMessagePayload(payload));
+    }
+
+    @Override
     /* package */ AwSupportLibIsomorphic getPeeredObject() {
         return mReplyProxy;
     }
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessageAdapter.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessageAdapter.java
index a71d7570..00e03f2 100644
--- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessageAdapter.java
+++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessageAdapter.java
@@ -48,6 +48,6 @@
     @Override
     public String[] getSupportedFeatures() {
         // getData() and getPorts() are not covered by feature flags.
-        return new String[] {Features.WEB_MESSAGE_GET_MESSAGE_PAYLOAD};
+        return new String[] {Features.WEB_MESSAGE_ARRAY_BUFFER};
     }
 }
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessageListenerAdapter.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessageListenerAdapter.java
index c0c0ad59..96f6ef8 100644
--- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessageListenerAdapter.java
+++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessageListenerAdapter.java
@@ -30,8 +30,8 @@
     private static final String TAG = "WebMsgLtrAdptr";
 
     private final WebView mWebView;
-    private WebMessageListenerBoundaryInterface mImpl;
-    private String[] mSupportedFeatures;
+    private final WebMessageListenerBoundaryInterface mImpl;
+    private final String[] mSupportedFeatures;
 
     public SupportLibWebMessageListenerAdapter(
             WebView webView, /* WebMessageListener */ InvocationHandler handler) {
@@ -54,16 +54,20 @@
             return;
         }
 
-        // TODO(crbug.com/1374142): Add array buffer type support.
-        if (payload.getType() != MessagePayloadType.STRING) {
-            return;
+        if (payload.getType() == MessagePayloadType.STRING
+                || (payload.getType() == MessagePayloadType.ARRAY_BUFFER
+                        && BoundaryInterfaceReflectionUtil.containsFeature(
+                                mSupportedFeatures, Features.WEB_MESSAGE_ARRAY_BUFFER))) {
+            mImpl.onPostMessage(mWebView,
+                    BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(
+                            new SupportLibWebMessageAdapter(payload, ports)),
+                    sourceOrigin, isMainFrame,
+                    BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(
+                            new SupportLibJsReplyProxyAdapter(replyProxy)));
+        } else {
+            Log.e(TAG,
+                    "The AndroidX doesn't support payload type: "
+                            + MessagePayload.typeToString(payload.getType()));
         }
-
-        mImpl.onPostMessage(mWebView,
-                BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(
-                        new SupportLibWebMessageAdapter(payload, ports)),
-                sourceOrigin, isMainFrame,
-                BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(
-                        new SupportLibJsReplyProxyAdapter(replyProxy)));
     }
 }
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessagePayloadAdapter.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessagePayloadAdapter.java
index 5d9cd80..25f07af 100644
--- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessagePayloadAdapter.java
+++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebMessagePayloadAdapter.java
@@ -64,8 +64,7 @@
     public static MessagePayload fromWebMessageBoundaryInterface(
             @NonNull WebMessageBoundaryInterface boundaryInterface) {
         if (BoundaryInterfaceReflectionUtil.containsFeature(
-                    boundaryInterface.getSupportedFeatures(),
-                    Features.WEB_MESSAGE_GET_MESSAGE_PAYLOAD)) {
+                    boundaryInterface.getSupportedFeatures(), Features.WEB_MESSAGE_ARRAY_BUFFER)) {
             // MessagePayload API is supported by AndroidX.
             final MessagePayload messagePayload =
                     SupportLibWebMessagePayloadAdapter.toMessagePayload(
@@ -79,7 +78,7 @@
         return new MessagePayload(boundaryInterface.getData());
     }
 
-    private static MessagePayload toMessagePayload(
+    public static MessagePayload toMessagePayload(
             /* MessagePayload */ InvocationHandler invocationHandler) {
         if (invocationHandler == null) {
             return null;
@@ -97,7 +96,7 @@
             default:
                 // String and ArrayBuffer are covered by WEB_MESSAGE_GET_MESSAGE_PAYLOAD feature.
                 // Please add new feature flags for new types.
-                throw new RuntimeException("Unsupported type: " + type);
+                throw new IllegalArgumentException("Unsupported type: " + type);
         }
     }
 }
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java
index cea1300..14523993 100644
--- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java
+++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebViewChromiumFactory.java
@@ -88,7 +88,7 @@
                     Features.ALGORITHMIC_DARKENING,
                     Features.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY,
                     Features.GET_COOKIE_INFO,
-                    Features.WEB_MESSAGE_GET_MESSAGE_PAYLOAD + Features.DEV_SUFFIX,
+                    Features.WEB_MESSAGE_ARRAY_BUFFER + Features.DEV_SUFFIX,
                     Features.REQUESTED_WITH_HEADER_ALLOW_LIST,
                     Features.IMAGE_DRAG_DROP + Features.DEV_SUFFIX,
                     Features.RESTRICT_SENSITIVE_WEB_CONTENT + Features.DEV_SUFFIX,
@@ -173,6 +173,7 @@
             ApiCall.SERVICE_WORKER_SETTINGS_GET_REQUESTED_WITH_HEADER_ORIGIN_ALLOWLIST,
             ApiCall.GET_IMAGE_DRAG_DROP_IMPLEMENTATION,
             ApiCall.RESTRICT_SENSITIVE_WEB_CONTENT,
+            ApiCall.JS_REPLY_POST_MESSAGE_WITH_PAYLOAD,
             // Add new constants above. The final constant should have a trailing comma for cleaner
             // diffs.
             ApiCall.COUNT, // Added to suppress WrongConstant in #recordApiCall
@@ -256,8 +257,9 @@
         int SERVICE_WORKER_SETTINGS_GET_REQUESTED_WITH_HEADER_ORIGIN_ALLOWLIST = 71;
         int GET_IMAGE_DRAG_DROP_IMPLEMENTATION = 72;
         int RESTRICT_SENSITIVE_WEB_CONTENT = 73;
+        int JS_REPLY_POST_MESSAGE_WITH_PAYLOAD = 74;
         // Remember to update AndroidXWebkitApiCall in enums.xml when adding new values here
-        int COUNT = 74;
+        int COUNT = 75;
     }
     // clang-format on
 
diff --git a/android_webview/system_webview_apk_tmpl.gni b/android_webview/system_webview_apk_tmpl.gni
index 090b7fd..a71c7e1 100644
--- a/android_webview/system_webview_apk_tmpl.gni
+++ b/android_webview/system_webview_apk_tmpl.gni
@@ -43,45 +43,57 @@
     _version_code = WEBVIEW_VERSION_MAP["${android_64bit_target_cpu}_${_include_64_bit_webview}_${_include_32_bit_webview}"]
   }
 
-  if (defined(invoker.manifest_package)) {
-    _manifest_package = invoker.manifest_package
+  # TODO(crbug.com/1411557): Remove option for custom manifest.
+  if (defined(invoker.android_manifest)) {
+    not_needed([
+                 "_include_32_bit_webview",
+                 "_include_64_bit_webview",
+                 "_is_64_bit_browser",
+               ])
   } else {
-    _manifest_package = system_webview_package_name
-  }
-  _android_manifest = "$target_gen_dir/$target_name/AndroidManifest.xml"
-  _android_manifest_target_name = "${target_name}__android_manifest"
-  jinja_template(_android_manifest_target_name) {
-    if (!defined(_android_sdk_release)) {
-      _android_sdk_release = android_sdk_release
+    if (defined(invoker.manifest_package)) {
+      _manifest_package = invoker.manifest_package
+    } else {
+      _manifest_package = system_webview_package_name
     }
-    input = "//android_webview/nonembedded/java/AndroidManifest.xml"
-    output = _android_manifest
-    _force_32_bit = _include_32_bit_webview && _include_64_bit_webview &&
-                    (!_is_trichrome || !_is_64_bit_browser)
-    variables = webview_jinja_variables + [
-                  "android_sdk_release=$_android_sdk_release",
-                  "force_32_bit=$_force_32_bit",
-                  "manifest_package=$_manifest_package",
-                ]
-    if (_is_trichrome) {
-      variables +=
-          trichrome_jinja_variables + [ "trichrome_version=$_version_code" ]
-      if (_is_64_bit_browser) {
-        variables += [ "library=libmonochrome_64.so" ]
-      } else {
-        variables += [ "library=libmonochrome.so" ]
+    _android_manifest = "$target_gen_dir/$target_name/AndroidManifest.xml"
+    _android_manifest_target_name = "${target_name}__android_manifest"
+    jinja_template(_android_manifest_target_name) {
+      if (!defined(_android_sdk_release)) {
+        _android_sdk_release = android_sdk_release
       }
-    }
-    includes = []
-    if (defined(invoker.jinja_input)) {
-      includes += [ input ]
-      input = invoker.jinja_input
-    }
-    if (defined(invoker.jinja_extra_variables)) {
-      variables += invoker.jinja_extra_variables
-    }
-    if (defined(invoker.jinja_extra_includes)) {
-      includes += invoker.jinja_extra_includes
+      input = "//android_webview/nonembedded/java/AndroidManifest.xml"
+      output = _android_manifest
+      _force_32_bit = _include_32_bit_webview && _include_64_bit_webview &&
+                      (!_is_trichrome || !_is_64_bit_browser)
+      variables = webview_jinja_variables + [
+                    "android_sdk_release=$_android_sdk_release",
+                    "force_32_bit=$_force_32_bit",
+                    "manifest_package=$_manifest_package",
+                  ]
+      if (_is_trichrome) {
+        variables +=
+            trichrome_jinja_variables + [ "trichrome_version=$_version_code" ]
+        if (_is_64_bit_browser) {
+          variables += [ "library=libmonochrome_64.so" ]
+
+          # TODO(crbug.com/1411557): Remove.
+          variables -= [ use_32bit_abi_jinja_variable ]
+        } else {
+          variables += [ "library=libmonochrome.so" ]
+        }
+      }
+      includes = []
+      if (defined(invoker.jinja_input)) {
+        includes += [ input ]
+        input = invoker.jinja_input
+      }
+      if (defined(invoker.jinja_extra_variables)) {
+        variables += invoker.jinja_extra_variables
+      }
+      if (defined(invoker.jinja_extra_includes)) {
+        includes += invoker.jinja_extra_includes
+      }
     }
   }
   if (defined(invoker.target_type)) {
@@ -126,9 +138,12 @@
       expected_android_manifest_library_version_offset = chrome_version_code
     }
 
-    android_manifest = _android_manifest
-    android_manifest_dep = ":$_android_manifest_target_name"
-    manifest_package = _manifest_package
+    # TODO(crbug.com/1411557): Remove option for custom manifest.
+    if (defined(_android_manifest_target_name)) {
+      android_manifest = _android_manifest
+      android_manifest_dep = ":$_android_manifest_target_name"
+      manifest_package = _manifest_package
+    }
     deps += [
       "//android_webview:locale_pak_assets",
       "//android_webview:pak_file_assets",
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index b093ce9..15783ed 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -2201,6 +2201,8 @@
     "wm/desks/desk_animation_base.h",
     "wm/desks/desk_animation_impl.cc",
     "wm/desks/desk_animation_impl.h",
+    "wm/desks/desk_bar_view_base.cc",
+    "wm/desks/desk_bar_view_base.h",
     "wm/desks/desk_button_base.cc",
     "wm/desks/desk_button_base.h",
     "wm/desks/desk_drag_proxy.cc",
@@ -2883,6 +2885,7 @@
     "ambient/ambient_photo_cache_unittest.cc",
     "ambient/ambient_photo_controller_unittest.cc",
     "ambient/ambient_ui_settings_unittest.cc",
+    "ambient/ambient_weather_controller_unittest.cc",
     "ambient/autotest_ambient_api_unittest.cc",
     "ambient/metrics/ambient_multi_screen_metrics_recorder_unittest.cc",
     "ambient/model/ambient_animation_attribution_provider_unittest.cc",
@@ -4132,6 +4135,7 @@
     "//ui/accessibility/mojom",
     "//ui/aura",
     "//ui/aura:test_support",
+    "//ui/base:pixel_diff_test_support",
     "//ui/base:test_support",
     "//ui/color:mixers",
     "//ui/compositor:test_support",
diff --git a/ash/accelerators/accelerator_alias_converter.cc b/ash/accelerators/accelerator_alias_converter.cc
index 4e0bc515..e0994b0 100644
--- a/ash/accelerators/accelerator_alias_converter.cc
+++ b/ash/accelerators/accelerator_alias_converter.cc
@@ -258,6 +258,17 @@
       continue;
     }
 
+    // VKEY_MEDIA_LAUNCH_APP2 is the "Calculator" button on many external
+    // keyboards.
+    if (accelerator.key_code() == ui::VKEY_MEDIA_LAUNCH_APP2) {
+      if (Shell::Get()
+              ->keyboard_capability()
+              ->HasCalculatorKeyOnAnyKeyboard()) {
+        filtered_accelerators.push_back(accelerator);
+      }
+      continue;
+    }
+
     // Otherwise, always copy the accelerator.
     filtered_accelerators.push_back(accelerator);
   }
diff --git a/ash/accelerators/accelerator_alias_converter_unittest.cc b/ash/accelerators/accelerator_alias_converter_unittest.cc
index 467e95b5..c104cb6 100644
--- a/ash/accelerators/accelerator_alias_converter_unittest.cc
+++ b/ash/accelerators/accelerator_alias_converter_unittest.cc
@@ -135,6 +135,34 @@
   EXPECT_EQ(accelerator, accelerator_aliases[0]);
 }
 
+TEST_F(AcceleratorAliasConverterTest, CheckCalculatorKeyAlias) {
+  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
+      std::make_unique<FakeDeviceManager>();
+  ui::InputDevice fake_keyboard(
+      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
+      /*name=*/kKbdTopRowLayout1Tag);
+  fake_keyboard.sys_path = base::FilePath("path");
+  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);
+
+  AcceleratorAliasConverter accelerator_alias_converter_;
+
+  const ui::Accelerator accelerator{ui::VKEY_MEDIA_LAUNCH_APP2, ui::EF_NONE};
+  std::vector<ui::Accelerator> accelerator_aliases =
+      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
+  EXPECT_EQ(0u, accelerator_aliases.size());
+
+  ui::InputDevice wilco_keyboard(
+      /*id=*/2, /*type=*/ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH,
+      /*name=*/kKbdTopRowLayout1Tag);
+  wilco_keyboard.sys_path = base::FilePath("path2");
+  fake_keyboard_manager_->AddFakeKeyboard(wilco_keyboard,
+                                          kKbdTopRowLayoutWilcoTag);
+  accelerator_aliases =
+      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
+  EXPECT_EQ(1u, accelerator_aliases.size());
+  EXPECT_EQ(accelerator, accelerator_aliases[0]);
+}
+
 class TopRowAliasTest : public AcceleratorAliasConverterTest,
                         public testing::WithParamInterface<
                             TopRowAcceleratorAliasConverterTestData> {
diff --git a/ash/ambient/ambient_controller.cc b/ash/ambient/ambient_controller.cc
index 6bbd71b..200f0c9 100644
--- a/ash/ambient/ambient_controller.cc
+++ b/ash/ambient/ambient_controller.cc
@@ -14,7 +14,6 @@
 #include "ash/ambient/ambient_ui_launcher.h"
 #include "ash/ambient/ambient_ui_settings.h"
 #include "ash/ambient/ambient_video_ui_launcher.h"
-#include "ash/ambient/ambient_weather_controller.h"
 #include "ash/ambient/metrics/ambient_multi_screen_metrics_recorder.h"
 #include "ash/ambient/model/ambient_animation_photo_config.h"
 #include "ash/ambient/model/ambient_backend_model_observer.h"
@@ -139,11 +138,6 @@
          pref_service->GetBoolean(ambient::prefs::kAmbientModeEnabled);
 }
 
-bool IsAmbientModeAllowed() {
-  return ash::features::IsAmbientModeManagedScreensaverEnabled() ||
-         AmbientClient::Get()->IsAmbientModeAllowed();
-}
-
 bool IsAmbientModeManagedScreensaverEnabled() {
   // TODO(fahadmansoor): Consider adding additional client side checks to
   // keep behavior consistent with the consumer ambient mode.
@@ -235,6 +229,12 @@
   registry->RegisterIntegerPref(
       ambient::prefs::kAmbientModeManagedScreensaverImageDisplayIntervalSeconds,
       kManagedScreensaverImageRefreshInterval.InSeconds());
+
+  if (ash::features::IsScreenSaverDurationEnabled()) {
+    registry->RegisterIntegerPref(
+        ambient::prefs::kAmbientModeRunningDurationMinutes,
+        kDefaultScreenSaverDuration.InMinutes());
+  }
 }
 
 AmbientController::AmbientController(
@@ -404,7 +404,7 @@
 
 void AmbientController::OnActiveUserPrefServiceChanged(
     PrefService* pref_service) {
-  if (!IsAmbientModeAllowed() || GetPrimaryUserPrefService() != pref_service) {
+  if (GetPrimaryUserPrefService() != pref_service) {
     return;
   }
 
@@ -413,17 +413,25 @@
   if (pref_change_registrar_)
     return;
 
-  pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
-  pref_change_registrar_->Init(pref_service);
+  bool ambient_mode_allowed = AmbientClient::Get()->IsAmbientModeAllowed();
+  bool managed_screensaver_flag_enabled =
+      ash::features::IsAmbientModeManagedScreensaverEnabled();
 
-  pref_change_registrar_->Add(
-      ambient::prefs::kAmbientModeEnabled,
-      base::BindRepeating(&AmbientController::OnEnabledPrefChanged,
-                          weak_ptr_factory_.GetWeakPtr()));
+  if (ambient_mode_allowed || managed_screensaver_flag_enabled) {
+    pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
+    pref_change_registrar_->Init(pref_service);
+  }
 
-  OnEnabledPrefChanged();
+  if (ambient_mode_allowed) {
+    pref_change_registrar_->Add(
+        ambient::prefs::kAmbientModeEnabled,
+        base::BindRepeating(&AmbientController::OnEnabledPrefChanged,
+                            weak_ptr_factory_.GetWeakPtr()));
 
-  if (ash::features::IsAmbientModeManagedScreensaverEnabled()) {
+    OnEnabledPrefChanged();
+  }
+
+  if (managed_screensaver_flag_enabled) {
     pref_change_registrar_->Add(
         ambient::prefs::kAmbientModeManagedScreensaverEnabled,
         base::BindRepeating(
@@ -654,6 +662,15 @@
     CloseUi();
 }
 
+void AmbientController::SetScreenSaverDuration(int minutes) {
+  auto* pref_service = GetPrimaryUserPrefService();
+  if (!pref_service) {
+    return;
+  }
+  pref_service->Set(ambient::prefs::kAmbientModeRunningDurationMinutes,
+                    base::Value(minutes));
+}
+
 bool AmbientController::IsShown() const {
   return ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kShown ||
          ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kPreview;
@@ -1107,6 +1124,7 @@
     ambient_ui_launcher_->Finalize();
     return;
   }
+  weather_refresher_.reset();
   DCHECK(ambient_photo_controller_);
   ambient_photo_controller_->StopScreenUpdate();
 }
@@ -1137,6 +1155,9 @@
                        weak_ptr_factory_.GetWeakPtr()));
   } else {
     StartRefreshingImages();
+    // TODO(b/274164306): Move `weather_refresher_` to `AmbientUiLauncher`
+    // implementation for slideshow and animation themes.
+    weather_refresher_ = ambient_weather_controller_->CreateScopedRefresher();
   }
 }
 
diff --git a/ash/ambient/ambient_controller.h b/ash/ambient/ambient_controller.h
index d438f12..bd4dcdb 100644
--- a/ash/ambient/ambient_controller.h
+++ b/ash/ambient/ambient_controller.h
@@ -14,6 +14,7 @@
 #include "ash/ambient/ambient_photo_controller.h"
 #include "ash/ambient/ambient_ui_launcher.h"
 #include "ash/ambient/ambient_view_delegate_impl.h"
+#include "ash/ambient/ambient_weather_controller.h"
 #include "ash/ambient/model/ambient_backend_model.h"
 #include "ash/ambient/model/ambient_backend_model_observer.h"
 #include "ash/ambient/ui/ambient_view_delegate.h"
@@ -60,7 +61,6 @@
 class AmbientMultiScreenMetricsRecorder;
 class AmbientPhotoController;
 class AmbientUiSettings;
-class AmbientWeatherController;
 
 // Class to handle all ambient mode functionalities.
 class ASH_EXPORT AmbientController
@@ -136,6 +136,10 @@
 
   void ToggleInSessionUi();
 
+  // |minutes| is the number of minutes to run screen saver before putting the
+  // device into sleep. |minutes| with a value 0 means forever.
+  void SetScreenSaverDuration(int minutes);
+
   // Returns true if ambient mode containers are visible or are being
   // constructed.
   bool IsShown() const;
@@ -285,6 +289,7 @@
 
   base::ScopedObservation<BacklightsForcedOffSetter, ScreenBacklightObserver>
       backlights_forced_off_observation_{this};
+  std::unique_ptr<AmbientWeatherController::ScopedRefresher> weather_refresher_;
 
   // Observes user profile prefs for ambient.
   std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
diff --git a/ash/ambient/ambient_photo_controller.cc b/ash/ambient/ambient_photo_controller.cc
index 1cb8bb3f..c959e744 100644
--- a/ash/ambient/ambient_photo_controller.cc
+++ b/ash/ambient/ambient_photo_controller.cc
@@ -13,7 +13,6 @@
 #include "ash/ambient/ambient_constants.h"
 #include "ash/ambient/ambient_controller.h"
 #include "ash/ambient/ambient_photo_cache.h"
-#include "ash/ambient/ambient_weather_controller.h"
 #include "ash/ambient/model/ambient_backend_model.h"
 #include "ash/public/cpp/ambient/ambient_backend_controller.h"
 #include "ash/public/cpp/ambient/proto/photo_cache_entry.pb.h"
@@ -115,11 +114,6 @@
   }
 
   Init(std::move(topic_queue_delegate));
-  FetchWeather();
-  weather_refresh_timer_.Start(
-      FROM_HERE, kWeatherRefreshInterval,
-      base::BindRepeating(&AmbientPhotoController::FetchWeather,
-                          weak_factory_.GetWeakPtr()));
   if (backup_photo_refresh_timer_.IsRunning()) {
     // Would use |timer_.FireNow()| but this does not execute if screen is
     // locked. Manually call the expected callback instead.
@@ -131,7 +125,6 @@
 
 void AmbientPhotoController::StopScreenUpdate() {
   state_ = State::kInactive;
-  weather_refresh_timer_.Stop();
   resume_fetch_image_backoff_.Reset();
   ambient_backend_model_.Clear();
   ambient_topic_queue_.reset();
@@ -173,13 +166,6 @@
   }
 }
 
-void AmbientPhotoController::FetchWeather() {
-  Shell::Get()
-      ->ambient_controller()
-      ->ambient_weather_controller()
-      ->FetchWeather();
-}
-
 void AmbientPhotoController::ScheduleFetchBackupImages() {
   DVLOG(3) << __func__;
   if (backup_photo_refresh_timer_.IsRunning())
diff --git a/ash/ambient/ambient_photo_controller.h b/ash/ambient/ambient_photo_controller.h
index 53c9c31..af50cdd 100644
--- a/ash/ambient/ambient_photo_controller.h
+++ b/ash/ambient/ambient_photo_controller.h
@@ -118,8 +118,6 @@
   ~AmbientPhotoController() override;
 
   // Start/stop updating the screen contents.
-  // We need different logics to update photos and weather info because they
-  // have different refreshing intervals.
   void StartScreenUpdate(
       std::unique_ptr<AmbientTopicQueue::Delegate> topic_queue_delegate);
   void StopScreenUpdate();
@@ -146,9 +144,6 @@
   // Initialize variables.
   void Init(std::unique_ptr<AmbientTopicQueue::Delegate> topic_queue_delegate);
 
-  // Requests that the weather controller fetch updated weather info.
-  void FetchWeather();
-
   void ScheduleFetchBackupImages();
 
   // Download backup cache images.
@@ -205,9 +200,6 @@
   // The timer to refresh backup cache photos.
   base::OneShotTimer backup_photo_refresh_timer_;
 
-  // The timer to refresh weather information.
-  base::RepeatingTimer weather_refresh_timer_;
-
   State state_ = State::kInactive;
 
   // The index of a topic to download.
diff --git a/ash/ambient/ambient_photo_controller_unittest.cc b/ash/ambient/ambient_photo_controller_unittest.cc
index f6cde6c5..2457485 100644
--- a/ash/ambient/ambient_photo_controller_unittest.cc
+++ b/ash/ambient/ambient_photo_controller_unittest.cc
@@ -12,12 +12,10 @@
 #include "ash/ambient/ambient_constants.h"
 #include "ash/ambient/ambient_controller.h"
 #include "ash/ambient/ambient_photo_cache.h"
-#include "ash/ambient/ambient_weather_controller.h"
 #include "ash/ambient/model/ambient_animation_photo_config.h"
 #include "ash/ambient/model/ambient_backend_model.h"
 #include "ash/ambient/model/ambient_backend_model_observer.h"
 #include "ash/ambient/model/ambient_photo_config.h"
-#include "ash/ambient/model/ambient_weather_model.h"
 #include "ash/ambient/test/ambient_ash_test_base.h"
 #include "ash/ambient/test/ambient_test_util.h"
 #include "ash/ambient/test/ambient_topic_queue_test_delegate.h"
@@ -706,36 +704,6 @@
   EXPECT_TRUE(photo_controller()->ambient_backend_model()->ImagesReady());
 }
 
-TEST_F(AmbientPhotoControllerTest, ShouldStartToRefreshWeather) {
-  auto* model = weather_controller()->weather_model();
-  EXPECT_FALSE(model->show_celsius());
-  EXPECT_TRUE(model->weather_condition_icon().isNull());
-
-  WeatherInfo info;
-  info.show_celsius = true;
-  info.condition_icon_url = "https://fake-icon-url";
-  info.temp_f = 70.0f;
-  backend_controller()->SetWeatherInfo(info);
-
-  // Start to refresh weather as screen update starts.
-  photo_controller()->StartScreenUpdate(
-      std::make_unique<AmbientTopicQueueTestDelegate>());
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_TRUE(model->show_celsius());
-  EXPECT_FALSE(model->weather_condition_icon().isNull());
-  EXPECT_GT(info.temp_f, 0);
-
-  // Refresh weather again after time passes.
-  info.show_celsius = false;
-  info.temp_f = -70.0f;
-  backend_controller()->SetWeatherInfo(info);
-
-  FastForwardToRefreshWeather();
-  EXPECT_FALSE(model->show_celsius());
-  EXPECT_LT(info.temp_f, 0);
-}
-
 TEST_F(AmbientPhotoControllerTest, IsScreenUpdateActive) {
   ASSERT_FALSE(photo_controller()->IsScreenUpdateActive());
   photo_controller()->StartScreenUpdate(
diff --git a/ash/ambient/ambient_video_ui_launcher.cc b/ash/ambient/ambient_video_ui_launcher.cc
index 91f68dc..d12d18f 100644
--- a/ash/ambient/ambient_video_ui_launcher.cc
+++ b/ash/ambient/ambient_video_ui_launcher.cc
@@ -4,10 +4,12 @@
 
 #include "ash/ambient/ambient_video_ui_launcher.h"
 
+#include "ash/ambient/ambient_controller.h"
 #include "ash/ambient/ambient_ui_settings.h"
 #include "ash/ambient/ui/ambient_video_utils.h"
 #include "ash/ambient/ui/ambient_video_view.h"
 #include "ash/public/cpp/personalization_app/time_of_day_paths.h"
+#include "ash/shell.h"
 #include "base/check.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -68,6 +70,10 @@
       {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
        base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
       base::BindOnce(&VerifyVideoExistsOnDisc, current_video_));
+  weather_refresher_ = Shell::Get()
+                           ->ambient_controller()
+                           ->ambient_weather_controller()
+                           ->CreateScopedRefresher();
   std::move(on_done).Run(/*success=*/true);
 }
 
@@ -78,6 +84,7 @@
 }
 
 void AmbientVideoUiLauncher::Finalize() {
+  weather_refresher_.reset();
   is_active_ = false;
 }
 
diff --git a/ash/ambient/ambient_video_ui_launcher.h b/ash/ambient/ambient_video_ui_launcher.h
index 73e0fa7..d9d3f56 100644
--- a/ash/ambient/ambient_video_ui_launcher.h
+++ b/ash/ambient/ambient_video_ui_launcher.h
@@ -5,7 +5,10 @@
 #ifndef ASH_AMBIENT_AMBIENT_VIDEO_UI_LAUNCHER_H_
 #define ASH_AMBIENT_AMBIENT_VIDEO_UI_LAUNCHER_H_
 
+#include <memory>
+
 #include "ash/ambient/ambient_ui_launcher.h"
+#include "ash/ambient/ambient_weather_controller.h"
 #include "ash/constants/ambient_video.h"
 #include "base/memory/raw_ptr.h"
 
@@ -33,6 +36,7 @@
   bool is_active_ = false;
   AmbientVideo current_video_;
   const base::raw_ptr<PrefService> pref_service_;
+  std::unique_ptr<AmbientWeatherController::ScopedRefresher> weather_refresher_;
 };
 
 }  // namespace ash
diff --git a/ash/ambient/ambient_weather_controller.cc b/ash/ambient/ambient_weather_controller.cc
index 121a7f1..2f67d6a 100644
--- a/ash/ambient/ambient_weather_controller.cc
+++ b/ash/ambient/ambient_weather_controller.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/ambient/ambient_constants.h"
 #include "ash/ambient/ambient_controller.h"
 #include "ash/ambient/model/ambient_weather_model.h"
 #include "ash/public/cpp/ambient/ambient_backend_controller.h"
@@ -17,6 +18,8 @@
 #include "base/check.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
 #include "components/account_id/account_id.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -66,11 +69,33 @@
 
 }  // namespace
 
+AmbientWeatherController::ScopedRefresher::ScopedRefresher(
+    AmbientWeatherController* controller)
+    : controller_(controller) {
+  CHECK(controller_);
+}
+
+AmbientWeatherController::ScopedRefresher::~ScopedRefresher() {
+  controller_->OnScopedRefresherDestroyed();
+}
+
 AmbientWeatherController::AmbientWeatherController()
     : weather_model_(std::make_unique<AmbientWeatherModel>()) {}
 
 AmbientWeatherController::~AmbientWeatherController() = default;
 
+std::unique_ptr<AmbientWeatherController::ScopedRefresher>
+AmbientWeatherController::CreateScopedRefresher() {
+  ++num_active_scoped_refreshers_;
+  if (!weather_refresh_timer_.IsRunning()) {
+    FetchWeather();
+    weather_refresh_timer_.Start(FROM_HERE, kWeatherRefreshInterval, this,
+                                 &AmbientWeatherController::FetchWeather);
+  }
+  // `WrapUnique()` needed for ScopedRefresher's private constructor.
+  return base::WrapUnique(new ScopedRefresher(this));
+}
+
 void AmbientWeatherController::FetchWeather() {
   Shell::Get()
       ->ambient_controller()
@@ -123,4 +148,14 @@
   weather_model_->UpdateWeatherInfo(icon, temp_f, show_celsius);
 }
 
+void AmbientWeatherController::OnScopedRefresherDestroyed() {
+  --num_active_scoped_refreshers_;
+  CHECK_GE(num_active_scoped_refreshers_, 0);
+  if (num_active_scoped_refreshers_ == 0) {
+    // This may not have user-visible effects, but refreshing the weather when
+    // there's no UI using it is wasting network/server resources.
+    weather_refresh_timer_.Stop();
+  }
+}
+
 }  // namespace ash
diff --git a/ash/ambient/ambient_weather_controller.h b/ash/ambient/ambient_weather_controller.h
index f43e568..6fb138d 100644
--- a/ash/ambient/ambient_weather_controller.h
+++ b/ash/ambient/ambient_weather_controller.h
@@ -8,7 +8,9 @@
 #include <memory>
 
 #include "ash/ash_export.h"
+#include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace gfx {
@@ -25,18 +27,39 @@
 // caches the current weather info.
 class ASH_EXPORT AmbientWeatherController {
  public:
+  // Causes AmbientWeatherController to periodically refresh the weather info
+  // in the model for as long as this object is alive. The latest weather is
+  // also fetched immediately upon construction if there are currently no
+  // active `ScopedRefresher`s.
+  class ScopedRefresher {
+   public:
+    ScopedRefresher(const ScopedRefresher&) = delete;
+    ScopedRefresher& operator=(const ScopedRefresher&) = delete;
+    ~ScopedRefresher();
+
+   private:
+    friend class AmbientWeatherController;
+
+    explicit ScopedRefresher(AmbientWeatherController* controller);
+
+    const base::raw_ptr<AmbientWeatherController> controller_;
+  };
+
   AmbientWeatherController();
   AmbientWeatherController(const AmbientWeatherController&) = delete;
   AmbientWeatherController& operator=(const AmbientWeatherController&) = delete;
   ~AmbientWeatherController();
 
-  // Triggers a fetch of weather information and a download of the appropriate
-  // weather condition icon.
-  void FetchWeather();
+  // Always returns non-null.
+  std::unique_ptr<ScopedRefresher> CreateScopedRefresher();
 
   AmbientWeatherModel* weather_model() { return weather_model_.get(); }
 
  private:
+  // Triggers a fetch of weather information and a download of the appropriate
+  // weather condition icon.
+  void FetchWeather();
+
   void StartDownloadingWeatherConditionIcon(
       const absl::optional<WeatherInfo>& weather_info);
 
@@ -46,8 +69,14 @@
                                         bool show_celsius,
                                         const gfx::ImageSkia& icon);
 
+  void OnScopedRefresherDestroyed();
+
   std::unique_ptr<AmbientWeatherModel> weather_model_;
 
+  int num_active_scoped_refreshers_ = 0;
+
+  base::RepeatingTimer weather_refresh_timer_;
+
   base::WeakPtrFactory<AmbientWeatherController> weak_factory_{this};
 };
 
diff --git a/ash/ambient/ambient_weather_controller_unittest.cc b/ash/ambient/ambient_weather_controller_unittest.cc
new file mode 100644
index 0000000..bf949089
--- /dev/null
+++ b/ash/ambient/ambient_weather_controller_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/ambient/ambient_weather_controller.h"
+
+#include "ash/ambient/model/ambient_weather_model.h"
+#include "ash/ambient/test/ambient_ash_test_base.h"
+#include "ash/public/cpp/ambient/fake_ambient_backend_controller_impl.h"
+#include "base/run_loop.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ash {
+namespace {
+
+using AmbientWeatherControllerTest = AmbientAshTestBase;
+
+TEST_F(AmbientWeatherControllerTest, RefreshesWeather) {
+  auto* model = weather_controller()->weather_model();
+  EXPECT_FALSE(model->show_celsius());
+  EXPECT_TRUE(model->weather_condition_icon().isNull());
+
+  WeatherInfo info;
+  info.show_celsius = true;
+  info.condition_icon_url = "https://fake-icon-url";
+  info.temp_f = 70.0f;
+  backend_controller()->SetWeatherInfo(info);
+
+  auto weather_refresher = weather_controller()->CreateScopedRefresher();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(model->show_celsius());
+  EXPECT_FALSE(model->weather_condition_icon().isNull());
+  EXPECT_FLOAT_EQ(model->temperature_fahrenheit(), 70.0f);
+
+  // Refresh weather again after time passes.
+  info.show_celsius = false;
+  info.temp_f = -70.0f;
+  backend_controller()->SetWeatherInfo(info);
+
+  FastForwardToRefreshWeather();
+  EXPECT_FALSE(model->show_celsius());
+  EXPECT_FLOAT_EQ(model->temperature_fahrenheit(), -70.0f);
+
+  info.show_celsius = true;
+  info.temp_f = 70.0f;
+  backend_controller()->SetWeatherInfo(info);
+  // Should stop refreshing after the `weather_refresher` is destroyed.
+  weather_refresher.reset();
+  FastForwardToRefreshWeather();
+  // The old info should hold in the model since we're not refreshing.
+  EXPECT_FALSE(model->show_celsius());
+  EXPECT_FLOAT_EQ(model->temperature_fahrenheit(), -70.0f);
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/ash/ambient/test/ambient_ash_test_base.h b/ash/ambient/test/ambient_ash_test_base.h
index 8646138b..59bc49d 100644
--- a/ash/ambient/test/ambient_ash_test_base.h
+++ b/ash/ambient/test/ambient_ash_test_base.h
@@ -55,8 +55,8 @@
   // Enables/disables ambient mode for the currently active user session.
   void SetAmbientModeEnabled(bool enabled);
 
-  // Enables/disabled the managed ambient mode for the currently active user
-  // session.
+  // Enables/disables the managed ambient mode pref in the currently active pref
+  // service.
   void SetAmbientModeManagedScreensaverEnabled(bool enabled);
 
   // Sets the |AmbientUiSettings| to use when ShowAmbientScreen() is called.
diff --git a/ash/app_list/views/app_drag_icon_proxy.cc b/ash/app_list/views/app_drag_icon_proxy.cc
index c38e0f1..a336ad74 100644
--- a/ash/app_list/views/app_drag_icon_proxy.cc
+++ b/ash/app_list/views/app_drag_icon_proxy.cc
@@ -4,6 +4,7 @@
 
 #include "ash/app_list/views/app_drag_icon_proxy.h"
 
+#include <memory>
 #include <utility>
 
 #include "ash/constants/ash_features.h"
@@ -13,6 +14,7 @@
 #include "ui/aura/window.h"
 #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
 #include "ui/compositor/layer.h"
+#include "ui/compositor/layer_owner.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -80,12 +82,32 @@
 
   shadow_->SetContentBounds(gfx::Rect(shadow_offset, scaled_shadow_size));
 
-  if (is_folder_icon && !features::IsAppCollectionFolderRefreshEnabled()) {
-    const float radius = size.width() / 2.0f;
-    drag_image->layer()->SetRoundedCornerRadius(
-        {radius, radius, radius, radius});
-    drag_image->layer()->SetBackgroundBlur(ColorProvider::kBackgroundBlurSigma);
-    drag_image->layer()->SetBackdropFilterQuality(
+  if (is_folder_icon) {
+    ui::Layer* blurred_layer;
+    float corner_radius;
+
+    if (features::IsAppCollectionFolderRefreshEnabled()) {
+      // For the refreshed icon, the blur should be only added on the background
+      // circle, where none of any exising layer is bounded to that area.
+      // Therefore, the `blurred_background_layer_` is needed here to explicitly
+      // blur the background of the icon.
+      blurred_background_layer_ =
+          std::make_unique<ui::LayerOwner>(std::make_unique<ui::Layer>());
+      blurred_layer = blurred_background_layer_->layer();
+      drag_image->AddLayerToRegion(blurred_layer, views::LayerRegion::kBelow);
+      blurred_layer->SetBounds(shadow_->GetContentBounds());
+      corner_radius = shadow_->GetContentBounds().width() / 2.0f;
+    } else {
+      // For the clipped drag icon, the `drag_image` layer can be used for
+      // blurring as the whole clipped area needs to be blurred.
+      blurred_layer = drag_image->layer();
+      corner_radius = size.width() / 2.0f;
+    }
+
+    blurred_layer->SetRoundedCornerRadius(
+        {corner_radius, corner_radius, corner_radius, corner_radius});
+    blurred_layer->SetBackgroundBlur(ColorProvider::kBackgroundBlurSigma);
+    blurred_layer->SetBackdropFilterQuality(
         ColorProvider::kBackgroundBlurQuality);
   }
 
@@ -168,6 +190,12 @@
   return drag_image_widget_.get();
 }
 
+ui::Layer* AppDragIconProxy::GetBlurredLayerForTesting() {
+  return features::IsAppCollectionFolderRefreshEnabled()
+             ? blurred_background_layer_->layer()
+             : GetImageLayerForTesting();  // IN-TEST
+}
+
 void AppDragIconProxy::OnProxyAnimationCompleted() {
   drag_image_widget_.reset();
   if (animation_completion_callback_) {
diff --git a/ash/app_list/views/app_drag_icon_proxy.h b/ash/app_list/views/app_drag_icon_proxy.h
index 2319d84c..5e9a9eaf 100644
--- a/ash/app_list/views/app_drag_icon_proxy.h
+++ b/ash/app_list/views/app_drag_icon_proxy.h
@@ -24,6 +24,7 @@
 
 namespace ui {
 class Layer;
+class LayerOwner;
 }  // namespace ui
 
 namespace ash {
@@ -83,6 +84,9 @@
     return shadow_->GetContentBounds();
   }
 
+  // Returns the layer that is used to blur the background.
+  ui::Layer* GetBlurredLayerForTesting();
+
  private:
   void OnProxyAnimationCompleted();
 
@@ -92,6 +96,10 @@
 
   std::unique_ptr<SystemShadow> shadow_;
 
+  // A layer that is used to blur the background of the dragged icon. Only used
+  // for refreshed folder icons.
+  std::unique_ptr<ui::LayerOwner> blurred_background_layer_;
+
   // The widget used to display the drag image.
   views::UniqueWidgetPtr drag_image_widget_;
 
diff --git a/ash/app_list/views/app_drag_icon_proxy_unittest.cc b/ash/app_list/views/app_drag_icon_proxy_unittest.cc
index bd19775..7ff1d8f 100644
--- a/ash/app_list/views/app_drag_icon_proxy_unittest.cc
+++ b/ash/app_list/views/app_drag_icon_proxy_unittest.cc
@@ -124,11 +124,11 @@
 
   // The background should be circular.
   EXPECT_EQ(gfx::RoundedCornersF(25.0f).ToString(),
-            drag_icon_proxy->GetImageLayerForTesting()
+            drag_icon_proxy->GetBlurredLayerForTesting()
                 ->rounded_corner_radii()
                 .ToString());
   EXPECT_EQ(30.0f,
-            drag_icon_proxy->GetImageLayerForTesting()->background_blur());
+            drag_icon_proxy->GetBlurredLayerForTesting()->background_blur());
 
   // Test that background corner radii are scaled with the image.
   drag_icon_proxy = std::make_unique<AppDragIconProxy>(
@@ -141,11 +141,11 @@
 
   // The background should be circular.
   EXPECT_EQ(gfx::RoundedCornersF(50.0f).ToString(),
-            drag_icon_proxy->GetImageLayerForTesting()
+            drag_icon_proxy->GetBlurredLayerForTesting()
                 ->rounded_corner_radii()
                 .ToString());
   EXPECT_EQ(30.0f,
-            drag_icon_proxy->GetImageLayerForTesting()->background_blur());
+            drag_icon_proxy->GetBlurredLayerForTesting()->background_blur());
 }
 
 TEST_F(AppDragIconProxyTest, AnimateBoundsForClosure) {
diff --git a/ash/app_list/views/app_list_item_view_pixeltest.cc b/ash/app_list/views/app_list_item_view_pixeltest.cc
index 690cefe..fb8ae90 100644
--- a/ash/app_list/views/app_list_item_view_pixeltest.cc
+++ b/ash/app_list/views/app_list_item_view_pixeltest.cc
@@ -54,6 +54,9 @@
     if (use_folder_icon_refresh()) {
       scoped_feature_list_.InitAndEnableFeature(
           features::kAppCollectionFolderRefresh);
+    } else {
+      scoped_feature_list_.InitAndDisableFeature(
+          features::kAppCollectionFolderRefresh);
     }
   }
 
diff --git a/ash/app_list/views/apps_grid_view_unittest.cc b/ash/app_list/views/apps_grid_view_unittest.cc
index 8837c1ed..8832d7c3 100644
--- a/ash/app_list/views/apps_grid_view_unittest.cc
+++ b/ash/app_list/views/apps_grid_view_unittest.cc
@@ -292,20 +292,22 @@
     if (is_rtl_)
       base::i18n::SetICUDefaultLocale("he");
     auto enabled_features = std::vector<base::test::FeatureRef>();
+    auto disabled_features = std::vector<base::test::FeatureRef>();
     if (use_drag_drop_refactor_) {
       enabled_features.push_back(app_list_features::kDragAndDropRefactor);
     }
 
     if (folder_icon_refresh_) {
       enabled_features.push_back(features::kAppCollectionFolderRefresh);
+    } else {
+      disabled_features.push_back(features::kAppCollectionFolderRefresh);
     }
 
     if (enable_shelf_party_) {
       enabled_features.push_back(features::kShelfParty);
     }
 
-    scoped_feature_list_.InitWithFeatures(enabled_features,
-                                          /*disabled_features*/ {});
+    scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
     AshTestBase::SetUp();
 
     // Make the display big enough to hold the app list.
diff --git a/ash/app_list/views/continue_task_view.cc b/ash/app_list/views/continue_task_view.cc
index d95efb9a..284e3126 100644
--- a/ash/app_list/views/continue_task_view.cc
+++ b/ash/app_list/views/continue_task_view.cc
@@ -217,7 +217,18 @@
     return;
   }
 
-  const gfx::ImageSkia& icon = result()->chip_icon();
+  gfx::ImageSkia icon;
+
+  // TODO(b/278271038): After changing the type of icon in
+  // `SearchResultIconInfo` from `ImageSkia` to `ImageModel`, please make sure
+  // get rid of `badge_icon` here; and use the `icon` instead. Also, you need to
+  // replace `SetBadgeIcon` in `DesksAdminTemplateResult` to `SetIcon`.
+  if (!result()->badge_icon().IsEmpty()) {
+    icon = result()->badge_icon().Rasterize(GetColorProvider());
+  } else {
+    icon = result()->chip_icon();
+  }
+
   icon_->SetImage(CreateIconWithCircleBackground(
       icon.size() == GetIconSize()
           ? icon
diff --git a/ash/ash_prefs.cc b/ash/ash_prefs.cc
index a805dbf..97b8058d 100644
--- a/ash/ash_prefs.cc
+++ b/ash/ash_prefs.cc
@@ -35,6 +35,7 @@
 #include "ash/system/camera/autozoom_controller_impl.h"
 #include "ash/system/camera/autozoom_nudge_controller.h"
 #include "ash/system/camera/camera_effects_controller.h"
+#include "ash/system/geolocation/geolocation_controller.h"
 #include "ash/system/gesture_education/gesture_education_notification_controller.h"
 #include "ash/system/human_presence/snooping_protection_controller.h"
 #include "ash/system/input_device_settings/input_device_settings_controller_impl.h"
@@ -98,6 +99,7 @@
   DockedMagnifierController::RegisterProfilePrefs(registry);
   FeatureDiscoveryDurationReporterImpl::RegisterProfilePrefs(registry);
   FullscreenController::RegisterProfilePrefs(registry);
+  GeolocationController::RegisterProfilePrefs(registry);
   GestureEducationNotificationController::RegisterProfilePrefs(registry,
                                                                for_test);
   holding_space_prefs::RegisterProfilePrefs(registry);
diff --git a/ash/components/arc/mojom/app.mojom b/ash/components/arc/mojom/app.mojom
index 13575114..5808ba05 100644
--- a/ash/components/arc/mojom/app.mojom
+++ b/ash/components/arc/mojom/app.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Next MinVersion: 57
+// Next MinVersion: 58
 
 module arc.mojom;
 
@@ -48,6 +48,10 @@
   // Option, only for ARC upgrade. True if the app is fixing up.
   // During fixup, it cannot be launched.
   [MinVersion=54] bool need_fixup;
+
+  // App category corresponding to the
+  // android.content.pm.ApplicationInfo#category field.
+  [MinVersion=57] AppCategory app_category;
 };
 
 // Describes the data required to install a web app.
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 36b32a1..5a3156b 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1147,6 +1147,11 @@
              "HindiInscriptLayout",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Enables Camera app integration with holding space.
+BASE_FEATURE(kHoldingSpaceCameraAppIntegration,
+             "HoldingSpaceCameraAppIntegration",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Enables in-progress downloads notification suppression with the productivity
 // feature that aims to reduce context switching by enabling users to collect
 // content and transfer or access it later.
@@ -2777,6 +2782,10 @@
   return base::FeatureList::IsEnabled(kHideShelfControlsInTabletMode);
 }
 
+bool IsHoldingSpaceCameraAppIntegrationEnabled() {
+  return base::FeatureList::IsEnabled(kHoldingSpaceCameraAppIntegration);
+}
+
 bool IsHoldingSpaceInProgressDownloadsNotificationSuppressionEnabled() {
   return base::FeatureList::IsEnabled(
       kHoldingSpaceInProgressDownloadsNotificationSuppression);
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 3a672c3..e307674 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -355,6 +355,8 @@
 BASE_DECLARE_FEATURE(kHideShelfControlsInTabletMode);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kHindiInscriptLayout);
 COMPONENT_EXPORT(ASH_CONSTANTS)
+BASE_DECLARE_FEATURE(kHoldingSpaceCameraAppIntegration);
+COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kHoldingSpaceInProgressDownloadsNotificationSuppression);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kHoldingSpacePredictability);
@@ -765,6 +767,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHideArcMediaNotificationsEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHideShelfControlsInTabletModeEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS)
+bool IsHoldingSpaceCameraAppIntegrationEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS)
 bool IsHoldingSpaceInProgressDownloadsNotificationSuppressionEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHoldingSpacePredictabilityEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHoldingSpaceRefreshEnabled();
diff --git a/ash/constants/ash_pref_names.cc b/ash/constants/ash_pref_names.cc
index c822cba..d852e22 100644
--- a/ash/constants/ash_pref_names.cc
+++ b/ash/constants/ash_pref_names.cc
@@ -1009,6 +1009,16 @@
 // session. Values are from PrivacyHubController::AccessLevel.
 const char kDeviceGeolocationAllowed[] = "ash.device.geolocation_allowed";
 
+// Double prefs storing the most recent valid geoposition, which is only used
+// when the device lacks connectivity and we're unable to retrieve a valid
+// geoposition to calculate the sunset / sunrise times.
+//
+// Note the night light feature will be migrated to use `GeolocationController`
+// eventually, at which time `kNightLightCachedLatitude|Longitude` will be
+// superseded by these prefs.
+const char kDeviceGeolocationCachedLatitude[] = "ash.device.cached_latitude";
+const char kDeviceGeolocationCachedLongitude[] = "ash.device.cached_longitude";
+
 // A boolean pref which determines whether tap-dragging is enabled.
 const char kTapDraggingEnabled[] = "settings.touchpad.enable_tap_dragging";
 
diff --git a/ash/constants/ash_pref_names.h b/ash/constants/ash_pref_names.h
index 00131c1..9b0a1ed0 100644
--- a/ash/constants/ash_pref_names.h
+++ b/ash/constants/ash_pref_names.h
@@ -465,6 +465,10 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kUserMicrophoneAllowed[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kUserGeolocationAllowed[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kDeviceGeolocationAllowed[];
+COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const char kDeviceGeolocationCachedLatitude[];
+COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const char kDeviceGeolocationCachedLongitude[];
 
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kTapDraggingEnabled[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kTouchpadEnabled[];
diff --git a/ash/events/keyboard_capability_unittest.cc b/ash/events/keyboard_capability_unittest.cc
index 0d2c1201..d2b1ba7 100644
--- a/ash/events/keyboard_capability_unittest.cc
+++ b/ash/events/keyboard_capability_unittest.cc
@@ -466,6 +466,24 @@
   EXPECT_TRUE(keyboard_capability_->HasGlobeKey(internal_keyboard_drallion));
 }
 
+TEST_F(KeyboardCapabilityTest, TestHasCalculatorKey) {
+  ui::InputDevice internal_keyboard(
+      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
+      /*name=*/"Keyboard1");
+  internal_keyboard.sys_path = base::FilePath("path1");
+  fake_keyboard_manager_->AddFakeKeyboard(internal_keyboard,
+                                          kKbdTopRowLayout1Tag);
+  EXPECT_FALSE(keyboard_capability_->HasCalculatorKey(internal_keyboard));
+
+  ui::InputDevice external_keyboard(
+      /*id=*/2, /*type=*/ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH,
+      /*name=*/"Keyboard2");
+  external_keyboard.sys_path = base::FilePath("path1");
+  fake_keyboard_manager_->AddFakeKeyboard(external_keyboard,
+                                          kKbdTopRowLayoutUnspecified);
+  EXPECT_TRUE(keyboard_capability_->HasCalculatorKey(external_keyboard));
+}
+
 class ModifierKeyTest : public KeyboardCapabilityTest,
                         public testing::WithParamInterface<
                             std::tuple<ui::DeviceCapabilities,
diff --git a/ash/glanceables/glanceables_controller.cc b/ash/glanceables/glanceables_controller.cc
index 80834c7..266732a 100644
--- a/ash/glanceables/glanceables_controller.cc
+++ b/ash/glanceables/glanceables_controller.cc
@@ -7,7 +7,6 @@
 #include <memory>
 
 #include "ash/ambient/ambient_controller.h"
-#include "ash/ambient/ambient_weather_controller.h"
 #include "ash/glanceables/glanceables_delegate.h"
 #include "ash/glanceables/glanceables_view.h"
 #include "ash/public/cpp/shell_window_ids.h"
@@ -114,6 +113,7 @@
   widget_.reset();
   view_ = nullptr;
   delegate_->OnGlanceablesClosed();
+  weather_refresher_.reset();
 }
 
 void GlanceablesController::OnWindowActivated(
@@ -139,10 +139,10 @@
 
 void GlanceablesController::FetchData() {
   // GlanceablesWeatherView observes the weather model for updates.
-  Shell::Get()
-      ->ambient_controller()
-      ->ambient_weather_controller()
-      ->FetchWeather();
+  weather_refresher_ = Shell::Get()
+                           ->ambient_controller()
+                           ->ambient_weather_controller()
+                           ->CreateScopedRefresher();
 
   Shell::Get()->system_tray_model()->calendar_model()->FetchEvents(
       start_of_month_utc_);
diff --git a/ash/glanceables/glanceables_controller.h b/ash/glanceables/glanceables_controller.h
index ca43745..0546e2ed 100644
--- a/ash/glanceables/glanceables_controller.h
+++ b/ash/glanceables/glanceables_controller.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "ash/ambient/ambient_weather_controller.h"
 #include "ash/ash_export.h"
 #include "ash/public/cpp/tablet_mode_observer.h"
 #include "base/time/time.h"
@@ -67,6 +68,7 @@
   std::unique_ptr<GlanceablesDelegate> delegate_;
   std::unique_ptr<views::Widget> widget_;
   GlanceablesView* view_ = nullptr;
+  std::unique_ptr<AmbientWeatherController::ScopedRefresher> weather_refresher_;
 
   // The start of current month in UTC. Used for fetching calendar events.
   // TODO(crbug.com/1353495): Update value at the beginning of the next month
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 0e697b9..ebeda476 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -116,6 +116,8 @@
     "clipboard_history_controller.h",
     "clipboard_image_model_factory.cc",
     "clipboard_image_model_factory.h",
+    "connectivity_services.cc",
+    "connectivity_services.h",
     "default_user_image.cc",
     "default_user_image.h",
     "desk_template.cc",
@@ -400,6 +402,7 @@
     "//chromeos/ash/services/assistant/public/cpp",
     "//chromeos/ash/services/bluetooth_config:in_process_bluetooth_config",
     "//chromeos/ash/services/cellular_setup:in_process_esim_manager",
+    "//chromeos/ash/services/connectivity/public/cpp",
     "//chromeos/ash/services/hotspot_config:in_process_hotspot_config",
     "//chromeos/ash/services/network_config:in_process_instance",
     "//chromeos/dbus/power:power_manager_proto",
@@ -445,6 +448,7 @@
     "//chromeos/ash/services/assistant/public/mojom",
     "//chromeos/ash/services/bluetooth_config/public/mojom",
     "//chromeos/ash/services/cellular_setup/public/mojom",
+    "//chromeos/ash/services/connectivity/public/mojom",
     "//chromeos/ash/services/hotspot_config/public/mojom",
     "//chromeos/components/security_token_pin",
     "//chromeos/crosapi/mojom",
diff --git a/ash/public/cpp/ambient/ambient_prefs.cc b/ash/public/cpp/ambient/ambient_prefs.cc
index 0d850a2..92cf83e 100644
--- a/ash/public/cpp/ambient/ambient_prefs.cc
+++ b/ash/public/cpp/ambient/ambient_prefs.cc
@@ -59,6 +59,9 @@
 constexpr char kAmbientModeManagedScreensaverImages[] =
     "ash.ambient.managed_screensaver.images";
 
+constexpr char kAmbientModeRunningDurationMinutes[] =
+    "ash.ambient.screensaver_duration_minutes";
+
 void MigrateDeprecatedPrefs(PrefService& pref_service) {
   // The largest |AmbientTheme| value possible with the old pref
   // |kAmbientTheme|.
diff --git a/ash/public/cpp/ambient/ambient_prefs.h b/ash/public/cpp/ambient/ambient_prefs.h
index 6127a730..e62beb75 100644
--- a/ash/public/cpp/ambient/ambient_prefs.h
+++ b/ash/public/cpp/ambient/ambient_prefs.h
@@ -90,6 +90,11 @@
 // for the sign-in profile.
 ASH_PUBLIC_EXPORT extern const char kAmbientModeManagedScreensaverImages[];
 
+// Integer pref for the number of minutes to wait before putting the device into
+// sleep after Ambient mode has started. Logged in users can set this value in
+// the Personalization Hub screensaver subpage.
+ASH_PUBLIC_EXPORT extern const char kAmbientModeRunningDurationMinutes[];
+
 // Migrates from the legacy |ambient::prefs::kAmbientTheme| to the new
 // |ambient::prefs::kAmbientUiSettings|.
 ASH_PUBLIC_EXPORT void MigrateDeprecatedPrefs(PrefService& pref_service);
diff --git a/ash/public/cpp/ambient/ambient_ui_model.h b/ash/public/cpp/ambient/ambient_ui_model.h
index 9f60e5a..7dd51b4e 100644
--- a/ash/public/cpp/ambient/ambient_ui_model.h
+++ b/ash/public/cpp/ambient/ambient_ui_model.h
@@ -40,6 +40,9 @@
 // The default interval to refresh photos.
 constexpr base::TimeDelta kPhotoRefreshInterval = base::Seconds(60);
 
+// The default time to run screen saver before put the device into sleep.
+constexpr base::TimeDelta kDefaultScreenSaverDuration = base::Minutes(10);
+
 // The default animation playback speed. Not used in slideshow mode.
 constexpr float kAnimationPlaybackSpeed = 1.f;
 
diff --git a/ash/public/cpp/connectivity_services.cc b/ash/public/cpp/connectivity_services.cc
new file mode 100644
index 0000000..b7f68bd3
--- /dev/null
+++ b/ash/public/cpp/connectivity_services.cc
@@ -0,0 +1,20 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/public/cpp/connectivity_services.h"
+
+#include "ash/constants/ash_features.h"
+#include "chromeos/ash/services/connectivity/public/cpp/connectivity_services.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+
+namespace ash {
+
+void GetPasspointService(
+    mojo::PendingReceiver<chromeos::connectivity::mojom::PasspointService>
+        receiver) {
+  DCHECK(ash::features::IsPasspointSettingsEnabled());
+  ash::connectivity::BindToPasspointService(std::move(receiver));
+}
+
+}  // namespace ash
diff --git a/ash/public/cpp/connectivity_services.h b/ash/public/cpp/connectivity_services.h
new file mode 100644
index 0000000..b971518
--- /dev/null
+++ b/ash/public/cpp/connectivity_services.h
@@ -0,0 +1,20 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_PUBLIC_CPP_CONNECTIVITY_SERVICES_H_
+#define ASH_PUBLIC_CPP_CONNECTIVITY_SERVICES_H_
+
+#include "ash/public/cpp/ash_public_export.h"
+#include "chromeos/ash/services/connectivity/public/mojom/passpoint.mojom-forward.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+
+namespace ash {
+
+ASH_PUBLIC_EXPORT void GetPasspointService(
+    mojo::PendingReceiver<chromeos::connectivity::mojom::PasspointService>
+        receiver);
+
+}  // namespace ash
+
+#endif  // ASH_PUBLIC_CPP_CONNECTIVITY_SERVICES_H_
diff --git a/ash/public/cpp/holding_space/holding_space_item.cc b/ash/public/cpp/holding_space/holding_space_item.cc
index a3751a12..e1d5c3b4 100644
--- a/ash/public/cpp/holding_space/holding_space_item.cc
+++ b/ash/public/cpp/holding_space/holding_space_item.cc
@@ -109,6 +109,33 @@
 }
 
 // static
+bool HoldingSpaceItem::IsCameraAppType(HoldingSpaceItem::Type type) {
+  switch (type) {
+    case Type::kCameraAppPhoto:
+    case Type::kCameraAppScanJpg:
+    case Type::kCameraAppScanPdf:
+    case Type::kCameraAppVideoGif:
+    case Type::kCameraAppVideoMp4:
+      return true;
+    case Type::kArcDownload:
+    case Type::kDownload:
+    case Type::kDiagnosticsLog:
+    case Type::kDriveSuggestion:
+    case Type::kLacrosDownload:
+    case Type::kLocalSuggestion:
+    case Type::kNearbyShare:
+    case Type::kPhoneHubCameraRoll:
+    case Type::kPinnedFile:
+    case Type::kPrintedPdf:
+    case Type::kScan:
+    case Type::kScreenRecording:
+    case Type::kScreenRecordingGif:
+    case Type::kScreenshot:
+      return false;
+  }
+}
+
+// static
 bool HoldingSpaceItem::IsDownload(HoldingSpaceItem::Type type) {
   switch (type) {
     case Type::kArcDownload:
diff --git a/ash/public/cpp/holding_space/holding_space_item.h b/ash/public/cpp/holding_space/holding_space_item.h
index 175c71b..c6b813c3 100644
--- a/ash/public/cpp/holding_space/holding_space_item.h
+++ b/ash/public/cpp/holding_space/holding_space_item.h
@@ -121,12 +121,18 @@
       const HoldingSpaceProgress& progress,
       ImageResolver image_resolver);
 
+  // Returns `true` if `type` is a Camera app type, `false` otherwise.
+  static bool IsCameraAppType(HoldingSpaceItem::Type type);
+
+  // TODO(http://b/278147195): Rename to `IsDownloadType()`.
   // Returns `true` if `type` is a download type, `false` otherwise.
   static bool IsDownload(HoldingSpaceItem::Type type);
 
+  // TODO(http://b/278147195): Rename to `IsScreenCaptureType()`.
   // Returns `true` if `type` is a screen capture type, `false` otherwise.
   static bool IsScreenCapture(HoldingSpaceItem::Type type);
 
+  // TODO(http://b/278147195): Rename to `IsSuggestionType()`.
   // Returns `true` if `type` is a suggestion type, `false` otherwise.
   static bool IsSuggestion(HoldingSpaceItem::Type type);
 
diff --git a/ash/public/cpp/holding_space/holding_space_item_unittest.cc b/ash/public/cpp/holding_space/holding_space_item_unittest.cc
index 2e8faf7..625c51d 100644
--- a/ash/public/cpp/holding_space/holding_space_item_unittest.cc
+++ b/ash/public/cpp/holding_space/holding_space_item_unittest.cc
@@ -155,6 +155,36 @@
   EXPECT_TRUE(holding_space_item->in_progress_commands().empty());
 }
 
+// Tests identification of Camera app holding space item types.
+TEST_P(HoldingSpaceItemTest, IsCameraAppType) {
+  const HoldingSpaceItem::Type type = GetParam();
+  switch (type) {
+    case HoldingSpaceItem::Type::kCameraAppPhoto:
+    case HoldingSpaceItem::Type::kCameraAppScanJpg:
+    case HoldingSpaceItem::Type::kCameraAppScanPdf:
+    case HoldingSpaceItem::Type::kCameraAppVideoGif:
+    case HoldingSpaceItem::Type::kCameraAppVideoMp4:
+      EXPECT_TRUE(HoldingSpaceItem::IsCameraAppType(type));
+      return;
+    case HoldingSpaceItem::Type::kArcDownload:
+    case HoldingSpaceItem::Type::kDiagnosticsLog:
+    case HoldingSpaceItem::Type::kDownload:
+    case HoldingSpaceItem::Type::kDriveSuggestion:
+    case HoldingSpaceItem::Type::kLacrosDownload:
+    case HoldingSpaceItem::Type::kLocalSuggestion:
+    case HoldingSpaceItem::Type::kNearbyShare:
+    case HoldingSpaceItem::Type::kPhoneHubCameraRoll:
+    case HoldingSpaceItem::Type::kPinnedFile:
+    case HoldingSpaceItem::Type::kPrintedPdf:
+    case HoldingSpaceItem::Type::kScan:
+    case HoldingSpaceItem::Type::kScreenRecording:
+    case HoldingSpaceItem::Type::kScreenRecordingGif:
+    case HoldingSpaceItem::Type::kScreenshot:
+      EXPECT_FALSE(HoldingSpaceItem::IsCameraAppType(type));
+      return;
+  }
+}
+
 // Tests identification of screen capture holding space item types.
 TEST_P(HoldingSpaceItemTest, IsScreenCapture) {
   const HoldingSpaceItem::Type type = GetParam();
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index eab3730..b26f069 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -521,9 +521,12 @@
     "video_conference_background_blur_maximum.icon",
     "video_conference_background_blur_off.icon",
     "video_conference_camera_muted.icon",
+    "video_conference_live_caption_off.icon",
     "video_conference_live_caption_on.icon",
     "video_conference_microphone_muted.icon",
+    "video_conference_noise_cancellation_off.icon",
     "video_conference_noise_cancellation_on.icon",
+    "video_conference_portrait_relight_off.icon",
     "video_conference_portrait_relight_on.icon",
     "video_conference_up_chevron.icon",
     "visibility.icon",
diff --git a/ash/resources/vector_icons/video_conference_live_caption_off.icon b/ash/resources/vector_icons/video_conference_live_caption_off.icon
new file mode 100644
index 0000000..fdfa1f0
--- /dev/null
+++ b/ash/resources/vector_icons/video_conference_live_caption_off.icon
@@ -0,0 +1,69 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+R_MOVE_TO, 1.56f, 3.56f,
+R_LINE_TO, 1.06f, -1.06f,
+R_LINE_TO, 14.58f, 14.58f,
+R_LINE_TO, -1.06f, 1.06f,
+LINE_TO, 1.56f, 3.56f,
+CLOSE,
+NEW_PATH,
+MOVE_TO, 4.12f, 4,
+H_LINE_TO, 3.5f,
+R_CUBIC_TO, -0.42f, 0, -0.77f, 0.14f, -1.06f, 0.44f,
+ARC_TO, 1.45f, 1.45f, 0, 0, 0, 2, 5.5f,
+R_V_LINE_TO, 9,
+R_CUBIC_TO, 0, 0.42f, 0.14f, 0.77f, 0.44f, 1.06f,
+R_CUBIC_TO, 0.29f, 0.29f, 0.65f, 0.44f, 1.06f, 0.44f,
+R_H_LINE_TO, 12.62f,
+R_LINE_TO, -1.5f, -1.5f,
+H_LINE_TO, 3.5f,
+R_V_LINE_TO, -9,
+R_H_LINE_TO, 2.12f,
+LINE_TO, 4.12f, 4,
+CLOSE,
+NEW_PATH,
+MOVE_TO, 8.62f, 8.5f,
+H_LINE_TO, 8,
+V_LINE_TO, 10,
+R_H_LINE_TO, 2.12f,
+R_LINE_TO, -1.5f, -1.5f,
+CLOSE,
+MOVE_TO, 12.24f, 10,
+R_LINE_TO, -1.5f, -1.5f,
+H_LINE_TO, 15,
+V_LINE_TO, 10,
+R_H_LINE_TO, -2.76f,
+CLOSE,
+MOVE_TO, 15, 12.76f,
+R_LINE_TO, -1.26f, -1.26f,
+H_LINE_TO, 15,
+R_V_LINE_TO, 1.26f,
+CLOSE,
+NEW_PATH,
+MOVE_TO, 16.5f, 14.26f,
+V_LINE_TO, 5.5f,
+H_LINE_TO, 7.74f,
+LINE_TO, 6.24f, 4,
+H_LINE_TO, 16.5f,
+R_CUBIC_TO, 0.42f, 0, 0.77f, 0.15f, 1.06f, 0.44f,
+R_CUBIC_TO, 0.29f, 0.29f, 0.44f, 0.65f, 0.44f, 1.06f,
+R_V_LINE_TO, 9,
+R_CUBIC_TO, 0, 0.36f, -0.11f, 0.67f, -0.32f, 0.94f,
+LINE_TO, 16.5f, 14.26f,
+CLOSE,
+MOVE_TO, 11.62f, 11.5f,
+H_LINE_TO, 5,
+V_LINE_TO, 13,
+R_H_LINE_TO, 7,
+R_V_LINE_TO, -1.12f,
+R_LINE_TO, -0.38f, -0.38f,
+CLOSE,
+MOVE_TO, 5, 10,
+V_LINE_TO, 8.5f,
+R_H_LINE_TO, 1.5f,
+V_LINE_TO, 10,
+H_LINE_TO, 5,
+CLOSE
diff --git a/ash/resources/vector_icons/video_conference_noise_cancellation_off.icon b/ash/resources/vector_icons/video_conference_noise_cancellation_off.icon
new file mode 100644
index 0000000..26a9e65b
--- /dev/null
+++ b/ash/resources/vector_icons/video_conference_noise_cancellation_off.icon
@@ -0,0 +1,36 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 4.6f, 5.4f,
+R_CUBIC_TO, 2.53f, 2.53f, 2.53f, 6.66f, 0, 9.19f,
+R_LINE_TO, 1.06f, 1.06f,
+R_CUBIC_TO, 3.12f, -3.12f, 3.12f, -8.19f, 0, -11.31f,
+LINE_TO, 4.6f, 5.4f,
+CLOSE,
+NEW_PATH,
+MOVE_TO, 3.54f, 6.46f,
+LINE_TO, 2.48f, 7.52f,
+R_ARC_TO, 3.51f, 3.51f, 0, 0, 1, 0, 4.95f,
+R_LINE_TO, 1.06f, 1.06f,
+R_ARC_TO, 5, 5, 0, 0, 0, 0, -7.07f,
+CLOSE,
+MOVE_TO, 10.75f, 2,
+R_H_LINE_TO, -1.5f,
+R_V_LINE_TO, 16,
+R_H_LINE_TO, 1.5f,
+V_LINE_TO, 2,
+CLOSE,
+MOVE_TO, 14, 9.25f,
+R_H_LINE_TO, -1.5f,
+R_V_LINE_TO, 1.5f,
+H_LINE_TO, 14,
+R_V_LINE_TO, -1.5f,
+CLOSE,
+MOVE_TO, 17, 9.25f,
+R_H_LINE_TO, -1.5f,
+R_V_LINE_TO, 1.5f,
+H_LINE_TO, 17,
+R_V_LINE_TO, -1.5f,
+CLOSE
diff --git a/ash/resources/vector_icons/video_conference_portrait_relight_off.icon b/ash/resources/vector_icons/video_conference_portrait_relight_off.icon
new file mode 100644
index 0000000..feadc43
--- /dev/null
+++ b/ash/resources/vector_icons/video_conference_portrait_relight_off.icon
@@ -0,0 +1,36 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 15.03f, 12.37f,
+R_CUBIC_TO, -0.35f, -0.21f, -0.72f, -0.39f, -1.1f, -0.55f,
+R_LINE_TO, 2.03f, 2.03f,
+R_CUBIC_TO, -0.07f, -0.61f, -0.4f, -1.17f, -0.93f, -1.48f,
+CLOSE,
+MOVE_TO, 10, 5.5f,
+R_CUBIC_TO, 0.83f, 0, 1.5f, 0.67f, 1.5f, 1.5f,
+R_CUBIC_TO, 0, 0.64f, -0.41f, 1.19f, -0.98f, 1.4f,
+R_LINE_TO, 1.11f, 1.11f,
+R_CUBIC_TO, 0.82f, -0.54f, 1.37f, -1.46f, 1.37f, -2.51f,
+R_ARC_TO, 3, 3, 0, 0, 0, -5.51f, -1.63f,
+LINE_TO, 10, 7.88f,
+R_V_LINE_TO, -2.38f,
+CLOSE,
+MOVE_TO, 16.94f, 16.94f,
+LINE_TO, 3.06f, 3.06f,
+LINE_TO, 2, 4.12f,
+R_LINE_TO, 6.95f, 6.95f,
+R_CUBIC_TO, -1.44f, 0.15f, -2.79f, 0.6f, -3.99f, 1.3f,
+R_CUBIC_TO, -0.6f, 0.36f, -0.97f, 1.02f, -0.97f, 1.72f,
+R_V_LINE_TO, 1.91f,
+R_H_LINE_TO, 9.89f,
+R_LINE_TO, 2, 2,
+R_LINE_TO, 1.06f, -1.06f,
+CLOSE,
+MOVE_TO, 10, 14.5f,
+R_V_LINE_TO, -2,
+R_CUBIC_TO, 0.14f, 0, 0.27f, 0.02f, 0.41f, 0.03f,
+R_LINE_TO, 1.97f, 1.97f,
+H_LINE_TO, 10,
+CLOSE
diff --git a/ash/shell.cc b/ash/shell.cc
index 6124b102..c9ddde2 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -135,6 +135,7 @@
 #include "ash/system/geolocation/geolocation_controller.h"
 #include "ash/system/human_presence/human_presence_orientation_controller.h"
 #include "ash/system/human_presence/snooping_protection_controller.h"
+#include "ash/system/input_device_settings/input_device_key_alias_manager.h"
 #include "ash/system/input_device_settings/input_device_settings_controller_impl.h"
 #include "ash/system/input_device_settings/input_device_settings_dispatcher.h"
 #include "ash/system/input_device_settings/input_device_tracker.h"
@@ -747,6 +748,7 @@
   input_device_settings_dispatcher_.reset();
   input_device_tracker_.reset();
   input_device_settings_controller_.reset();
+  input_device_key_alias_manager_.reset();
 
   screen_orientation_controller_.reset();
   screen_layout_observer_.reset();
@@ -1253,6 +1255,9 @@
   window_modality_controller_ =
       std::make_unique<::wm::WindowModalityController>(this, env);
 
+  input_device_key_alias_manager_ =
+      std::make_unique<InputDeviceKeyAliasManager>();
+
   // The `InputDeviceSettingsController` is a dependency of the following so it
   // must be initialized first:
   //  - `EventRewriterController`
diff --git a/ash/shell.h b/ash/shell.h
index 8a979c1..d5a74de1 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -153,6 +153,7 @@
 class HoldingSpaceController;
 class HumanPresenceOrientationController;
 class ImeControllerImpl;
+class InputDeviceKeyAliasManager;
 class InputDeviceSettingsControllerImpl;
 class InputDeviceSettingsDispatcher;
 class InputDeviceTracker;
@@ -496,6 +497,11 @@
   EventRewriterControllerImpl* event_rewriter_controller() {
     return event_rewriter_controller_.get();
   }
+
+  InputDeviceKeyAliasManager* input_device_key_alias_manager() {
+    return input_device_key_alias_manager_.get();
+  }
+
   InputDeviceSettingsControllerImpl* input_device_settings_controller() {
     return input_device_settings_controller_.get();
   }
@@ -892,6 +898,7 @@
   std::unique_ptr<InputDeviceTracker> input_device_tracker_;
   std::unique_ptr<KeyboardModifierMetricsRecorder>
       keyboard_modifier_metrics_recorder_;
+  std::unique_ptr<InputDeviceKeyAliasManager> input_device_key_alias_manager_;
   std::unique_ptr<UserMetricsRecorder> user_metrics_recorder_;
 
   std::unique_ptr<AshAcceleratorConfiguration> ash_accelerator_configuration_;
diff --git a/ash/strings/ash_strings_da.xtb b/ash/strings/ash_strings_da.xtb
index e49e0492..e5e811b 100644
--- a/ash/strings/ash_strings_da.xtb
+++ b/ash/strings/ash_strings_da.xtb
@@ -1655,7 +1655,7 @@
 <translation id="8735678380411481005">Farve på tastaturets baggrundslys</translation>
 <translation id="8747464587821437069"><ph name="CAMERA_AND_MICROPHONE_ACCESS_STATUS" />,
         <ph name="SCREEN_SHARE_STATUS" /></translation>
-<translation id="8755498163081687682">Bekræft din identitet: <ph name="ORIGIN_NAME" /> ønsker, at du bekræfter din identitet</translation>
+<translation id="8755498163081687682">Verificer din identitet: <ph name="ORIGIN_NAME" /> ønsker, at du bekræfter din identitet</translation>
 <translation id="875593634123171288">Vis VPN-indstillinger</translation>
 <translation id="8759408218731716181">Samlet login fra flere konti kan ikke konfigureres</translation>
 <translation id="8763883995157866248">Aktivér dvaletilstand på enheden</translation>
diff --git a/ash/system/audio/audio_effects_controller.cc b/ash/system/audio/audio_effects_controller.cc
index 1727d88a..9b2c8ba 100644
--- a/ash/system/audio/audio_effects_controller.cc
+++ b/ash/system/audio/audio_effects_controller.cc
@@ -130,7 +130,8 @@
                           base::Unretained(this),
                           VcEffectId::kNoiseCancellation),
       /*effect_id=*/VcEffectId::kNoiseCancellation);
-  effect->AddState(std::make_unique<VcEffectState>(
+
+  auto effect_state = std::make_unique<VcEffectState>(
       /*icon=*/&kVideoConferenceNoiseCancellationOnIcon,
       /*label_text=*/
       l10n_util::GetStringUTF16(
@@ -141,7 +142,10 @@
       base::BindRepeating(&AudioEffectsController::OnEffectControlActivated,
                           weak_factory_.GetWeakPtr(),
                           /*effect_id=*/VcEffectId::kNoiseCancellation,
-                          /*value=*/0)));
+                          /*value=*/0));
+  effect_state->set_disabled_icon(&kVideoConferenceNoiseCancellationOffIcon);
+  effect->AddState(std::move(effect_state));
+
   effect->set_dependency_flags(VcHostedEffect::ResourceDependency::kMicrophone);
   AddEffect(std::move(effect));
 }
@@ -153,7 +157,8 @@
       base::BindRepeating(&AudioEffectsController::GetEffectState,
                           base::Unretained(this), VcEffectId::kLiveCaption),
       /*effect_id=*/VcEffectId::kLiveCaption);
-  effect->AddState(std::make_unique<VcEffectState>(
+
+  auto effect_state = std::make_unique<VcEffectState>(
       /*icon=*/&kVideoConferenceLiveCaptionOnIcon,
       /*label_text=*/
       l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_LIVE_CAPTION),
@@ -163,7 +168,10 @@
       base::BindRepeating(&AudioEffectsController::OnEffectControlActivated,
                           weak_factory_.GetWeakPtr(),
                           /*effect_id=*/VcEffectId::kLiveCaption,
-                          /*value=*/0)));
+                          /*value=*/0));
+  effect_state->set_disabled_icon(&kVideoConferenceLiveCaptionOffIcon);
+
+  effect->AddState(std::move(effect_state));
   AddEffect(std::move(effect));
 }
 
diff --git a/ash/system/camera/camera_effects_controller.cc b/ash/system/camera/camera_effects_controller.cc
index 415b631..576286c5 100644
--- a/ash/system/camera/camera_effects_controller.cc
+++ b/ash/system/camera/camera_effects_controller.cc
@@ -445,7 +445,8 @@
                             base::Unretained(this),
                             VcEffectId::kPortraitRelighting),
         /*effect_id=*/VcEffectId::kPortraitRelighting);
-    effect->AddState(std::make_unique<VcEffectState>(
+
+    auto effect_state = std::make_unique<VcEffectState>(
         /*icon=*/&kVideoConferencePortraitRelightOnIcon,
         /*label_text=*/
         l10n_util::GetStringUTF16(
@@ -456,7 +457,10 @@
         base::BindRepeating(&CameraEffectsController::OnEffectControlActivated,
                             base::Unretained(this),
                             /*effect_id=*/VcEffectId::kPortraitRelighting,
-                            /*value=*/absl::nullopt)));
+                            /*value=*/absl::nullopt));
+    effect_state->set_disabled_icon(&kVideoConferencePortraitRelightOffIcon);
+    effect->AddState(std::move(effect_state));
+
     effect->set_dependency_flags(VcHostedEffect::ResourceDependency::kCamera);
     AddEffect(std::move(effect));
   }
diff --git a/ash/system/geolocation/geolocation_controller.cc b/ash/system/geolocation/geolocation_controller.cc
index bdcd4665..c881893 100644
--- a/ash/system/geolocation/geolocation_controller.cc
+++ b/ash/system/geolocation/geolocation_controller.cc
@@ -16,6 +16,7 @@
 #include "base/time/clock.h"
 #include "chromeos/ash/components/geolocation/geoposition.h"
 #include "chromeos/ash/components/geolocation/simple_geolocation_provider.h"
+#include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "third_party/icu/source/i18n/astro.h"
 
@@ -48,7 +49,8 @@
                 std::move(factory),
                 SimpleGeolocationProvider::DefaultGeolocationProviderURL()),
       backoff_delay_(kMinimumDelayAfterFailure),
-      timer_(std::make_unique<base::OneShotTimer>()) {
+      timer_(std::make_unique<base::OneShotTimer>()),
+      scoped_session_observer_(this) {
   auto* timezone_settings = system::TimezoneSettings::GetInstance();
   current_timezone_id_ = timezone_settings->GetCurrentTimezoneID();
   timezone_settings->AddObserver(this);
@@ -68,6 +70,12 @@
   return controller;
 }
 
+// static
+void GeolocationController::RegisterProfilePrefs(PrefRegistrySimple* registry) {
+  registry->RegisterDoublePref(prefs::kDeviceGeolocationCachedLatitude, 0.0);
+  registry->RegisterDoublePref(prefs::kDeviceGeolocationCachedLongitude, 0.0);
+}
+
 void GeolocationController::AddObserver(Observer* observer) {
   const bool is_first_observer = observers_.empty();
   observers_.AddObserver(observer);
@@ -116,6 +124,16 @@
   return primary_user_prefs->GetBoolean(ash::prefs::kUserGeolocationAllowed);
 }
 
+void GeolocationController::OnActiveUserPrefServiceChanged(
+    PrefService* pref_service) {
+  if (pref_service == active_user_pref_service_.get()) {
+    return;
+  }
+
+  active_user_pref_service_ = pref_service;
+  LoadCachedGeopositionIfNeeded();
+}
+
 // static
 base::TimeDelta
 GeolocationController::GetNextRequestDelayAfterSuccessForTesting() {
@@ -163,6 +181,9 @@
   geoposition_->latitude = position.latitude;
   geoposition_->longitude = position.longitude;
 
+  is_current_geoposition_from_cache_ = false;
+  StoreCachedGeoposition();
+
   if (previous_sunset && previous_sunrise) {
     // If the change in geoposition results in an hour or more in either sunset
     // or sunrise times indicates of a possible timezone change.
@@ -231,4 +252,53 @@
   return base::Time::FromDoubleT(sun_rise_set_ms / 1000.0);
 }
 
+void GeolocationController::LoadCachedGeopositionIfNeeded() {
+  DCHECK(active_user_pref_service_);
+
+  // Even if there is a geoposition, but it's coming from a previously cached
+  // value, switching users should load the currently saved values for the
+  // new user. This is to keep users' prefs completely separate. We only ignore
+  // the cached values once we have a valid non-cached geoposition from any
+  // user in the same session.
+  if (geoposition_ && !is_current_geoposition_from_cache_) {
+    return;
+  }
+
+  if (!active_user_pref_service_->HasPrefPath(
+          prefs::kDeviceGeolocationCachedLatitude) ||
+      !active_user_pref_service_->HasPrefPath(
+          prefs::kDeviceGeolocationCachedLongitude)) {
+    LOG(ERROR)
+        << "No valid current geoposition and no valid cached geoposition"
+           " are available. Will use default times for sunset / sunrise.";
+    geoposition_.reset();
+    return;
+  }
+
+  geoposition_ = std::make_unique<SimpleGeoposition>();
+  geoposition_->latitude = active_user_pref_service_->GetDouble(
+      prefs::kDeviceGeolocationCachedLatitude);
+  geoposition_->longitude = active_user_pref_service_->GetDouble(
+      prefs::kDeviceGeolocationCachedLongitude);
+  is_current_geoposition_from_cache_ = true;
+}
+
+void GeolocationController::StoreCachedGeoposition() const {
+  CHECK(geoposition_);
+  const SessionControllerImpl* session_controller =
+      Shell::Get()->session_controller();
+  for (const auto& user_session : session_controller->GetUserSessions()) {
+    PrefService* pref_service = session_controller->GetUserPrefServiceForUser(
+        user_session->user_info.account_id);
+    if (!pref_service) {
+      continue;
+    }
+
+    pref_service->SetDouble(prefs::kDeviceGeolocationCachedLatitude,
+                            geoposition_->latitude);
+    pref_service->SetDouble(prefs::kDeviceGeolocationCachedLongitude,
+                            geoposition_->longitude);
+  }
+}
+
 }  // namespace ash
diff --git a/ash/system/geolocation/geolocation_controller.h b/ash/system/geolocation/geolocation_controller.h
index 24393ec..e25c998b 100644
--- a/ash/system/geolocation/geolocation_controller.h
+++ b/ash/system/geolocation/geolocation_controller.h
@@ -9,6 +9,8 @@
 #include <string>
 
 #include "ash/ash_export.h"
+#include "ash/public/cpp/session/session_observer.h"
+#include "base/memory/raw_ptr.h"
 #include "base/observer_list.h"
 #include "base/observer_list_types.h"
 #include "base/time/time.h"
@@ -18,6 +20,9 @@
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
+class PrefRegistrySimple;
+class PrefService;
+
 namespace base {
 class Clock;
 }  // namespace base
@@ -48,6 +53,7 @@
 class ASH_EXPORT GeolocationController
     : public system::TimezoneSettings::Observer,
       public chromeos::PowerManagerClient::Observer,
+      public SessionObserver,
       public SimpleGeolocationProvider::Delegate {
  public:
   class Observer : public base::CheckedObserver {
@@ -68,13 +74,10 @@
   ~GeolocationController() override;
 
   static GeolocationController* Get();
+  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
 
   const base::OneShotTimer& timer() const { return *timer_; }
 
-  base::Time last_successful_geo_request_time() const {
-    return last_successful_geo_request_time_;
-  }
-
   const std::u16string& current_timezone_id() const {
     return current_timezone_id_;
   }
@@ -91,8 +94,12 @@
   // SimpleGeolocationProvider::Delegate:
   bool IsPreciseGeolocationAllowed() const override;
 
-  // Returns sunset and sunrise time calculated from `geoposition_`. If the
-  // position is not set, returns the default sunset 6 PM and sunrise 6 AM.
+  // SessionObserver:
+  void OnActiveUserPrefServiceChanged(PrefService* pref_service) override;
+
+  // Returns sunset and sunrise time calculated from the most recently observed
+  // geoposition. If a geoposition has not been observed, defaults to sunset
+  // 6 PM and sunrise 6 AM.
   base::Time GetSunsetTime() const { return GetSunRiseSet(/*sunrise=*/false); }
   base::Time GetSunriseTime() const { return GetSunRiseSet(/*sunrise=*/true); }
 
@@ -145,8 +152,20 @@
   // the chances of getting inaccurate values, especially around DST changes.
   base::Time GetSunRiseSet(bool sunrise) const;
 
+  // Called only when the active user changes in order to see if we need to use
+  // a previously cached geoposition value from the active user's prefs.
+  void LoadCachedGeopositionIfNeeded();
+
+  // Called whenever we receive a new geoposition update to cache it in all
+  // logged-in users' prefs so that it can be used later in the event of not
+  // being able to retrieve a valid geoposition.
+  void StoreCachedGeoposition() const;
+
   network::SharedURLLoaderFactory* const factory_;
 
+  // May be null if a user has not logged in yet.
+  base::raw_ptr<PrefService> active_user_pref_service_;
+
   // The IP-based geolocation provider.
   SimpleGeolocationProvider provider_;
 
@@ -158,15 +177,22 @@
   // Optional Used in tests to override the time of "Now".
   base::Clock* clock_ = nullptr;  // Not owned.
 
-  // Last successful geoposition coordinates and its timestamp.
-  base::Time last_successful_geo_request_time_;
-
   // The ID of the current timezone in the format similar to "America/Chicago".
   std::u16string current_timezone_id_;
 
   base::ObserverList<Observer> observers_;
 
+  // True if the current `geoposition_` is from a previously cached value in the
+  // user prefs of any of the users in the current session. It is reset to false
+  // once we receive a newly-updated geoposition. This is used to treat the
+  // current geoposition as temporary until we receive a valid geoposition
+  // update, and also not to let a cached geoposition value to leak to another
+  // user for privacy reasons.
+  bool is_current_geoposition_from_cache_ = false;
+
   std::unique_ptr<SimpleGeoposition> geoposition_;
+
+  ScopedSessionObserver scoped_session_observer_;
 };
 
 }  // namespace ash
diff --git a/ash/system/geolocation/geolocation_controller_unittest.cc b/ash/system/geolocation/geolocation_controller_unittest.cc
index 943558f..2ed2137 100644
--- a/ash/system/geolocation/geolocation_controller_unittest.cc
+++ b/ash/system/geolocation/geolocation_controller_unittest.cc
@@ -4,18 +4,24 @@
 
 #include "ash/system/geolocation/geolocation_controller.h"
 
+#include "ash/constants/ash_pref_names.h"
+#include "ash/session/session_controller_impl.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/system/geolocation/geolocation_controller_test_util.h"
 #include "ash/system/geolocation/test_geolocation_url_loader_factory.h"
 #include "ash/system/time/time_of_day.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test_shell_delegate.h"
+#include "base/check.h"
+#include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/simple_test_clock.h"
 #include "base/time/clock.h"
 #include "base/time/time.h"
 #include "base/timer/mock_timer.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
+#include "components/prefs/pref_service.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "third_party/icu/source/i18n/unicode/timezone.h"
 
@@ -23,6 +29,26 @@
 
 namespace {
 
+constexpr char kUser1Email[] = "user1@geolocation";
+constexpr char kUser2Email[] = "user2@geolocation";
+
+// Sets of test longitudes/latitude and the corresponding sunrise/sunset times
+// for testing. They all assume the clock's current time is `kTestNow`.
+constexpr base::StringPiece kTestNow = "23 Dec 2021 12:00:00";
+
+constexpr double kTestLatitude1 = 23.5;
+constexpr double kTestLongitude1 = 35.88;
+constexpr base::StringPiece kTestSunriseTime1 = "23 Dec 2021 04:14:36.626";
+constexpr base::StringPiece kTestSunsetTime1 = "23 Dec 2021 14:59:58.459";
+
+constexpr double kTestLatitude2 = 37.5;
+constexpr double kTestLongitude2 = -100.5;
+constexpr base::StringPiece kTestSunriseTime2 = "23 Dec 2021 13:55:13.306";
+constexpr base::StringPiece kTestSunsetTime2 = "23 Dec 2021 23:33:46.855";
+
+constexpr int kDefaultSunsetTimeOffsetMinutes = 18 * 60;
+constexpr int kDefaultSunriseTimeOffsetMinutes = 6 * 60;
+
 // Constructs a TimeZone object from the given `timezone_id`.
 std::unique_ptr<icu::TimeZone> CreateTimezone(const char* timezone_id) {
   return base::WrapUnique(icu::TimeZone::createTimeZone(
@@ -33,6 +59,13 @@
   return system::TimezoneSettings::GetTimezoneID(timezone);
 }
 
+base::Time ToUTCTime(base::StringPiece utc_time_str) {
+  base::Time time;
+  CHECK(base::Time::FromUTCString(utc_time_str.data(), &time))
+      << "Invalid UTC time string specified: " << utc_time_str;
+  return time;
+}
+
 // Base test fixture.
 class GeolocationControllerTest : public AshTestBase {
  public:
@@ -47,6 +80,7 @@
   // AshTestBase:
   void SetUp() override {
     AshTestBase::SetUp();
+    CreateTestUserSessions();
     controller_ = std::make_unique<GeolocationController>(
         static_cast<scoped_refptr<network::SharedURLLoaderFactory>>(
             base::MakeRefCounted<TestGeolocationUrlLoaderFactory>()));
@@ -79,6 +113,27 @@
   base::OneShotTimer* timer_ptr() const { return timer_ptr_; }
   const Geoposition& position() const { return position_; }
 
+  PrefService* user1_pref_service() {
+    return Shell::Get()->session_controller()->GetUserPrefServiceForUser(
+        AccountId::FromUserEmail(kUser1Email));
+  }
+
+  PrefService* user2_pref_service() {
+    return Shell::Get()->session_controller()->GetUserPrefServiceForUser(
+        AccountId::FromUserEmail(kUser2Email));
+  }
+
+  void CreateTestUserSessions() {
+    GetSessionControllerClient()->Reset();
+    GetSessionControllerClient()->AddUserSession(kUser1Email);
+    GetSessionControllerClient()->AddUserSession(kUser2Email);
+  }
+
+  void SwitchActiveUser(const std::string& email) {
+    GetSessionControllerClient()->SwitchActiveUser(
+        AccountId::FromUserEmail(email));
+  }
+
   // Fires the timer of the scheduler to request geoposition and wait for all
   // observers to receive the latest geoposition from the server.
   void FireTimerToFetchGeoposition() {
@@ -96,6 +151,7 @@
   // `GeolocationController` request.
   void SetServerPosition(const Geoposition& position) {
     position_ = position;
+    factory_->ClearResponses();
     factory_->set_position(position_);
   }
 
@@ -222,11 +278,6 @@
 // Tests obtaining sunset/sunrise time when there is no valid geoposition, for
 // example, due to lack of connectivity.
 TEST_F(GeolocationControllerTest, SunsetSunriseDefault) {
-  // Default sunset time at 6:00 PM as an offset from 00:00.
-  constexpr int kDefaultSunsetTimeOffsetMinutes = 18 * 60;
-  // Default sunrise time at 6:00 AM as an offset from 00:00.
-  constexpr int kDefaultSunriseTimeOffsetMinutes = 6 * 60;
-
   // If geoposition is unset, the controller should return the default sunset
   // and sunrise time .
   EXPECT_EQ(controller()->GetSunsetTime(),
@@ -238,39 +289,32 @@
 // Tests the behavior when there is a valid geoposition, sunrise and sunset
 // times are calculated correctly.
 TEST_F(GeolocationControllerTest, GetSunRiseSet) {
-  base::Time now;
-  EXPECT_TRUE(base::Time::FromUTCString("23 Dec 2021 12:00:00", &now));
-  test_clock()->SetNow(now);
-
-  base::Time sunrise;
-  EXPECT_TRUE(base::Time::FromUTCString("23 Dec 2021 04:14:36.626", &sunrise));
-  base::Time sunset;
-  EXPECT_TRUE(base::Time::FromUTCString("23 Dec 2021 14:59:58.459", &sunset));
+  test_clock()->SetNow(ToUTCTime(kTestNow));
 
   // Add an observer and make sure that sunset and sunrise time are not
   // updated until the timer is fired.
   GeolocationControllerObserver observer1;
   controller()->AddObserver(&observer1);
   EXPECT_TRUE(timer_ptr()->IsRunning());
-  EXPECT_NE(controller()->GetSunsetTime(), sunset);
-  EXPECT_NE(controller()->GetSunriseTime(), sunrise);
+  EXPECT_NE(controller()->GetSunsetTime(), ToUTCTime(kTestSunsetTime1));
+  EXPECT_NE(controller()->GetSunriseTime(), ToUTCTime(kTestSunriseTime1));
   EXPECT_EQ(0, observer1.position_received_num());
 
   // Prepare a valid geoposition.
   Geoposition position;
-  position.latitude = 23.5;
-  position.longitude = 35.88;
+  position.latitude = kTestLatitude1;
+  position.longitude = kTestLongitude1;
   position.status = Geoposition::STATUS_OK;
   position.accuracy = 10;
-  position.timestamp = now;
+  position.timestamp = ToUTCTime(kTestNow);
 
   // Test that after sending the new position, sunrise and sunset time are
   // updated correctly.
   SetServerPosition(position);
   FireTimerToFetchGeoposition();
   EXPECT_EQ(1, observer1.position_received_num());
-  EXPECT_EQ(controller()->GetSunsetTime(), sunset);
-  EXPECT_EQ(controller()->GetSunriseTime(), sunrise);
+  EXPECT_EQ(controller()->GetSunsetTime(), ToUTCTime(kTestSunsetTime1));
+  EXPECT_EQ(controller()->GetSunriseTime(), ToUTCTime(kTestSunriseTime1));
   EXPECT_TRUE(timer_ptr()->IsRunning());
 }
 
@@ -313,6 +357,92 @@
   EXPECT_EQ(next_request_delay_after_success, timer_ptr()->GetCurrentDelay());
 }
 
+// Tests the behavior when there is no valid geoposition for example due to lack
+// of connectivity.
+TEST_F(GeolocationControllerTest, AbsentValidGeoposition) {
+  test_clock()->SetNow(ToUTCTime(kTestNow));
+
+  // Initially, no values are stored in either of the two users' prefs.
+  ASSERT_FALSE(user1_pref_service()->HasPrefPath(
+      prefs::kDeviceGeolocationCachedLatitude));
+  ASSERT_FALSE(user1_pref_service()->HasPrefPath(
+      prefs::kDeviceGeolocationCachedLongitude));
+  ASSERT_FALSE(user2_pref_service()->HasPrefPath(
+      prefs::kDeviceGeolocationCachedLatitude));
+  ASSERT_FALSE(user2_pref_service()->HasPrefPath(
+      prefs::kDeviceGeolocationCachedLongitude));
+
+  // Store fake geoposition in user 2's prefs.
+  user2_pref_service()->SetDouble(prefs::kDeviceGeolocationCachedLatitude,
+                                  kTestLatitude1);
+  user2_pref_service()->SetDouble(prefs::kDeviceGeolocationCachedLongitude,
+                                  kTestLongitude1);
+
+  // Switch to user 2 and expect that geoposition is loaded from pref.
+  SwitchActiveUser(kUser2Email);
+  EXPECT_EQ(controller()->GetSunsetTime(), ToUTCTime(kTestSunsetTime1));
+  EXPECT_EQ(controller()->GetSunriseTime(), ToUTCTime(kTestSunriseTime1));
+
+  // Switching to user 1 should ignore the current geoposition since it's
+  // a cached value from user 2's prefs rather than a newly-updated value.
+  SwitchActiveUser(kUser1Email);
+  EXPECT_EQ(controller()->GetSunsetTime(),
+            TimeOfDay(kDefaultSunsetTimeOffsetMinutes)
+                .SetClock(test_clock())
+                .ToTimeToday());
+  EXPECT_EQ(controller()->GetSunriseTime(),
+            TimeOfDay(kDefaultSunriseTimeOffsetMinutes)
+                .SetClock(test_clock())
+                .ToTimeToday());
+
+  // Now simulate receiving a live geoposition update.
+  Geoposition position;
+  position.latitude = kTestLatitude1;
+  position.longitude = kTestLongitude1;
+  position.status = Geoposition::STATUS_OK;
+  position.accuracy = 10;
+  position.timestamp = ToUTCTime(kTestNow);
+  SetServerPosition(position);
+  FireTimerToFetchGeoposition();
+  EXPECT_EQ(controller()->GetSunsetTime(), ToUTCTime(kTestSunsetTime1));
+  EXPECT_EQ(controller()->GetSunriseTime(), ToUTCTime(kTestSunriseTime1));
+
+  // Update user 2's prefs with different geoposition.
+  user2_pref_service()->SetDouble(prefs::kDeviceGeolocationCachedLatitude,
+                                  kTestLatitude2);
+  user2_pref_service()->SetDouble(prefs::kDeviceGeolocationCachedLongitude,
+                                  kTestLongitude2);
+
+  // Now switching to user 2 should completely ignore their cached geopsoition,
+  // since from now on we have a valid newly-retrieved value.
+  SwitchActiveUser(kUser2Email);
+  EXPECT_EQ(controller()->GetSunsetTime(), ToUTCTime(kTestSunsetTime1));
+  EXPECT_EQ(controller()->GetSunriseTime(), ToUTCTime(kTestSunriseTime1));
+
+  // Clear all cached geoposition prefs for all users, just to make sure getting
+  // a new geoposition will persist it for all users not just the active one.
+  user1_pref_service()->ClearPref(prefs::kDeviceGeolocationCachedLatitude);
+  user1_pref_service()->ClearPref(prefs::kDeviceGeolocationCachedLongitude);
+  user2_pref_service()->ClearPref(prefs::kDeviceGeolocationCachedLatitude);
+  user2_pref_service()->ClearPref(prefs::kDeviceGeolocationCachedLongitude);
+
+  // Now simulate receiving another live geoposition update.
+  position.latitude = kTestLatitude2;
+  position.longitude = kTestLongitude2;
+  SetServerPosition(position);
+  FireTimerToFetchGeoposition();
+  EXPECT_EQ(controller()->GetSunsetTime(), ToUTCTime(kTestSunsetTime2));
+  EXPECT_EQ(controller()->GetSunriseTime(), ToUTCTime(kTestSunriseTime2));
+  EXPECT_EQ(kTestLatitude2, user1_pref_service()->GetDouble(
+                                prefs::kDeviceGeolocationCachedLatitude));
+  EXPECT_EQ(kTestLongitude2, user1_pref_service()->GetDouble(
+                                 prefs::kDeviceGeolocationCachedLongitude));
+  EXPECT_EQ(kTestLatitude2, user2_pref_service()->GetDouble(
+                                prefs::kDeviceGeolocationCachedLatitude));
+  EXPECT_EQ(kTestLongitude2, user2_pref_service()->GetDouble(
+                                 prefs::kDeviceGeolocationCachedLongitude));
+}
+
 }  // namespace
 
 }  // namespace ash
diff --git a/ash/system/input_device_settings/input_device_key_alias_manager.cc b/ash/system/input_device_settings/input_device_key_alias_manager.cc
index 82e4051..2623268 100644
--- a/ash/system/input_device_settings/input_device_key_alias_manager.cc
+++ b/ash/system/input_device_settings/input_device_key_alias_manager.cc
@@ -4,9 +4,52 @@
 
 #include "ash/system/input_device_settings/input_device_key_alias_manager.h"
 
-namespace ash {
+#include "ash/system/input_device_settings/input_device_settings_utils.h"
+#include "base/strings/string_piece.h"
 
-InputDeviceKeyAliasManager::InputDeviceKeyAliasManager() = default;
+namespace ash {
+namespace {
+
+// Device Key - Built using the VID/PID for the device "<vid>:<pid>"
+// Contains entries in the form of <aliased_key, primary_key> for devices that
+// report different PID/VIDs depending on the connection method used
+// (Bluetooth/USB). The device key reported when connected via USB will be
+// used as the primary key for a set of keys belonging to a device.
+static constexpr std::pair<const char*, const char*>
+    kAliasToPrimaryDeviceKeyMap[] = {
+        // Apple Magic Keyboard
+        {"05ac:026c", "004c:026c"},
+};
+
+}  // namespace
+
+InputDeviceKeyAliasManager::InputDeviceKeyAliasManager() {
+  for (const auto& [aliased_key, primary_key] : kAliasToPrimaryDeviceKeyMap) {
+    AddDeviceKeyPair(primary_key, aliased_key);
+  }
+}
+
 InputDeviceKeyAliasManager::~InputDeviceKeyAliasManager() = default;
 
+std::string InputDeviceKeyAliasManager::GetAliasedDeviceKey(
+    const ui::InputDevice& device) {
+  const std::string key = BuildDeviceKey(device);
+  const auto it = alias_to_primary_key_map_.find(key);
+  return it == alias_to_primary_key_map_.end() ? key : it->second;
+}
+
+const base::flat_set<std::string>*
+InputDeviceKeyAliasManager::GetAliasesForPrimaryDeviceKey(
+    base::StringPiece primary_device_key) const {
+  const auto it = primary_key_to_aliases_map_.find(primary_device_key);
+  return it == primary_key_to_aliases_map_.end() ? nullptr : &it->second;
+}
+
+void InputDeviceKeyAliasManager::AddDeviceKeyPair(
+    const std::string& primary_key,
+    const std::string& aliased_key) {
+  primary_key_to_aliases_map_[primary_key].insert(aliased_key);
+  alias_to_primary_key_map_.emplace(aliased_key, primary_key);
+}
+
 }  // namespace ash
diff --git a/ash/system/input_device_settings/input_device_key_alias_manager.h b/ash/system/input_device_settings/input_device_key_alias_manager.h
index 5a082b3..9c924a2 100644
--- a/ash/system/input_device_settings/input_device_key_alias_manager.h
+++ b/ash/system/input_device_settings/input_device_key_alias_manager.h
@@ -5,10 +5,20 @@
 #ifndef ASH_SYSTEM_INPUT_DEVICE_SETTINGS_INPUT_DEVICE_KEY_ALIAS_MANAGER_H_
 #define ASH_SYSTEM_INPUT_DEVICE_SETTINGS_INPUT_DEVICE_KEY_ALIAS_MANAGER_H_
 
+#include <string>
+
 #include "ash/ash_export.h"
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
+#include "base/strings/string_piece_forward.h"
+#include "ui/events/devices/input_device.h"
 
 namespace ash {
 
+using PrimaryDeviceKeyToAliasesMap =
+    base::flat_map<std::string, base::flat_set<std::string>>;
+using AliasToPrimaryDeviceKeyMap = base::flat_map<std::string, std::string>;
+
 class ASH_EXPORT InputDeviceKeyAliasManager {
  public:
   InputDeviceKeyAliasManager();
@@ -16,6 +26,20 @@
   InputDeviceKeyAliasManager& operator=(const InputDeviceKeyAliasManager&) =
       delete;
   ~InputDeviceKeyAliasManager();
+  // Builds the device key for `device` and checks to see if it's an alias
+  // to a device's primary key or not before returning.
+  std::string GetAliasedDeviceKey(const ui::InputDevice& device);
+  // Uses `primary_device_key` to retrieve all aliased device keys for a given
+  // device.
+  const base::flat_set<std::string>* GetAliasesForPrimaryDeviceKey(
+      base::StringPiece primary_device_key) const;
+
+  void AddDeviceKeyPair(const std::string& primary_key,
+                        const std::string& aliased_key);
+
+ private:
+  PrimaryDeviceKeyToAliasesMap primary_key_to_aliases_map_;
+  AliasToPrimaryDeviceKeyMap alias_to_primary_key_map_;
 };
 
 }  // namespace ash
diff --git a/ash/system/input_device_settings/input_device_key_alias_manager_unittest.cc b/ash/system/input_device_settings/input_device_key_alias_manager_unittest.cc
index 36c69e19..9a295e0 100644
--- a/ash/system/input_device_settings/input_device_key_alias_manager_unittest.cc
+++ b/ash/system/input_device_settings/input_device_key_alias_manager_unittest.cc
@@ -4,10 +4,18 @@
 
 #include "ash/system/input_device_settings/input_device_key_alias_manager.h"
 
+#include "ash/system/input_device_settings/input_device_settings_utils.h"
 #include "ash/test/ash_test_base.h"
+#include "base/containers/contains.h"
+#include "ui/events/devices/input_device.h"
 
 namespace ash {
-
+namespace {
+const ui::InputDevice CreateInputDevice(uint16_t vendor, uint16_t product) {
+  return ui::InputDevice(5, ui::INPUT_DEVICE_INTERNAL, "kDeviceName", "",
+                         base::FilePath(), vendor, product, 0);
+}
+}  // namespace
 class InputDeviceKeyAliasManagerTest : public AshTestBase {
  public:
   InputDeviceKeyAliasManagerTest() = default;
@@ -32,8 +40,20 @@
   std::unique_ptr<InputDeviceKeyAliasManager> manager_;
 };
 
-TEST_F(InputDeviceKeyAliasManagerTest, InitializationTest) {
+TEST_F(InputDeviceKeyAliasManagerTest, DeviceKeyAliasing) {
   EXPECT_NE(manager_.get(), nullptr);
+  const auto device_usb = CreateInputDevice(0x1111, 0x1111);
+  const auto device_bluetooh = CreateInputDevice(0x1112, 0x1111);
+  const auto primary_device_key = BuildDeviceKey(device_usb);
+  const auto aliased_device_key = BuildDeviceKey(device_bluetooh);
+  manager_->AddDeviceKeyPair(primary_device_key, aliased_device_key);
+
+  EXPECT_EQ(primary_device_key, manager_->GetAliasedDeviceKey(device_usb));
+  EXPECT_EQ(primary_device_key, manager_->GetAliasedDeviceKey(device_bluetooh));
+  const auto aliases =
+      *manager_->GetAliasesForPrimaryDeviceKey(primary_device_key);
+  EXPECT_EQ(1u, aliases.size());
+  EXPECT_TRUE(base::Contains(aliases, aliased_device_key));
 }
 
 }  // namespace ash
diff --git a/ash/system/input_device_settings/input_device_settings_controller_impl.cc b/ash/system/input_device_settings/input_device_settings_controller_impl.cc
index e7144e9..eb6e820 100644
--- a/ash/system/input_device_settings/input_device_settings_controller_impl.cc
+++ b/ash/system/input_device_settings/input_device_settings_controller_impl.cc
@@ -12,6 +12,7 @@
 #include "ash/public/mojom/input_device_settings.mojom.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
+#include "ash/system/input_device_settings/input_device_key_alias_manager.h"
 #include "ash/system/input_device_settings/input_device_notifier.h"
 #include "ash/system/input_device_settings/input_device_settings_defaults.h"
 #include "ash/system/input_device_settings/input_device_settings_policy_handler.h"
@@ -60,7 +61,9 @@
   mojom::KeyboardPtr mojom_keyboard = mojom::Keyboard::New();
   mojom_keyboard->id = keyboard.id;
   mojom_keyboard->name = keyboard.name;
-  mojom_keyboard->device_key = BuildDeviceKey(keyboard);
+  mojom_keyboard->device_key =
+      Shell::Get()->input_device_key_alias_manager()->GetAliasedDeviceKey(
+          keyboard);
   mojom_keyboard->is_external =
       keyboard.type != ui::InputDeviceType::INPUT_DEVICE_INTERNAL;
   // Enable only when flag is enabled to avoid crashing while problem is
@@ -77,7 +80,9 @@
   mojom::MousePtr mojom_mouse = mojom::Mouse::New();
   mojom_mouse->id = mouse.id;
   mojom_mouse->name = mouse.name;
-  mojom_mouse->device_key = BuildDeviceKey(mouse);
+  mojom_mouse->device_key =
+      Shell::Get()->input_device_key_alias_manager()->GetAliasedDeviceKey(
+          mouse);
   mojom_mouse->is_external =
       mouse.type != ui::InputDeviceType::INPUT_DEVICE_INTERNAL;
   return mojom_mouse;
@@ -87,7 +92,9 @@
   mojom::TouchpadPtr mojom_touchpad = mojom::Touchpad::New();
   mojom_touchpad->id = touchpad.id;
   mojom_touchpad->name = touchpad.name;
-  mojom_touchpad->device_key = BuildDeviceKey(touchpad);
+  mojom_touchpad->device_key =
+      Shell::Get()->input_device_key_alias_manager()->GetAliasedDeviceKey(
+          touchpad);
   mojom_touchpad->is_external =
       touchpad.type != ui::InputDeviceType::INPUT_DEVICE_INTERNAL;
   return mojom_touchpad;
@@ -98,7 +105,9 @@
   mojom::PointingStickPtr mojom_pointing_stick = mojom::PointingStick::New();
   mojom_pointing_stick->id = touchpad.id;
   mojom_pointing_stick->name = touchpad.name;
-  mojom_pointing_stick->device_key = BuildDeviceKey(touchpad);
+  mojom_pointing_stick->device_key =
+      Shell::Get()->input_device_key_alias_manager()->GetAliasedDeviceKey(
+          touchpad);
   mojom_pointing_stick->is_external =
       touchpad.type != ui::InputDeviceType::INPUT_DEVICE_INTERNAL;
   return mojom_pointing_stick;
diff --git a/ash/system/input_device_settings/input_device_settings_metrics_manager.cc b/ash/system/input_device_settings/input_device_settings_metrics_manager.cc
index c1b3218..8b74a5a 100644
--- a/ash/system/input_device_settings/input_device_settings_metrics_manager.cc
+++ b/ash/system/input_device_settings/input_device_settings_metrics_manager.cc
@@ -7,7 +7,9 @@
 #include "ash/public/mojom/input_device_settings.mojom-forward.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
+#include "base/containers/fixed_flat_map.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/strings/strcat.h"
 
 namespace ash {
 
@@ -22,6 +24,17 @@
   kMaxValue = kHighest,
 };
 
+constexpr auto kModifierNames =
+    base::MakeFixedFlatMap<ui::mojom::ModifierKey, const char*>({
+        {ui::mojom::ModifierKey::kMeta, "Meta"},
+        {ui::mojom::ModifierKey::kControl, "Control"},
+        {ui::mojom::ModifierKey::kAlt, "Alt"},
+        {ui::mojom::ModifierKey::kCapsLock, "CapsLock"},
+        {ui::mojom::ModifierKey::kEscape, "Escape"},
+        {ui::mojom::ModifierKey::kBackspace, "Backspace"},
+        {ui::mojom::ModifierKey::kAssistant, "Assistant"},
+    });
+
 std::string GetKeyboardMetricsPrefix(const mojom::Keyboard& keyboard) {
   if (!keyboard.is_external) {
     return "ChromeOS.Settings.Device.Keyboard.Internal.";
@@ -33,6 +46,16 @@
   }
 }
 
+ui::mojom::ModifierKey GetModifierRemappingTo(
+    const mojom::KeyboardSettings& settings,
+    ui::mojom::ModifierKey modifier_key) {
+  const auto iter = settings.modifier_remappings.find(modifier_key);
+  if (iter != settings.modifier_remappings.end()) {
+    return iter->second;
+  }
+  return modifier_key;
+}
+
 }  // namespace
 
 InputDeviceSettingsMetricsManager::InputDeviceSettingsMetricsManager() =
@@ -65,6 +88,18 @@
         keyboard_metrics_prefix + "BlockMetaFKeyRewrites.Initial",
         keyboard.settings->suppress_meta_fkey_rewrites);
   }
+
+  // Record metrics for modifier remappings.
+  for (const auto modifier_key : keyboard.modifier_keys) {
+    auto* modifier_name_iter = kModifierNames.find(modifier_key);
+    DCHECK(modifier_name_iter != kModifierNames.end());
+    const auto key_remapped_to =
+        GetModifierRemappingTo(*keyboard.settings, modifier_key);
+    const std::string modifier_remapping_metrics =
+        base::StrCat({keyboard_metrics_prefix, "Modifiers.",
+                      modifier_name_iter->second, "RemappedTo.Initial"});
+    base::UmaHistogramEnumeration(modifier_remapping_metrics, key_remapped_to);
+  }
 }
 
 void InputDeviceSettingsMetricsManager::RecordKeyboardChangedMetrics(
@@ -86,6 +121,23 @@
         keyboard_metrics_prefix + "BlockMetaFKeyRewrites.Changed",
         keyboard.settings->suppress_meta_fkey_rewrites);
   }
+
+  // Record metrics for modifier remappings.
+  for (const auto modifier_key : keyboard.modifier_keys) {
+    auto* modifier_name_iter = kModifierNames.find(modifier_key);
+    DCHECK(modifier_name_iter != kModifierNames.end());
+    const auto key_remapped_to_before =
+        GetModifierRemappingTo(old_settings, modifier_key);
+    const auto key_remapped_to =
+        GetModifierRemappingTo(*keyboard.settings, modifier_key);
+    if (key_remapped_to_before != key_remapped_to) {
+      const std::string modifier_remapping_metrics =
+          base::StrCat({keyboard_metrics_prefix, "Modifiers.",
+                        modifier_name_iter->second, "RemappedTo.Changed"});
+      base::UmaHistogramEnumeration(modifier_remapping_metrics,
+                                    key_remapped_to);
+    }
+  }
 }
 
 void InputDeviceSettingsMetricsManager::RecordMouseInitialMetrics(
diff --git a/ash/system/input_device_settings/input_device_settings_metrics_manager_unittest.cc b/ash/system/input_device_settings/input_device_settings_metrics_manager_unittest.cc
index 5edf2312..daed85d 100644
--- a/ash/system/input_device_settings/input_device_settings_metrics_manager_unittest.cc
+++ b/ash/system/input_device_settings/input_device_settings_metrics_manager_unittest.cc
@@ -324,4 +324,48 @@
       /*expected_count=*/1u);
 }
 
+TEST_F(InputDeviceSettingsMetricsManagerTest, RecordModifierRemappingMetrics) {
+  mojom::Keyboard keyboard;
+  keyboard.device_key = kExternalKeyboardId;
+  keyboard.is_external = false;
+  keyboard.modifier_keys = {
+      ui::mojom::ModifierKey::kAlt,
+      ui::mojom::ModifierKey::kMeta,
+      ui::mojom::ModifierKey::kAssistant,
+  };
+  keyboard.settings = mojom::KeyboardSettings::New();
+  keyboard.settings->modifier_remappings = {
+      {ui::mojom::ModifierKey::kMeta, ui::mojom::ModifierKey::kControl},
+  };
+  base::HistogramTester histogram_tester;
+  manager_.get()->RecordKeyboardInitialMetrics(keyboard);
+  histogram_tester.ExpectTotalCount(
+      "ChromeOS.Settings.Device.Keyboard.Internal.Modifiers.AltRemappedTo."
+      "Initial",
+      /*expected_count=*/1u);
+  histogram_tester.ExpectTotalCount(
+      "ChromeOS.Settings.Device.Keyboard.Internal.Modifiers.MetaRemappedTo."
+      "Initial",
+      /*expected_count=*/1u);
+
+  const auto old_settings = std::move(keyboard.settings);
+  keyboard.settings = mojom::KeyboardSettings::New();
+  keyboard.settings->modifier_remappings = {
+      {ui::mojom::ModifierKey::kAlt, ui::mojom::ModifierKey::kControl},
+      {ui::mojom::ModifierKey::kMeta, ui::mojom::ModifierKey::kCapsLock},
+  };
+  manager_.get()->RecordKeyboardChangedMetrics(keyboard, *old_settings);
+  histogram_tester.ExpectTotalCount(
+      "ChromeOS.Settings.Device.Keyboard.Internal.Modifiers.AltRemappedTo."
+      "Changed",
+      /*expected_count=*/1u);
+  histogram_tester.ExpectTotalCount(
+      "ChromeOS.Settings.Device.Keyboard.Internal.Modifiers.MetaRemappedTo."
+      "Changed",
+      /*expected_count=*/1u);
+  histogram_tester.ExpectTotalCount(
+      "ChromeOS.Settings.Device.Keyboard.Internal.Modifiers."
+      "AssistantRemappedTo.Changed",
+      /*expected_count=*/0);
+}
 }  // namespace ash
\ No newline at end of file
diff --git a/ash/system/input_device_settings/input_device_tracker.cc b/ash/system/input_device_settings/input_device_tracker.cc
index 8ec717ed..0198d2fe 100644
--- a/ash/system/input_device_settings/input_device_tracker.cc
+++ b/ash/system/input_device_settings/input_device_tracker.cc
@@ -10,6 +10,7 @@
 #include "ash/constants/ash_features.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
+#include "ash/system/input_device_settings/input_device_key_alias_manager.h"
 #include "ash/system/input_device_settings/input_device_settings_controller_impl.h"
 #include "ash/system/input_device_settings/input_device_settings_pref_names.h"
 #include "base/containers/contains.h"
@@ -143,12 +144,31 @@
   std::vector<std::string> previously_observed_devices =
       observed_devices->GetValue();
 
-  if (!base::Contains(previously_observed_devices, device_key)) {
+  if (!base::Contains(previously_observed_devices, device_key) &&
+      !HasSeenPrimaryDeviceKeyAlias(previously_observed_devices, device_key)) {
     previously_observed_devices.emplace_back(device_key);
     observed_devices->SetValue(previously_observed_devices);
   }
 }
 
+bool InputDeviceTracker::HasSeenPrimaryDeviceKeyAlias(
+    const std::vector<std::string>& previously_observed_devices,
+    base::StringPiece device_key) {
+  const auto* aliases = Shell::Get()
+                            ->input_device_key_alias_manager()
+                            ->GetAliasesForPrimaryDeviceKey(device_key);
+  if (!aliases) {
+    return false;
+  }
+
+  for (const auto& alias : *aliases) {
+    if (base::Contains(previously_observed_devices, alias)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 StringListPrefMember* InputDeviceTracker::GetObservedDevicesForCategory(
     InputDeviceCategory category) const {
   switch (category) {
diff --git a/ash/system/input_device_settings/input_device_tracker.h b/ash/system/input_device_settings/input_device_tracker.h
index e7f128e..cf197d4 100644
--- a/ash/system/input_device_settings/input_device_tracker.h
+++ b/ash/system/input_device_settings/input_device_tracker.h
@@ -64,6 +64,10 @@
   StringListPrefMember* GetObservedDevicesForCategory(
       InputDeviceCategory category) const;
 
+  bool HasSeenPrimaryDeviceKeyAlias(
+      const std::vector<std::string>& previously_observed_devices,
+      base::StringPiece device_key);
+
   std::unique_ptr<StringListPrefMember> keyboard_observed_devices_;
   std::unique_ptr<StringListPrefMember> mouse_observed_devices_;
   std::unique_ptr<StringListPrefMember> touchpad_observed_devices_;
diff --git a/ash/system/message_center/message_center_style.h b/ash/system/message_center/message_center_style.h
index e656790..8fd1e59 100644
--- a/ash/system/message_center/message_center_style.h
+++ b/ash/system/message_center/message_center_style.h
@@ -7,23 +7,17 @@
 
 #include "ash/system/tray/tray_constants.h"
 #include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/color_palette.h"
 #include "ui/gfx/geometry/insets.h"
 
 namespace ash {
 
 namespace message_center_style {
 
-constexpr SkColor kEmptyViewColor = SkColorSetARGB(0x8A, 0x0, 0x0, 0x0);
 constexpr SkColor kScrollShadowColor = SkColorSetARGB(0x24, 0x0, 0x0, 0x0);
 
 // TODO(crbug.com/1309551): Get the colors from AshColorProvider once
 // notification supports dark/light mode.
 constexpr SkColor kSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x24);  // 14%
-constexpr SkColor kUnifiedMenuButtonColorActive =
-    SkColorSetRGB(0x25, 0x81, 0xDF);
-constexpr SkColor kInkRippleColor = SK_ColorBLACK;
-constexpr float kInkRippleOpacity = 0.06f;
 
 constexpr int kEmptyIconSize = 24;
 constexpr auto kEmptyIconPadding = gfx::Insets::TLBR(0, 0, 4, 0);
diff --git a/ash/system/power/power_prefs.cc b/ash/system/power/power_prefs.cc
index 16e1a2a4..571dd97 100644
--- a/ash/system/power/power_prefs.cc
+++ b/ash/system/power/power_prefs.cc
@@ -13,6 +13,7 @@
 #include "ash/shell.h"
 #include "ash/system/human_presence/human_presence_metrics.h"
 #include "ash/system/human_presence/lock_on_leave_controller.h"
+#include "ash/system/power/adaptive_charging_controller.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/metrics/histogram_functions.h"
@@ -433,7 +434,10 @@
         local_state_->GetBoolean(prefs::kUsbPowerShareEnabled);
   }
 
-  if (features::IsAdaptiveChargingEnabled()) {
+  if (features::IsAdaptiveChargingEnabled() &&
+      Shell::Get()
+          ->adaptive_charging_controller()
+          ->IsAdaptiveChargingSupported()) {
     values.adaptive_charging_enabled =
         prefs->GetBoolean(prefs::kPowerAdaptiveChargingEnabled);
     if (values.adaptive_charging_enabled) {
diff --git a/ash/system/power/power_prefs_unittest.cc b/ash/system/power/power_prefs_unittest.cc
index 63b151f..e96319d 100644
--- a/ash/system/power/power_prefs_unittest.cc
+++ b/ash/system/power/power_prefs_unittest.cc
@@ -223,6 +223,11 @@
     FakeHumanPresenceDBusClient::Get()->set_hps_service_is_available(true);
     NoSessionAshTestBase::SetUp();
 
+    // Sets adaptive charging hardware support.
+    power_manager::PowerSupplyProperties power_props;
+    power_props.set_adaptive_charging_supported(true);
+    power_manager_client()->UpdatePowerProperties(power_props);
+
     power_policy_controller_ = chromeos::PowerPolicyController::Get();
     power_prefs_ = ShellTestApi().power_prefs();
 
@@ -658,6 +663,19 @@
   // Should be enabled after setting the prefs to true.
   SetAdaptiveChargingPreference(true);
   EXPECT_TRUE(power_manager_client()->policy().adaptive_charging_enabled());
+
+  // Removes adaptive charging hardware support.
+  power_manager::PowerSupplyProperties power_props;
+  power_props.set_adaptive_charging_supported(false);
+  power_manager_client()->UpdatePowerProperties(power_props);
+
+  // Should be disabled in spite of the prefs setting because lack of hardware
+  // support.
+  SetAdaptiveChargingPreference(false);
+  EXPECT_FALSE(power_manager_client()->policy().adaptive_charging_enabled());
+
+  SetAdaptiveChargingPreference(true);
+  EXPECT_FALSE(power_manager_client()->policy().adaptive_charging_enabled());
 }
 
 }  // namespace ash
diff --git a/ash/system/video_conference/bubble/bubble_view_ids.h b/ash/system/video_conference/bubble/bubble_view_ids.h
index b19a4bd5..538f804 100644
--- a/ash/system/video_conference/bubble/bubble_view_ids.h
+++ b/ash/system/video_conference/bubble/bubble_view_ids.h
@@ -36,6 +36,9 @@
   // `kToggleEffectsContainer`.
   kToggleEffectsButton,
 
+  // Icon which is a child of an individual "toggle" VC effect.
+  kToggleEffectIcon,
+
   // Buttons for setting an individual value of a "set-value" VC effect,
   // children of `kSetValueEffectsContainer`. Since the number of values for a
   // given effect can't be known at compile-time, an allowable range of IDs
diff --git a/ash/system/video_conference/bubble/bubble_view_unittest.cc b/ash/system/video_conference/bubble/bubble_view_unittest.cc
index 2d234a0..768aa829 100644
--- a/ash/system/video_conference/bubble/bubble_view_unittest.cc
+++ b/ash/system/video_conference/bubble/bubble_view_unittest.cc
@@ -44,16 +44,19 @@
                             base::Unretained(this),
                             /*effect_id=*/VcEffectId::kTestEffect),
         VcEffectId::kTestEffect);
+    effect->set_container_id(kSquareCinnamonCerealViewId);
+    effect->set_dependency_flags(dependency_flags);
+
     auto state = std::make_unique<VcEffectState>(
-        &ash::kPrivacyIndicatorsCameraIcon, u"Square Cinnamon Cereal",
+        &kVideoConferenceBackgroundBlurMaximumIcon, u"Square Cinnamon Cereal",
         IDS_PRIVACY_NOTIFICATION_TITLE_CAMERA,
         base::BindRepeating(&SquareCinnamonCereal::OnEffectControlActivated,
                             base::Unretained(this),
                             /*effect_id=*/VcEffectId::kTestEffect,
                             /*value=*/absl::nullopt));
+    state->set_disabled_icon(&kVideoConferenceBackgroundBlurOffIcon);
     effect->AddState(std::move(state));
-    effect->set_container_id(kSquareCinnamonCerealViewId);
-    effect->set_dependency_flags(dependency_flags);
+
     AddEffect(std::move(effect));
   }
   SquareCinnamonCereal(const SquareCinnamonCereal&) = delete;
@@ -599,4 +602,4 @@
   }
 }
 
-}  // namespace ash::video_conference
\ No newline at end of file
+}  // namespace ash::video_conference
diff --git a/ash/system/video_conference/bubble/toggle_effects_view.cc b/ash/system/video_conference/bubble/toggle_effects_view.cc
index 8bb72ee..0535de7 100644
--- a/ash/system/video_conference/bubble/toggle_effects_view.cc
+++ b/ash/system/video_conference/bubble/toggle_effects_view.cc
@@ -50,7 +50,8 @@
   METADATA_HEADER(ButtonContainer);
 
   ButtonContainer(views::Button::PressedCallback callback,
-                  const gfx::VectorIcon* vector_icon,
+                  const gfx::VectorIcon* enabled_vector_icon,
+                  const gfx::VectorIcon* disabled_vector_icon,
                   bool toggle_state,
                   const std::u16string& label_text,
                   const int accessible_name_id,
@@ -59,7 +60,8 @@
       : callback_(callback),
         toggled_(toggle_state),
         effect_id_(effect_id),
-        vector_icon_(vector_icon) {
+        enabled_vector_icon_(enabled_vector_icon),
+        disabled_vector_icon_(disabled_vector_icon) {
     SetCallback(base::BindRepeating(&ButtonContainer::OnButtonClicked,
                                     weak_ptr_factory_.GetWeakPtr()));
     SetID(video_conference::BubbleViewID::kToggleEffectsButton);
@@ -79,8 +81,8 @@
     SetPreferredSize(gfx::Size(GetPreferredSize().width(), kButtonHeight));
 
     auto icon = std::make_unique<views::ImageView>();
-    icon->SetImage(ui::ImageModel::FromVectorIcon(
-        *vector_icon_, cros_tokens::kCrosSysOnSurface, kIconSize));
+    icon->SetID(video_conference::BubbleViewID::kToggleEffectIcon);
+    // `icon_` image set in `UpdateColorsAndBackground()`.
     icon_ = AddChildView(std::move(icon));
 
     // Label is below the button.
@@ -129,7 +131,8 @@
         toggled_ ? cros_tokens::kCrosSysSystemOnPrimaryContainer
                  : cros_tokens::kCrosSysOnSurface;
     icon_->SetImage(ui::ImageModel::FromVectorIcon(
-        *vector_icon_, foreground_color_id, kIconSize));
+        toggled_ ? *enabled_vector_icon_ : *disabled_vector_icon_,
+        foreground_color_id, kIconSize));
     label_->SetEnabledColorId(foreground_color_id);
   }
 
@@ -145,7 +148,8 @@
   views::ImageView* icon_ = nullptr;
   views::Label* label_ = nullptr;
 
-  const gfx::VectorIcon* vector_icon_;
+  const gfx::VectorIcon* enabled_vector_icon_;
+  const gfx::VectorIcon* disabled_vector_icon_;
 
   base::WeakPtrFactory<ButtonContainer> weak_ptr_factory_{this};
 };
@@ -200,9 +204,11 @@
       // `current_state` can only be a `bool` for a toggle effect.
       bool toggle_state = current_state.value() != 0;
       const VcEffectState* state = tile->GetState(/*index=*/0);
+      CHECK(state->disabled_icon())
+          << "Toggle effects must define a disabled icon.";
       row_view->AddChildView(std::make_unique<ButtonContainer>(
-          state->button_callback(), state->icon(), toggle_state,
-          state->label_text(), state->accessible_name_id(),
+          state->button_callback(), state->icon(), state->disabled_icon(),
+          toggle_state, state->label_text(), state->accessible_name_id(),
           tile->container_id(), tile->id()));
     }
 
diff --git a/ash/system/video_conference/bubble/toggle_effects_view_unittest.cc b/ash/system/video_conference/bubble/toggle_effects_view_unittest.cc
index b92f71d5..7151e6d 100644
--- a/ash/system/video_conference/bubble/toggle_effects_view_unittest.cc
+++ b/ash/system/video_conference/bubble/toggle_effects_view_unittest.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/system/video_conference/bubble/bubble_view.h"
-
+#include "ash/system/video_conference/bubble/toggle_effects_view.h"
 #include "ash/constants/ash_features.h"
 #include "ash/constants/ash_switches.h"
+#include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/style/icon_button.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/status_area_widget_test_helper.h"
+#include "ash/system/video_conference/bubble/bubble_view.h"
 #include "ash/system/video_conference/bubble/bubble_view_ids.h"
-#include "ash/system/video_conference/bubble/toggle_effects_view.h"
 #include "ash/system/video_conference/effects/fake_video_conference_effects.h"
 #include "ash/system/video_conference/effects/video_conference_tray_effects_manager_types.h"
 #include "ash/system/video_conference/fake_video_conference_tray_controller.h"
@@ -18,6 +18,7 @@
 #include "ash/test/ash_test_base.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
+#include "ui/views/controls/image_view.h"
 
 namespace ash::video_conference {
 
@@ -74,11 +75,20 @@
 
   FakeVideoConferenceTrayController* controller() { return controller_.get(); }
 
-  views::View* toggle_effect_button() {
+  // Each toggle button in the bubble view has this view ID, this just gets the
+  // first one in the view tree.
+  views::View* GetFirstToggleEffectButton() {
     return bubble_view()->GetViewByID(
         video_conference::BubbleViewID::kToggleEffectsButton);
   }
 
+  // Each toggle button icon in a toggle button has this view ID, this just gets
+  // the first one in the view tree.
+  views::ImageView* GetFirstToggleEffectIcon() {
+    return static_cast<views::ImageView*>(bubble_view()->GetViewByID(
+        video_conference::BubbleViewID::kToggleEffectIcon));
+  }
+
   ash::fake_video_conference::OfficeBunnyEffect* office_bunny() {
     return office_bunny_.get();
   }
@@ -89,24 +99,51 @@
   std::unique_ptr<ash::fake_video_conference::OfficeBunnyEffect> office_bunny_;
 };
 
+// Tests that a toggle button records histograms when clicked.
 TEST_F(ToggleEffectsViewTest, ToggleButtonClickedRecordedHistogram) {
   base::HistogramTester histogram_tester;
 
-  // Adds one toggle effect.
+  // Add one toggle effect.
   controller()->effects_manager().RegisterDelegate(office_bunny());
 
-  // Clicks to open the bubble, toggle effect button is present/visible.
+  // Click to open the bubble, toggle effect button should be visible.
   LeftClickOn(toggle_bubble_button());
-  ASSERT_TRUE(toggle_effect_button());
-  ASSERT_TRUE(toggle_effect_button()->GetVisible());
+  ASSERT_TRUE(GetFirstToggleEffectButton());
+  ASSERT_TRUE(GetFirstToggleEffectButton()->GetVisible());
 
-  // Clicks the toggle effect button, verify that metrics is recorded.
-  LeftClickOn(toggle_effect_button());
+  // Click the toggle effect button, verify that metrics is recorded.
+  LeftClickOn(GetFirstToggleEffectButton());
   histogram_tester.ExpectBucketCount(kTestEffectHistogramName, true, 1);
 
-  // Clicks again.
-  LeftClickOn(toggle_effect_button());
+  // Click again.
+  LeftClickOn(GetFirstToggleEffectButton());
   histogram_tester.ExpectBucketCount(kTestEffectHistogramName, false, 1);
 }
 
+// Tests that a toggled ToggleButton's image is updated.
+TEST_F(ToggleEffectsViewTest, ToggleUpdatesImage) {
+  // Add one toggle effect.
+  controller()->effects_manager().RegisterDelegate(office_bunny());
+  LeftClickOn(toggle_bubble_button());
+
+  // Initially the fake toggle effects icon is set to the video conference
+  // background blur off icon.
+  EXPECT_STREQ(GetFirstToggleEffectIcon()
+                   ->GetImageModel()
+                   .GetVectorIcon()
+                   .vector_icon()
+                   ->name,
+               kVideoConferenceBackgroundBlurOffIcon.name);
+
+  // Toggle the button, the icon should change to the privacy indicators camera
+  // icon.
+  LeftClickOn(GetFirstToggleEffectButton());
+  EXPECT_STREQ(GetFirstToggleEffectIcon()
+                   ->GetImageModel()
+                   .GetVectorIcon()
+                   .vector_icon()
+                   ->name,
+               ash::kPrivacyIndicatorsCameraIcon.name);
+}
+
 }  // namespace ash::video_conference
\ No newline at end of file
diff --git a/ash/system/video_conference/effects/fake_video_conference_effects.cc b/ash/system/video_conference/effects/fake_video_conference_effects.cc
index c534a29..f81076e 100644
--- a/ash/system/video_conference/effects/fake_video_conference_effects.cc
+++ b/ash/system/video_conference/effects/fake_video_conference_effects.cc
@@ -42,6 +42,7 @@
                           weak_factory_.GetWeakPtr(),
                           /*effect_id=*/VcEffectId::kTestEffect,
                           /*value=*/absl::nullopt));
+  state->set_disabled_icon(&kVideoConferenceBackgroundBlurOffIcon);
   effect->AddState(std::move(state));
   AddEffect(std::move(effect));
 }
diff --git a/ash/system/video_conference/effects/video_conference_tray_effects_manager_types.cc b/ash/system/video_conference/effects/video_conference_tray_effects_manager_types.cc
index 9a978ce..f7fa247e 100644
--- a/ash/system/video_conference/effects/video_conference_tray_effects_manager_types.cc
+++ b/ash/system/video_conference/effects/video_conference_tray_effects_manager_types.cc
@@ -9,17 +9,17 @@
 
 namespace ash {
 
-VcEffectState::VcEffectState(const gfx::VectorIcon* icon,
+VcEffectState::VcEffectState(const gfx::VectorIcon* enabled_icon,
                              const std::u16string& label_text,
                              int accessible_name_id,
                              views::Button::PressedCallback button_callback,
                              absl::optional<int> state_value)
-    : icon_(icon),
+    : enabled_icon_(enabled_icon),
       label_text_(label_text),
       accessible_name_id_(accessible_name_id),
       button_callback_(button_callback),
       state_value_(state_value) {
-  DCHECK(icon);
+  DCHECK(enabled_icon);
 }
 
 VcEffectState::~VcEffectState() = default;
diff --git a/ash/system/video_conference/effects/video_conference_tray_effects_manager_types.h b/ash/system/video_conference/effects/video_conference_tray_effects_manager_types.h
index 1ef9b00bc..7ce5f92 100644
--- a/ash/system/video_conference/effects/video_conference_tray_effects_manager_types.h
+++ b/ash/system/video_conference/effects/video_conference_tray_effects_manager_types.h
@@ -26,19 +26,21 @@
  public:
   // Arguments:
   //
-  // `icon` - The icon displayed, used for all effect types (if non-nullptr).
+  // `enabled_icon` - The icon displayed, used for all effect types (if
+  //                  non-nullptr). Used for the enabled state if this is for a
+  //                  toggle button.
   //
   // `label_text` - The text displayed.
   //
   // `accessible_name_id` - The ID of the string spoken when focused in a11y
-  // mode.
+  //                        mode.
   //
   // `button_callback` - A callback that's invoked when the user sets the effect
-  // to this state.
+  //                     to this state.
   //
   // `state` - The actual state value. Optional because only certain types of
-  // effects (e.g. set-value) actually need it.
-  VcEffectState(const gfx::VectorIcon* icon,
+  //           effects (e.g. set-value) actually need it.
+  VcEffectState(const gfx::VectorIcon* enabled_icon,
                 const std::u16string& label_text,
                 int accessible_name_id,
                 views::Button::PressedCallback button_callback,
@@ -49,8 +51,15 @@
 
   ~VcEffectState();
 
+  void set_disabled_icon(gfx::VectorIcon const* disabled_icon) {
+    disabled_icon_ = disabled_icon;
+  }
+
   absl::optional<int> state_value() const { return state_value_; }
-  const gfx::VectorIcon* icon() const { return icon_; }
+  const gfx::VectorIcon* icon() const { return enabled_icon_; }
+  const gfx::VectorIcon* disabled_icon() const {
+    return disabled_icon_.value_or(nullptr);
+  }
   const std::u16string& label_text() const { return label_text_; }
   int accessible_name_id() const { return accessible_name_id_; }
   const views::Button::PressedCallback& button_callback() const {
@@ -58,8 +67,13 @@
   }
 
  private:
-  // The icon to be displayed.
-  gfx::VectorIcon const* icon_;
+  // The icon to be displayed when enabled (for toggle effects) or at all times
+  // for set-value effects.
+  gfx::VectorIcon const* enabled_icon_;
+
+  // Icon to display when the effect is toggled off. Only used for toggle
+  // effects, which create one `VcEffectState`.
+  absl::optional<gfx::VectorIcon const*> disabled_icon_;
 
   // The text to be displayed.
   std::u16string label_text_;
diff --git a/ash/system/video_conference/video_conference_tray.cc b/ash/system/video_conference/video_conference_tray.cc
index 5f2c885..d7ca5d0 100644
--- a/ash/system/video_conference/video_conference_tray.cc
+++ b/ash/system/video_conference/video_conference_tray.cc
@@ -161,6 +161,10 @@
 VideoConferenceTray::VideoConferenceTray(Shelf* shelf)
     : TrayBackgroundView(shelf,
                          TrayBackgroundViewCatalogName::kVideoConferenceTray) {
+  // If the user pressed the body of the tray, just toggle the bubble.
+  SetPressedCallback(base::BindRepeating(&VideoConferenceTray::ToggleBubble,
+                                         weak_ptr_factory_.GetWeakPtr()));
+
   tray_container()->SetSpacingBetweenChildren(kTrayButtonsSpacing);
 
   audio_icon_ = tray_container()->AddChildView(
diff --git a/ash/system/video_conference/video_conference_tray_unittest.cc b/ash/system/video_conference/video_conference_tray_unittest.cc
index 5b4bb32..d8322c0 100644
--- a/ash/system/video_conference/video_conference_tray_unittest.cc
+++ b/ash/system/video_conference/video_conference_tray_unittest.cc
@@ -151,6 +151,25 @@
   EXPECT_FALSE(toggle_bubble_button()->toggled());
 }
 
+// Tests that tapping directly on the VideoConferenceTray (not the child toggle
+// buttons) toggles the bubble.
+TEST_F(VideoConferenceTrayTest, ClickTrayBackgroundViewTogglesBubble) {
+  // Tap the body of the TrayBackgroundView, missing all toggle buttons. The
+  // bubble should show up.
+  video_conference_tray()->PerformAction(ui::GestureEvent(
+      0, 0, 0, base::TimeTicks(), ui::GestureEventDetails(ui::ET_GESTURE_TAP)));
+
+  EXPECT_TRUE(video_conference_tray()->GetBubbleView());
+  EXPECT_TRUE(toggle_bubble_button()->toggled());
+
+  // Tap the body again, it should hide the bubble.
+  video_conference_tray()->PerformAction(ui::GestureEvent(
+      0, 0, 0, base::TimeTicks(), ui::GestureEventDetails(ui::ET_GESTURE_TAP)));
+
+  EXPECT_FALSE(video_conference_tray()->GetBubbleView());
+  EXPECT_FALSE(toggle_bubble_button()->toggled());
+}
+
 TEST_F(VideoConferenceTrayTest, ToggleBubbleButtonRotation) {
   SetTrayAndButtonsVisible();
 
diff --git a/ash/test/pixel/ash_pixel_differ.cc b/ash/test/pixel/ash_pixel_differ.cc
index f9b30f8..6069b010 100644
--- a/ash/test/pixel/ash_pixel_differ.cc
+++ b/ash/test/pixel/ash_pixel_differ.cc
@@ -11,10 +11,31 @@
 #include "base/strings/strcat.h"
 
 namespace ash {
+namespace {
+
+// The names of the pixel tests that use the "positive if only" algorithm.
+// This list should be removed when all existing tests are migrated.
+const std::array<std::string, 1> kMigratedTests = {{"DemoAshPixelDiffTest"}};
+
+// Returns true if the test specified by `screenshot_prefix` should use the
+// "positive if only" algorithm.
+bool ShouldUsePositiveIfOnlyAlgorithm(const std::string& screenshot_prefix) {
+  for (const auto& migrated_test : kMigratedTests) {
+    if (screenshot_prefix.find(migrated_test) != screenshot_prefix.npos) {
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace
 
 AshPixelDiffer::AshPixelDiffer(const std::string& screenshot_prefix,
                                const std::string& corpus) {
   pixel_diff_.Init(screenshot_prefix, corpus);
+  if (ShouldUsePositiveIfOnlyAlgorithm(screenshot_prefix)) {
+    positive_if_only_algorithm_.emplace();
+  }
 }
 
 AshPixelDiffer::~AshPixelDiffer() = default;
@@ -36,7 +57,8 @@
       std::numeric_limits<float>::epsilon()) {
     return pixel_diff_.CompareNativeWindowScreenshotInRects(
         full_name, primary_root_window, primary_root_window->bounds(),
-        /*algorithm=*/nullptr, rects_in_screen);
+        positive_if_only_algorithm_ ? &*positive_if_only_algorithm_ : nullptr,
+        rects_in_screen);
   }
 
   // Convert rects from screen coordinates to pixel coordinates.
@@ -53,7 +75,8 @@
 
   return pixel_diff_.CompareNativeWindowScreenshotInRects(
       full_name, primary_root_window, primary_root_window->bounds(),
-      /*algorithm=*/nullptr, rects_in_pixel);
+      positive_if_only_algorithm_ ? &*positive_if_only_algorithm_ : nullptr,
+      rects_in_pixel);
 }
 
 }  // namespace ash
diff --git a/ash/test/pixel/ash_pixel_differ.h b/ash/test/pixel/ash_pixel_differ.h
index 0c217e5c..370d7cc 100644
--- a/ash/test/pixel/ash_pixel_differ.h
+++ b/ash/test/pixel/ash_pixel_differ.h
@@ -7,6 +7,8 @@
 
 #include "ash/test/pixel/ash_pixel_diff_util.h"
 #include "base/check_op.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/base/test/skia_gold_matching_algorithm.h"
 #include "ui/views/test/view_skia_gold_pixel_diff.h"
 
 namespace ash {
@@ -74,6 +76,11 @@
       size_t revision_number,
       const std::vector<gfx::Rect>& rects_in_screen);
 
+  // Set only when the "positive if only" algorithm should be used instead of
+  // the exact matching algorithm.
+  absl::optional<ui::test::PositiveIfOnlyImageAlgorithm>
+      positive_if_only_algorithm_;
+
   // Used to take screenshots and upload images to the Skia Gold server to
   // perform pixel comparison.
   // NOTE: the user of `ViewSkiaGoldPixelDiff` has the duty to initialize
diff --git a/ash/test/pixel/demo_ash_pixel_diff_test.cc b/ash/test/pixel/demo_ash_pixel_diff_test.cc
index a897037..c536b9f 100644
--- a/ash/test/pixel/demo_ash_pixel_diff_test.cc
+++ b/ash/test/pixel/demo_ash_pixel_diff_test.cc
@@ -69,7 +69,7 @@
 
   EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
       "check_widgets",
-      /*revision_number=*/0, widget1.get(), widget2.get(), widget3.get(),
+      /*revision_number=*/1, widget1.get(), widget2.get(), widget3.get(),
       widget4.get()));
 }
 
diff --git a/ash/webui/common/resources/BUILD.gn b/ash/webui/common/resources/BUILD.gn
index bff66401..246cf61 100644
--- a/ash/webui/common/resources/BUILD.gn
+++ b/ash/webui/common/resources/BUILD.gn
@@ -211,6 +211,7 @@
 }
 
 non_web_component_files_ts = [
+  "connectivity/mojo_connectivity_provider.ts",
   "hotspot/cros_hotspot_config.ts",
   "hotspot/fake_hotspot_config.ts",
   "typescript_utils/strict_query.ts",
@@ -222,7 +223,10 @@
   out_folder = preprocessed_dir
 }
 
-mojo_files_ts = [ "hotspot/cros_hotspot_config.mojom-webui.ts" ]
+mojo_files_ts = [
+  "connectivity/passpoint.mojom-webui.ts",
+  "hotspot/cros_hotspot_config.mojom-webui.ts",
+]
 
 ts_library("build_ts") {
   root_dir = preprocessed_dir
@@ -238,6 +242,7 @@
     ":generate_definitions",
     ":preprocess",
     ":preprocess_ts",
+    "connectivity:copy_mojo_files",
     "hotspot:copy_mojo_files",
   ]
 }
diff --git a/ash/webui/common/resources/connectivity/BUILD.gn b/ash/webui/common/resources/connectivity/BUILD.gn
new file mode 100644
index 0000000..292e145
--- /dev/null
+++ b/ash/webui/common/resources/connectivity/BUILD.gn
@@ -0,0 +1,15 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD - style license that can be
+# found in the LICENSE file.
+
+import("//build/config/chromeos/ui_mode.gni")
+
+assert(is_chromeos_ash, "Connectivity services are Chrome OS only.")
+
+copy("copy_mojo_files") {
+  deps = [
+    "//chromeos/ash/services/connectivity/public/mojom:mojom_ts__generator",
+  ]
+  sources = [ "$root_gen_dir/chromeos/ash/services/connectivity/public/mojom/passpoint.mojom-webui.ts" ]
+  outputs = [ "$root_gen_dir/ash/webui/common/resources/preprocessed/connectivity/{{source_file_part}}" ]
+}
diff --git a/ash/webui/common/resources/connectivity/mojo_connectivity_provider.ts b/ash/webui/common/resources/connectivity/mojo_connectivity_provider.ts
new file mode 100644
index 0000000..276ed16
--- /dev/null
+++ b/ash/webui/common/resources/connectivity/mojo_connectivity_provider.ts
@@ -0,0 +1,33 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {PasspointService, PasspointServiceInterface} from './passpoint.mojom-webui.js';
+
+/**
+ * @fileoverview Wrapper for connectivity services that provides the ability to
+ * inject a fake implementation for tests.
+ */
+
+export class MojoConnectivityProvider {
+  private static instance: MojoConnectivityProvider|null = null;
+  private passpointService: PasspointServiceInterface|null = null;
+
+  getPasspointService(): PasspointServiceInterface {
+    if (!this.passpointService) {
+      this.passpointService = PasspointService.getRemote();
+    }
+    return this.passpointService;
+  }
+
+  setPasspointServiceForTest(service: PasspointServiceInterface): void {
+    this.passpointService = service;
+  }
+
+  static getInstance(): MojoConnectivityProvider {
+    if (!this.instance) {
+      this.instance = new MojoConnectivityProvider();
+    }
+    return this.instance;
+  }
+}
diff --git a/ash/webui/personalization_app/mojom/personalization_app.mojom b/ash/webui/personalization_app/mojom/personalization_app.mojom
index fa61d4c..8cb4b54 100644
--- a/ash/webui/personalization_app/mojom/personalization_app.mojom
+++ b/ash/webui/personalization_app/mojom/personalization_app.mojom
@@ -347,6 +347,7 @@
 };
 
 // Color scheme options used to generate the system UI's color palette.
+// These options are based off the user's wallpaper.
 enum ColorScheme {
   kStatic = 0,
   kTonalSpot = 1,
@@ -355,6 +356,21 @@
   kVibrant = 4,
 };
 
+// Static color options used to generate the system UI's color palette. These
+// options are not based off the user's wallpaper.
+enum StaticColor {
+  kUnknown = 0,
+  kGoogleBlue = 1,
+  kLightPink = 2,
+  kDarkGreen = 3,
+  kLightPurple = 4,
+};
+
+const uint32 kStaticColorGoogleBlue = 0x4285F4;
+const uint32 kStaticColorLightPink = 0xFFD6D6;
+const uint32 kStaticColorDarkGreen = 0x485045;
+const uint32 kStaticColorLightPurple = 0xCBBFFF;
+
 // Samples of a color scheme for the tri-color scheme preview.
 struct SampleColorScheme {
   ColorScheme scheme;
@@ -639,6 +655,11 @@
   // Sets the ambient animation theme.
   SetAnimationTheme(AnimationTheme animation_theme);
 
+  // Sets the screen saver running duration before put into sleep.
+  //
+  // SPECIAL NOTE: |minutes| with value 0 means forever.
+  SetScreenSaverDuration(int32 minutes);
+
   // Sets the ambient mode topic source.
   //
   // SPECIAL NOTE: If |SetAnimationTheme(kVideo)| is called, the provider's
diff --git a/ash/webui/personalization_app/resources/js/personalization_metrics_logger.ts b/ash/webui/personalization_app/resources/js/personalization_metrics_logger.ts
index c68c77d5..0561b68 100644
--- a/ash/webui/personalization_app/resources/js/personalization_metrics_logger.ts
+++ b/ash/webui/personalization_app/resources/js/personalization_metrics_logger.ts
@@ -4,6 +4,8 @@
 
 import {assert} from 'chrome://resources/js/assert_ts.js';
 
+import {ColorScheme, StaticColor} from '../personalization_app.mojom-webui.js';
+
 import {Paths} from './personalization_router_element.js';
 
 // Numerical values are used for metrics; do not change or reuse values. These
@@ -27,6 +29,10 @@
   AMBIENT_OPTIN = 'Ash.Personalization.AmbientMode.OptIn',
   AMBIENT_PERFORMANCE_GOOGLE_PHOTOS_PREVIEWS =
       'Ash.Personalization.Ambient.GooglePhotosPreviewsLoadTime',
+  DYNAMIC_COLOR_COLOR_SCHEME_BUTTON =
+      'Ash.Personalization.DynamicColor.ColorSchemeButton',
+  DYNAMIC_COLOR_STATIC_COLOR_BUTTON =
+      'Ash.Personalization.DynamicColor.StaticColorButton',
   DYNAMIC_COLOR_TOGGLE_BUTTON = 'Ash.Personalization.DynamicColor.ToggleButton',
   KEYBOARD_BACKLIGHT_OPEN_ZONE_CUSTOMIZATION =
       'Ash.Personalization.KeyboardBacklight.OpenZoneCustomization',
@@ -82,3 +88,15 @@
   chrome.metricsPrivate.recordBoolean(
       HistogramName.DYNAMIC_COLOR_TOGGLE_BUTTON, enabled);
 }
+
+export function logDynamicColorStaticColorButtonClick(color: StaticColor) {
+  chrome.metricsPrivate.recordEnumerationValue(
+      HistogramName.DYNAMIC_COLOR_STATIC_COLOR_BUTTON, color,
+      StaticColor.MAX_VALUE);
+}
+
+export function logDynamicColorColorSchemeButtonClick(color: ColorScheme) {
+  chrome.metricsPrivate.recordEnumerationValue(
+      HistogramName.DYNAMIC_COLOR_COLOR_SCHEME_BUTTON, color,
+      ColorScheme.MAX_VALUE);
+}
diff --git a/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.html b/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.html
index 7090445..e7a332b 100644
--- a/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.html
+++ b/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.html
@@ -120,13 +120,12 @@
       hidden$="[[automaticSeedColorEnabled]]">
     <template is="dom-repeat" items="[[staticColors_]]" as="staticColor">
       <cr-button
-          tabindex$="[[getStaticColorTabIndex_(staticColor)]]"
+          tabindex$="[[getStaticColorTabIndex_(staticColor.hexVal)]]"
           on-click="onClickStaticColorButton_"
-          aria-checked$="[[getStaticColorAriaChecked_(staticColor, staticColorSelected_)]]"
-          data-static-color$="[[staticColor]]">
+          aria-checked$="[[getStaticColorAriaChecked_(staticColor.hexVal, staticColorSelected_)]]">
         <div class="container">
           <svg>
-            <circle style$="fill: [[staticColor]]" cx="24" cy="24" r="24"></circle>
+            <circle style$="fill: [[staticColor.hexVal]]" cx="24" cy="24" r="24"></circle>
           </svg>
           <iron-icon icon="personalization:circle_checkmark"></iron-icon>
         </div>
diff --git a/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.ts b/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.ts
index 5100bfa..91769bd 100644
--- a/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.ts
+++ b/ash/webui/personalization_app/resources/js/theme/dynamic_color_element.ts
@@ -19,8 +19,8 @@
 import {IronA11yKeysElement} from 'chrome://resources/polymer/v3_0/iron-a11y-keys/iron-a11y-keys.js';
 import {IronSelectorElement} from 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
 
-import {ColorScheme, SampleColorScheme} from '../../personalization_app.mojom-webui.js';
-import {logDynamicColorToggleButtonClick} from '../personalization_metrics_logger.js';
+import {ColorScheme, SampleColorScheme, STATIC_COLOR_DARK_GREEN, STATIC_COLOR_GOOGLE_BLUE, STATIC_COLOR_LIGHT_PINK, STATIC_COLOR_LIGHT_PURPLE, StaticColor} from '../../personalization_app.mojom-webui.js';
+import {logDynamicColorColorSchemeButtonClick, logDynamicColorStaticColorButtonClick, logDynamicColorToggleButtonClick} from '../personalization_metrics_logger.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
 import {convertToRgbHexStr} from '../utils.js';
 
@@ -39,6 +39,15 @@
   };
 }
 
+export interface StaticColorInfo {
+  hexVal: string;
+  enumVal: StaticColor;
+}
+
+interface OnStaticColorSelectedEvent {
+  model: {staticColor: StaticColorInfo};
+}
+
 export class DynamicColorElement extends WithPersonalizationStore {
   static get is() {
     return 'dynamic-color';
@@ -61,13 +70,7 @@
       colorSchemeSelected_: Object,
       staticColors_: {
         type: Object,
-        readOnly: true,
-        value: [
-          '#4285f4',
-          '#ffd6d6',
-          '#485045',
-          '#cbbfff',
-        ],
+        computed: 'computePresetStaticColors_()',
       },
       sampleColorSchemes_: {
         type: Array,
@@ -91,7 +94,7 @@
   private previousColorSchemeSelected_: ColorScheme|null;
   private staticColorSelected_: SkColor|null;
   private colorSchemeSelected_: ColorScheme|null;
-  private staticColors_: string[];
+  private staticColors_: StaticColorInfo[];
   private sampleColorSchemes_: SampleColorScheme[];
   private colorSchemeHighlightedButton_: CrButtonElement;
   private staticColorHighlightedButton_: CrButtonElement;
@@ -115,17 +118,40 @@
     initializeDynamicColorData(getThemeProvider(), this.getStore());
   }
 
+  private computePresetStaticColors_() {
+    return [
+      {
+        hexVal: convertToRgbHexStr(STATIC_COLOR_GOOGLE_BLUE),
+        enumVal: StaticColor.kGoogleBlue,
+      },
+      {
+        hexVal: convertToRgbHexStr(STATIC_COLOR_LIGHT_PINK),
+        enumVal: StaticColor.kLightPink,
+      },
+      {
+        hexVal: convertToRgbHexStr(STATIC_COLOR_DARK_GREEN),
+        enumVal: StaticColor.kDarkGreen,
+      },
+      {
+        hexVal: convertToRgbHexStr(STATIC_COLOR_LIGHT_PURPLE),
+        enumVal: StaticColor.kLightPurple,
+      },
+    ];
+  }
+
   private onClickColorSchemeButton_(event: Event) {
     const eventTarget = event.currentTarget as HTMLElement;
     const colorScheme = Number(eventTarget.dataset['colorSchemeId']);
+    logDynamicColorColorSchemeButtonClick(colorScheme);
     setColorSchemePref(colorScheme, getThemeProvider(), this.getStore());
   }
 
-  private onClickStaticColorButton_(event: Event) {
-    const eventTarget = event.currentTarget as HTMLElement;
-    const staticColorHexStr = String(eventTarget.dataset['staticColor']);
-    const staticColor = hexColorToSkColor(staticColorHexStr);
-    setStaticColorPref(staticColor, getThemeProvider(), this.getStore());
+  private onClickStaticColorButton_(event: OnStaticColorSelectedEvent) {
+    const staticColorInfo = event.model.staticColor;
+    logDynamicColorStaticColorButtonClick(staticColorInfo.enumVal);
+    setStaticColorPref(
+        hexColorToSkColor(staticColorInfo.hexVal), getThemeProvider(),
+        this.getStore());
   }
 
   private onToggleChanged_() {
diff --git a/ash/webui/personalization_app/test/fake_personalization_app_ambient_provider.h b/ash/webui/personalization_app/test/fake_personalization_app_ambient_provider.h
index 6c1a52a..0180453 100644
--- a/ash/webui/personalization_app/test/fake_personalization_app_ambient_provider.h
+++ b/ash/webui/personalization_app/test/fake_personalization_app_ambient_provider.h
@@ -45,6 +45,7 @@
           observer) override {}
   void SetAmbientModeEnabled(bool enabled) override {}
   void SetAnimationTheme(ash::AmbientTheme animation_theme) override {}
+  void SetScreenSaverDuration(int) override {}
   void SetTopicSource(ash::AmbientModeTopicSource topic_source) override {}
   void SetTemperatureUnit(
       ash::AmbientModeTemperatureUnit temperature_unit) override {}
diff --git a/ash/webui/personalization_app/test/personalization_app_mojom_banned_browsertest_fixture.cc b/ash/webui/personalization_app/test/personalization_app_mojom_banned_browsertest_fixture.cc
index cc03441..b930e5556 100644
--- a/ash/webui/personalization_app/test/personalization_app_mojom_banned_browsertest_fixture.cc
+++ b/ash/webui/personalization_app/test/personalization_app_mojom_banned_browsertest_fixture.cc
@@ -41,6 +41,7 @@
               SetAnimationTheme,
               (ash::AmbientTheme animation_theme),
               (override));
+  MOCK_METHOD(void, SetScreenSaverDuration, (int minutes), (override));
   MOCK_METHOD(void,
               SetTopicSource,
               (ash::AmbientModeTopicSource topic_source),
diff --git a/ash/webui/shortcut_customization_ui/resources/common/icons.html b/ash/webui/shortcut_customization_ui/resources/common/icons.html
index 41ecb4a..44de08b 100644
--- a/ash/webui/shortcut_customization_ui/resources/common/icons.html
+++ b/ash/webui/shortcut_customization_ui/resources/common/icons.html
@@ -90,8 +90,16 @@
         <path fill-rule="evenodd" d="M9.992 2C5.576 2 2 5.584 2 10C2 14.416 5.576 18 9.992 18C14.416 18 18 14.416 18 10C18 5.584 14.416 2 9.992 2ZM10 16.5C6.40875 16.5 3.5 13.5912 3.5 10C3.5 6.40875 6.40875 3.5 10 3.5C13.5912 3.5 16.5 6.40875 16.5 10C16.5 13.5912 13.5912 16.5 10 16.5ZM12.8 9.20005C13.464 9.20005 14 8.66405 14 8.00005C14 7.33605 13.464 6.80005 12.8 6.80005C12.136 6.80005 11.6 7.33605 11.6 8.00005C11.6 8.66405 12.136 9.20005 12.8 9.20005ZM7.2 9.20005C7.864 9.20005 8.4 8.66405 8.4 8.00005C8.4 7.33605 7.864 6.80005 7.2 6.80005C6.536 6.80005 6 7.33605 6 8.00005C6 8.66405 6.536 9.20005 7.2 9.20005ZM9.99999 14C11.864 14 13.448 12.7486 14.088 11H5.91199C6.55199 12.7486 8.13599 14 9.99999 14Z"></path>
       </g>
       <g id="dictation-toggle" viewBox="0 0 20 20">
-        <path fill-rule="evenodd" clip-rule="evenodd" d="M12.5715 4.5L12.5629 9.5C12.5629 9.95509 12.4395 10.3813 12.2233 10.7484L12 10.5251V10.5273L9.02316 7.54469L9.02314 7.54828L7.4286 5.95375V4.5C7.4286 3.11667 8.57717 2 10 2C11.4229 2 12.5715 3.11667 12.5715 4.5ZM2.23742 3.23744L1 4.47486L10.3834 13.8582C10.2564 13.8685 10.1285 13.8737 10 13.8737C7.6343 13.8737 5.45715 12.1053 5.45715 9.57898H4.00001C4.00001 12.459 6.33144 14.8253 9.14287 15.2379V18H10.8572V15.2379C11.1112 15.2014 11.3614 15.1488 11.6063 15.0811L15.5251 19L16.7626 17.7626L2.23742 3.23744ZM14.6382 13.1633L13.6393 12.1645C14.2003 11.4639 14.5429 10.5811 14.5429 9.57898H16C16 10.9374 15.4813 12.1835 14.6382 13.1633Z"></path>
-      </g>
+        <path
+          d="M8.02018 10.8332C7.13129 10.8332 6.38129 10.5276 5.77018 9.9165C5.15907 9.30539 4.85352 8.56234 4.85352 7.68734C4.85352 6.79845 5.15907 6.0415 5.77018 5.4165C6.38129 4.7915 7.13129 4.479 8.02018 4.479C8.89518 4.479 9.63824 4.7915 10.2493 5.4165C10.8743 6.0415 11.1868 6.79845 11.1868 7.68734C11.1868 8.56234 10.8813 9.30539 10.2702 9.9165C9.65907 10.5276 8.90907 10.8332 8.02018 10.8332ZM1.85352 17.1665V14.9582C1.85352 14.5832 1.95768 14.2429 2.16602 13.9373C2.37435 13.6318 2.62435 13.3887 2.91602 13.2082C3.6799 12.7498 4.49935 12.4026 5.37435 12.1665C6.24935 11.9304 7.13129 11.8123 8.02018 11.8123C8.90907 11.8123 9.78407 11.9304 10.6452 12.1665C11.5202 12.4026 12.3396 12.7498 13.1035 13.2082C13.3813 13.3887 13.6313 13.6318 13.8535 13.9373C14.0757 14.2429 14.1868 14.5832 14.1868 14.9582V17.1665H1.85352ZM3.58268 15.4373H12.4577V14.979C12.4577 14.9234 12.4368 14.8748 12.3952 14.8332C12.3535 14.7776 12.298 14.729 12.2285 14.6873C11.5757 14.2846 10.8882 13.9929 10.166 13.8123C9.45768 13.6318 8.7424 13.5415 8.02018 13.5415C7.29796 13.5415 6.57574 13.6318 5.85352 13.8123C5.14518 13.9929 4.46463 14.2846 3.81185 14.6873C3.7424 14.729 3.68685 14.7776 3.64518 14.8332C3.60352 14.8748 3.58268 14.9234 3.58268 14.979V15.4373ZM8.02018 9.104C8.42296 9.104 8.76324 8.96512 9.04102 8.68734C9.31879 8.40956 9.45768 8.06928 9.45768 7.6665C9.45768 7.27761 9.31185 6.93734 9.02018 6.64567C8.7424 6.354 8.40907 6.20817 8.02018 6.20817C7.61741 6.20817 7.27713 6.354 6.99935 6.64567C6.72157 6.93734 6.58268 7.27761 6.58268 7.6665C6.58268 8.06928 6.72157 8.40956 6.99935 8.68734C7.27713 8.96512 7.61741 9.104 8.02018 9.104Z">
+        </path>
+        <path
+          d="M15.1875 11.021L16.3542 12.1877C17.1458 11.3821 17.7361 10.4863 18.125 9.50016C18.5 8.51405 18.6875 7.50016 18.6875 6.4585C18.6875 5.41683 18.5 4.40294 18.125 3.41683C17.7361 2.43072 17.1389 1.52794 16.3333 0.708496L15.1667 1.87516C15.7778 2.51405 16.2431 3.23627 16.5625 4.04183C16.8681 4.8335 17.0208 5.63905 17.0208 6.4585C17.0208 7.29183 16.8681 8.10433 16.5625 8.896C16.2569 9.68766 15.7986 10.396 15.1875 11.021Z">
+        </path>
+        <path
+          d="M12.9792 8.8335L14.1458 10.0002C14.6319 9.51405 14.9931 8.96544 15.2292 8.35433C15.4653 7.74322 15.5833 7.11127 15.5833 6.4585C15.5833 5.81961 15.4653 5.18766 15.2292 4.56266C14.9792 3.93766 14.6181 3.38211 14.1458 2.896L12.9792 4.06266C13.2847 4.40989 13.5208 4.79183 13.6875 5.2085C13.8542 5.62516 13.9375 6.04183 13.9375 6.4585C13.9375 6.88905 13.8611 7.31266 13.7083 7.72933C13.5417 8.146 13.2986 8.51405 12.9792 8.8335Z">
+        </path>
+        </g>
       <g id="settings" viewBox="0 0 20 20">
         <path fill-rule="evenodd" clip-rule="evenodd" d="M11.4781 18H8.51899C7.92717 18 7.43132 17.5783 7.35934 17.0083L7.14341 15.5325C6.92747 15.4231 6.71954 15.306 6.5116 15.1733L5.07204 15.7355C4.51221 15.9385 3.89639 15.7121 3.62448 15.2279L2.16092 12.7526C1.881 12.2372 2.00097 11.6281 2.44883 11.2845L3.67246 10.3553C3.66446 10.2382 3.65647 10.121 3.65647 9.9961C3.65647 9.87897 3.66446 9.75403 3.67246 9.6369L2.45683 8.70766C1.98497 8.35627 1.86501 7.72377 2.16092 7.23963L3.64047 4.74866C3.91239 4.26452 4.5282 4.04588 5.07204 4.25671L6.5196 4.82674C6.72753 4.694 6.93547 4.57687 7.14341 4.46755L7.35934 2.97609C7.43132 2.42948 7.92717 2 8.51099 2H11.4701C12.0619 2 12.5578 2.42167 12.6297 2.9917L12.8457 4.46755C13.0616 4.57687 13.2695 4.694 13.4775 4.82674L14.917 4.26452C15.4849 4.06149 16.1007 4.28795 16.3726 4.77208L17.8442 7.25525C18.1321 7.77062 18.0041 8.3797 17.5562 8.72328L16.3406 9.65251C16.3486 9.76964 16.3566 9.88677 16.3566 10.0117C16.3566 10.1367 16.3486 10.2538 16.3406 10.3709L17.5562 11.3001C18.0041 11.6515 18.1321 12.2606 17.8522 12.7526L16.3646 15.267C16.0927 15.7511 15.4769 15.9697 14.925 15.7589L13.4855 15.1967C13.2775 15.3294 13.0696 15.4466 12.8617 15.5559L12.6457 17.0473C12.5658 17.5783 12.0699 18 11.4781 18ZM8.94703 16H11.0606L11.344 14.1455L11.7498 13.9855C12.0868 13.8545 12.4237 13.6655 12.776 13.4182L13.1206 13.1709L14.9432 13.8691L16 12.1236L14.4454 10.9745L14.499 10.5673C14.522 10.3782 14.545 10.1964 14.545 10C14.545 9.80364 14.522 9.61455 14.499 9.43273L14.4454 9.02545L16 7.87636L14.9355 6.13091L13.1053 6.82909L12.7607 6.57455C12.4391 6.34182 12.0944 6.15273 11.7422 6.01455L11.344 5.85455L11.0606 4H8.94703L8.66369 5.85455L8.25782 6.00727C7.92087 6.14545 7.58392 6.32727 7.23165 6.58182L6.88705 6.82182L5.06445 6.13091L4 7.86909L5.55456 9.01818L5.50096 9.42545C5.47798 9.61455 5.45501 9.81091 5.45501 10C5.45501 10.1891 5.47033 10.3855 5.50096 10.5673L5.55456 10.9745L4 12.1236L5.0568 13.8691L6.88705 13.1709L7.23165 13.4255C7.56094 13.6655 7.89024 13.8473 8.25016 13.9855L8.65603 14.1455L8.94703 16ZM10 12.5C11.3807 12.5 12.5 11.3807 12.5 10C12.5 8.61929 11.3807 7.5 10 7.5C8.61929 7.5 7.5 8.61929 7.5 10C7.5 11.3807 8.61929 12.5 10 12.5Z"></path>
       </g>
@@ -117,13 +125,17 @@
       <g id="calculator" viewBox="0 0 20 20">
         <path d="M7.36338 14.2592H8.44507V12.6366H10.0676V11.5549H8.44507V9.93239H7.36338V11.5549H5.74085V12.6366H7.36338V14.2592ZM11.0141 13.4479H14.2592V12.3662H11.0141V13.4479ZM11.0141 11.8254H14.2592V10.7437H11.0141V11.8254ZM13.7859 9.57183L14.5521 8.80563L13.4028 7.65634L14.5521 6.50704L13.7859 5.74084L12.6366 6.89014L11.4873 5.74084L10.7211 6.50704L11.8704 7.6338L10.7211 8.7831L11.4873 9.5493L12.6366 8.42254L13.7859 9.57183ZM5.74085 8.12958H8.98592V7.04789H5.74085V8.12958ZM4.20845 18C3.59249 18 3.06667 17.7897 2.63099 17.369C2.21033 16.9333 2 16.4075 2 15.7915V4.20845C2 3.59249 2.21033 3.07418 2.63099 2.65352C3.06667 2.21784 3.59249 2 4.20845 2H15.7916C16.4075 2 16.9258 2.21784 17.3465 2.65352C17.7822 3.07418 18 3.59249 18 4.20845V15.7915C18 16.4075 17.7822 16.9333 17.3465 17.369C16.9258 17.7897 16.4075 18 15.7916 18H4.20845ZM4.20845 15.7915H15.7916V4.20845H4.20845V15.7915ZM4.20845 4.20845V15.7915V4.20845Z"></path>
       </g>
-      <g id="open-launcher" viewBox="0 0 20 20">
-        <path d="M15 10C16.1 10 17 9.1 17 8C17 6.9 16.1 6 15 6C13.9 6 13 6.9 13 8C13 9.1 13.9 10 15 10Z"></path>
-        <path d="M7 8C7 9.1 6.1 10 5 10C3.9 10 3 9.1 3 8C3 6.9 3.9 6 5 6C6.1 6 7 6.9 7 8Z"></path>
-        <path d="M10 10C11.1 10 12 9.1 12 8C12 6.9 11.1 6 10 6C8.9 6 8 6.9 8 8C8 9.1 8.9 10 10 10Z"></path>
-        <path d="M17 13C17 14.1 16.1 15 15 15C13.9 15 13 14.1 13 13C13 11.9 13.9 11 15 11C16.1 11 17 11.9 17 13Z"></path>
-        <path d="M5 15C6.1 15 7 14.1 7 13C7 11.9 6.1 11 5 11C3.9 11 3 11.9 3 13C3 14.1 3.9 15 5 15Z"></path>
-        <path d="M12 13C12 14.1 11.1 15 10 15C8.9 15 8 14.1 8 13C8 11.9 8.9 11 10 11C11.1 11 12 11.9 12 13Z"></path>
+      <g id="open-launcher" viewBox="0 0 20 20" fill="none">
+        <!-- Include a <style> to set the stroke color dynamically based on color scheme (light or dark mode) -->
+        <style>
+          path {
+            stroke: var(--cros-text-color-secondary);
+            stroke-width: 1.5;
+          }
+        </style>
+        <path
+          d="M1.75 3.75H5.41427V7.41427H1.75V3.75ZM8.16787 3.75H11.8321V7.41427H8.16787V3.75ZM14.5857 3.75H18.25V7.41427H14.5857V3.75ZM14.5857 12.5857H18.25V16.25H14.5857V12.5857ZM8.16787 12.5857H11.8321V16.25H8.16787V12.5857ZM1.75 12.5857H5.41427V16.25H1.75V12.5857Z">
+        </path>
       </g>
       <g id="menu" viewBox="0 0 20 20">
         <path
diff --git a/ash/webui/shortcut_customization_ui/resources/js/accelerator_view.ts b/ash/webui/shortcut_customization_ui/resources/js/accelerator_view.ts
index 515d00a3..e0d56a4 100644
--- a/ash/webui/shortcut_customization_ui/resources/js/accelerator_view.ts
+++ b/ash/webui/shortcut_customization_ui/resources/js/accelerator_view.ts
@@ -6,7 +6,7 @@
 import 'chrome://resources/cr_elements/cr_input/cr_input.js';
 
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
-import {assertNotReached} from 'chrome://resources/js/assert_ts.js';
+import {assert, assertNotReached} from 'chrome://resources/js/assert_ts.js';
 import {String16} from 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-webui.js';
 import {PolymerElementProperties} from 'chrome://resources/polymer/v3_0/polymer/interfaces.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -252,11 +252,20 @@
     this.statusMessage = '';
     this.hasError = false;
 
+    let result: {result: AcceleratorResultData};
+    assert(this.viewState !== ViewState.VIEW);
+
     if (this.viewState === ViewState.ADD) {
-      const result = await this.shortcutProvider.addAccelerator(
+      result = await this.shortcutProvider.addAccelerator(
           this.source, this.action, getAccelerator(pendingAccelInfo));
-      this.handleAcceleratorResultData(result.result);
     }
+
+    if (this.viewState === ViewState.EDIT) {
+      result = await this.shortcutProvider.replaceAccelerator(
+          this.source, this.action, getAccelerator(this.acceleratorInfo),
+          getAccelerator(pendingAccelInfo));
+    }
+    this.handleAcceleratorResultData(result!.result);
   }
 
   private handleAcceleratorResultData(result: AcceleratorResultData): void {
@@ -407,41 +416,6 @@
     return this.viewState !== ViewState.VIEW;
   }
 
-  private requestUpdateAccelerator(newAcceleratorInfo: StandardAcceleratorInfo):
-      void {
-    if (this.viewState === ViewState.EDIT) {
-      this.shortcutProvider
-          .replaceAccelerator(
-              this.source, this.action, (getAccelerator(this.acceleratorInfo)),
-              (getAccelerator(newAcceleratorInfo)))
-          .then(({result}) => {
-            // TODO(jimmyxgong): Handle other error cases.
-            if (result.result === AcceleratorConfigResult.kSuccess) {
-              this.lookupManager.replaceAccelerator(
-                  this.source, this.action,
-                  this.acceleratorInfo.layoutProperties.standardAccelerator
-                      .accelerator,
-                  newAcceleratorInfo);
-              this.fireUpdateEvent();
-            }
-          });
-    }
-
-    if (this.viewState === ViewState.ADD) {
-      this.shortcutProvider
-          .addAccelerator(
-              this.source, this.action, getAccelerator(newAcceleratorInfo))
-          .then(({result}) => {
-            // TODO(jimmyxgong): Handle other error cases.
-            if (result.result === AcceleratorConfigResult.kSuccess) {
-              this.lookupManager.addAccelerator(
-                  this.source, this.action, newAcceleratorInfo);
-              this.fireUpdateEvent();
-            }
-          });
-    }
-  }
-
   private fireUpdateEvent(): void {
     this.dispatchEvent(new CustomEvent('request-update-accelerator', {
       bubbles: true,
diff --git a/ash/webui/shortcut_customization_ui/resources/js/fake_shortcut_provider.ts b/ash/webui/shortcut_customization_ui/resources/js/fake_shortcut_provider.ts
index ff70c131..e23ba66 100644
--- a/ash/webui/shortcut_customization_ui/resources/js/fake_shortcut_provider.ts
+++ b/ash/webui/shortcut_customization_ui/resources/js/fake_shortcut_provider.ts
@@ -111,9 +111,6 @@
       _old_accelerator: Accelerator,
       _new_accelerator: Accelerator): Promise<{result: AcceleratorResultData}> {
     // Always return kSuccess in this fake.
-    const result = new AcceleratorResultData();
-    result.result = AcceleratorConfigResult.kSuccess;
-    this.methods.setResult('replaceAccelerator', {result});
     return this.methods.resolveMethod('replaceAccelerator');
   }
 
@@ -181,6 +178,10 @@
     this.methods.setResult('addAccelerator', {result});
   }
 
+  setFakeReplaceAcceleratorResult(result: AcceleratorResultData): void {
+    this.methods.setResult('replaceAccelerator', {result});
+  }
+
   // Sets up an observer for methodName.
   private observe(methodName: string, callback: (T: any) => void):
       Promise<void> {
diff --git a/ash/webui/shortcut_customization_ui/resources/js/mojo_interface_provider.ts b/ash/webui/shortcut_customization_ui/resources/js/mojo_interface_provider.ts
index 89aa32b..b1430a0 100644
--- a/ash/webui/shortcut_customization_ui/resources/js/mojo_interface_provider.ts
+++ b/ash/webui/shortcut_customization_ui/resources/js/mojo_interface_provider.ts
@@ -101,8 +101,7 @@
   replaceAccelerator(
       source: AcceleratorSource, action: number, oldAccelerator: Accelerator,
       newAccelerator: Accelerator): Promise<{result: AcceleratorResultData}> {
-    // TODO(cambickel) Replace with real mojo method.
-    return this.fakeProvider.replaceAccelerator(
+    return this.remote.replaceAccelerator(
         source, action, oldAccelerator, newAccelerator);
   }
 
diff --git a/ash/webui/shortcut_customization_ui/resources/js/search/search_box.html b/ash/webui/shortcut_customization_ui/resources/js/search/search_box.html
index 400c9dc1..587613a 100644
--- a/ash/webui/shortcut_customization_ui/resources/js/search/search_box.html
+++ b/ash/webui/shortcut_customization_ui/resources/js/search/search_box.html
@@ -34,7 +34,7 @@
   }
 
   :host(:not(:focus-within)) cr-toolbar-search-field {
-    --cr-toolbar-search-field-cursor: pointer;
+    --cr-toolbar-search-field-cursor: text;
   }
 
   :host([has-search-query]) cr-toolbar-search-field {
@@ -114,6 +114,8 @@
             search-query="[[getCurrentQuery(searchResults)]]"
             last-focused="{{lastFocused}}"
             list-blurred="{{listBlurred}}"
+            list-length="[[getListLength(searchResults)]]"
+            focus-row-index="[[index]]"
             on-navigated-to-result-route="onNavigatedToResultRowRoute"
             tabindex$="[[getRowTabIndex(item, selectedItem,
                 shouldShowDropdown)]]"
diff --git a/ash/webui/shortcut_customization_ui/resources/js/search/search_box.ts b/ash/webui/shortcut_customization_ui/resources/js/search/search_box.ts
index 1be6b626..2c11d72 100644
--- a/ash/webui/shortcut_customization_ui/resources/js/search/search_box.ts
+++ b/ash/webui/shortcut_customization_ui/resources/js/search/search_box.ts
@@ -132,6 +132,12 @@
     const searchInput =
         strictQuery('#search', this.shadowRoot, CrToolbarSearchFieldElement)
             .getSearchInput();
+
+    // Focus the search bar when the app opens.
+    afterNextRender(this, () => {
+      searchInput.focus();
+    });
+
     searchInput.addEventListener('focus', this.onSearchInputFocused.bind(this));
     searchInput.addEventListener(
         'mousedown', this.onSearchInputMousedown.bind(this));
@@ -167,6 +173,13 @@
     return this.searchResults.length !== 0;
   }
 
+  /**
+   * @return Length of the search results array.
+   */
+  private getListLength(): number {
+    return this.searchResults.length;
+  }
+
   private getCurrentQuery(): string {
     return strictQuery('#search', this.shadowRoot, CrToolbarSearchFieldElement)
         .getSearchInput()
diff --git a/ash/webui/shortcut_customization_ui/resources/js/search/search_result_row.ts b/ash/webui/shortcut_customization_ui/resources/js/search/search_result_row.ts
index d1628ec..bdfe8af3 100644
--- a/ash/webui/shortcut_customization_ui/resources/js/search/search_result_row.ts
+++ b/ash/webui/shortcut_customization_ui/resources/js/search/search_result_row.ts
@@ -4,6 +4,7 @@
 import 'chrome://resources/cr_elements/cr_shared_style.css.js';
 import '../text_accelerator.js';
 
+import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
 import {FocusRowMixin} from 'chrome://resources/cr_elements/focus_row_mixin.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {assert} from 'chrome://resources/js/assert_ts.js';
@@ -46,10 +47,23 @@
       selected: {
         type: Boolean,
         reflectToAttribute: true,
+        observer: 'makeA11yAnnouncementIfSelectedAndUnfocused',
       },
+
+      /** Aria label for the row. */
+      ariaLabel: {
+        type: String,
+        computed: 'computeAriaLabel(searchResult)',
+        reflectToAttribute: true,
+      },
+
+      /** Number of rows in the list this row is part of. */
+      listLength: Number,
     };
   }
 
+  override ariaLabel: string;
+  listLength: number;
   searchResult: MojoSearchResult;
   searchQuery: string;
   selected: boolean;
@@ -142,6 +156,29 @@
             this.searchResult.acceleratorLayoutInfo.description),
         this.searchQuery);
   }
+
+  /**
+   * @return Aria label string for ChromeVox to verbalize.
+   */
+  private computeAriaLabel(): string {
+    return this.i18n(
+        'searchResultSelectedAriaLabel', this.focusRowIndex + 1,
+        this.listLength,
+        mojoString16ToString(
+            this.searchResult.acceleratorLayoutInfo.description));
+  }
+
+  private makeA11yAnnouncementIfSelectedAndUnfocused(): void {
+    if (!this.selected || this.lastFocused) {
+      // Do not alert the user if the result is not selected, or
+      // the list is focused, defer to aria tags instead.
+      return;
+    }
+
+    // The selected item is normally not focused when selected, the
+    // selected search result should be verbalized as it changes.
+    getAnnouncerInstance().announce(this.ariaLabel);
+  }
 }
 
 declare global {
diff --git a/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc b/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc
index bac24f2..17a2d20 100644
--- a/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc
+++ b/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc
@@ -79,6 +79,8 @@
        IDS_SHORTCUT_CUSTOMIZATION_SEARCH_PLACEHOLDER_LABEL},
       {"searchAcceleratorTextDivider",
        IDS_SHORTCUT_CUSTOMIZATION_SEARCH_ACCELERATOR_TEXT_DIVIDER},
+      {"searchResultSelectedAriaLabel",
+       IDS_SHORTCUT_CUSTOMIZATION_SEARCH_RESULT_ROW_A11Y_RESULT_SELECTED},
       {"subcategoryGeneralControls",
        IDS_SHORTCUT_CUSTOMIZATION_SUBCATEGORY_GENERAL_CONTROLS},
       {"subcategoryApps", IDS_SHORTCUT_CUSTOMIZATION_SUBCATEGORY_APPS},
diff --git a/ash/wm/desks/desk_bar_view_base.cc b/ash/wm/desks/desk_bar_view_base.cc
new file mode 100644
index 0000000..07056bd1
--- /dev/null
+++ b/ash/wm/desks/desk_bar_view_base.cc
@@ -0,0 +1,135 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/wm/desks/desk_bar_view_base.h"
+
+#include <memory>
+
+#include "ash/public/cpp/shell_window_ids.h"
+#include "ash/public/cpp/window_properties.h"
+#include "ash/shell.h"
+#include "ash/wm/desks/desk_preview_view.h"
+#include "ash/wm/desks/desks_constants.h"
+#include "ash/wm/desks/desks_controller.h"
+#include "ash/wm/overview/overview_controller.h"
+#include "ash/wm/overview/overview_session.h"
+#include "base/check.h"
+#include "base/notreached.h"
+#include "ui/wm/core/window_animations.h"
+
+namespace ash {
+
+DeskBarViewBase::DeskBarViewBase(aura::Window* root, Type type)
+    : type_(type), state_(GetPerferredState(type)), root_(root) {
+  CHECK(root && root->IsRootWindow());
+}
+
+DeskBarViewBase::~DeskBarViewBase() = default;
+
+// static
+int DeskBarViewBase::GetPreferredBarHeight(aura::Window* root,
+                                           Type type,
+                                           State state) {
+  int height = 0;
+  switch (type) {
+    case Type::kDeskButton:
+      CHECK_EQ(State::kExpanded, state);
+      height =
+          DeskPreviewView::GetHeight(root) + kDeskBarNonPreviewAllocatedHeight;
+      break;
+    case Type::kOverview:
+      if (state == State::kZero) {
+        height = kDeskBarZeroStateHeight;
+      } else {
+        height = DeskPreviewView::GetHeight(root) +
+                 kDeskBarNonPreviewAllocatedHeight;
+      }
+      break;
+  }
+
+  return height;
+}
+
+// static
+DeskBarViewBase::State DeskBarViewBase::GetPerferredState(Type type) {
+  State state = State::kZero;
+  switch (type) {
+    case Type::kDeskButton:
+      // Desk button desk bar is always expaneded.
+      state = State::kExpanded;
+      break;
+    case Type::kOverview: {
+      // Overview desk bar can be zero state if both conditions below are true.
+      //   - there is only one desk;
+      //   - not currently showing saved desk library;
+      OverviewController* overview_controller =
+          Shell::Get()->overview_controller();
+      DesksController* desk_controller = DesksController::Get();
+      if (desk_controller->GetNumberOfDesks() == 1 &&
+          overview_controller->InOverviewSession() &&
+          !overview_controller->overview_session()
+               ->IsShowingSavedDeskLibrary()) {
+        state = State::kZero;
+      } else {
+        state = State::kExpanded;
+      }
+      break;
+    }
+  }
+
+  return state;
+}
+
+// static
+std::unique_ptr<views::Widget> DeskBarViewBase::CreateDeskWidget(
+    aura::Window* root,
+    const gfx::Rect& bounds,
+    Type type) {
+  CHECK(root && root->IsRootWindow());
+
+  std::unique_ptr<views::Widget> widget;
+  switch (type) {
+    case Type::kOverview: {
+      widget = std::make_unique<views::Widget>();
+      views::Widget::InitParams params(
+          views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+      params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+      params.activatable = views::Widget::InitParams::Activatable::kYes;
+      params.accept_events = true;
+      params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
+      // This widget will be parented to the currently-active desk container on
+      // `root`.
+      params.context = root;
+      params.bounds = bounds;
+      params.name = "VirtualDesksWidget";
+
+      // Even though this widget exists on the active desk container, it should
+      // not show up in the MRU list, and it should not be mirrored in the desks
+      // mini_views.
+      params.init_properties_container.SetProperty(kExcludeInMruKey, true);
+      params.init_properties_container.SetProperty(kHideInDeskMiniViewKey,
+                                                   true);
+      widget->Init(std::move(params));
+
+      auto* window = widget->GetNativeWindow();
+      window->SetId(kShellWindowId_DesksBarWindow);
+      ::wm::SetWindowVisibilityAnimationTransition(window, ::wm::ANIMATE_NONE);
+
+      break;
+    }
+    case Type::kDeskButton:
+      // TODO(b/274840033): Create desk bar widget for desk button.
+      NOTREACHED();
+
+      break;
+  }
+
+  return widget;
+}
+
+bool DeskBarViewBase::IsZeroState() const {
+  return state_ == DeskBarViewBase::State::kZero;
+}
+
+}  // namespace ash
diff --git a/ash/wm/desks/desk_bar_view_base.h b/ash/wm/desks/desk_bar_view_base.h
new file mode 100644
index 0000000..28998d4
--- /dev/null
+++ b/ash/wm/desks/desk_bar_view_base.h
@@ -0,0 +1,66 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_WM_DESKS_DESK_BAR_VIEW_BASE_H_
+#define ASH_WM_DESKS_DESK_BAR_VIEW_BASE_H_
+
+#include <memory>
+
+#include "ash/ash_export.h"
+#include "ash/wm/desks/desks_controller.h"
+#include "base/allocator/partition_allocator/pointers/raw_ptr.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+
+// Base class for desk bar views, including desk bar view within overview and
+// desk bar view for the desk button.
+class ASH_EXPORT DeskBarViewBase : public views::View,
+                                   public DesksController::Observer {
+ public:
+  enum class Type {
+    kOverview,
+    kDeskButton,
+  };
+
+  enum class State {
+    kZero,
+    kExpanded,
+  };
+
+  DeskBarViewBase(aura::Window* root, Type type);
+  DeskBarViewBase(const DeskBarViewBase&) = delete;
+  DeskBarViewBase& operator=(const DeskBarViewBase&) = delete;
+  ~DeskBarViewBase() override;
+
+  // Returns the preferred height of the desk bar that exists on `root` with
+  // `state`.
+  static int GetPreferredBarHeight(aura::Window* root, Type type, State state);
+
+  // Returns the preferred state for the desk bar given `type`.
+  static State GetPerferredState(Type type);
+
+  // Creates and returns the widget that contains the desk bar view of `type`.
+  // The returned widget has no contents view yet, and hasn't been shown yet.
+  static std::unique_ptr<views::Widget>
+  CreateDeskWidget(aura::Window* root, const gfx::Rect& bounds, Type type);
+
+  Type type() const { return type_; }
+  State state() const { return state_; }
+
+  // Returns true if it is currently in zero state.
+  bool IsZeroState() const;
+
+ protected:
+  const Type type_ = Type::kOverview;
+  State state_ = State::kZero;
+
+ private:
+  raw_ptr<aura::Window> root_;
+};
+
+}  // namespace ash
+
+#endif  // ASH_WM_DESKS_DESK_BAR_VIEW_BASE_H_
diff --git a/ash/wm/desks/desk_mini_view_animations.cc b/ash/wm/desks/desk_mini_view_animations.cc
index 348b4a6..a362335 100644
--- a/ash/wm/desks/desk_mini_view_animations.cc
+++ b/ash/wm/desks/desk_mini_view_animations.cc
@@ -8,8 +8,10 @@
 
 #include "ash/shell.h"
 #include "ash/wm/desks/cros_next_desk_icon_button.h"
+#include "ash/wm/desks/desk_bar_view_base.h"
 #include "ash/wm/desks/desk_mini_view.h"
 #include "ash/wm/desks/desks_bar_view.h"
+#include "ash/wm/desks/desks_constants.h"
 #include "ash/wm/desks/expanded_desks_bar_button.h"
 #include "ash/wm/overview/overview_controller.h"
 #include "ash/wm/overview/overview_grid.h"
@@ -232,7 +234,7 @@
     // When `to_zero_state` is false, desks bar is switching from zero to
     // expanded state.
     if (to_zero_state) {
-      target_widget_bounds.set_height(DesksBarView::kZeroStateBarHeight);
+      target_widget_bounds.set_height(kDeskBarZeroStateHeight);
 
       if (chromeos::features::IsJellyrollEnabled()) {
         // When `Jellyroll` is enabled, setting desks bar's bounds to its bounds
@@ -259,8 +261,9 @@
       // Then set the bounds of the desks bar back to its bounds at zero state
       // to start the bounds change animation. See more details at
       // `is_bounds_animation_on_going_`.
-      target_widget_bounds.set_height(bar_view_->GetExpandedBarHeight(
-          desks_widget->GetNativeWindow()->GetRootWindow()));
+      target_widget_bounds.set_height(DeskBarViewBase::GetPreferredBarHeight(
+          desks_widget->GetNativeWindow()->GetRootWindow(),
+          DeskBarViewBase::Type::kOverview, DeskBarViewBase::State::kExpanded));
       desks_widget->SetBounds(target_widget_bounds);
       bar_view_->set_is_bounds_animation_on_going(true);
       desks_widget->SetBounds(current_widget_bounds);
diff --git a/ash/wm/desks/desks_bar_view.cc b/ash/wm/desks/desks_bar_view.cc
index df572b0..a3b9b33 100644
--- a/ash/wm/desks/desks_bar_view.cc
+++ b/ash/wm/desks/desks_bar_view.cc
@@ -18,6 +18,7 @@
 #include "ash/utility/haptics_util.h"
 #include "ash/wm/desks/cros_next_desk_icon_button.h"
 #include "ash/wm/desks/desk_action_view.h"
+#include "ash/wm/desks/desk_bar_view_base.h"
 #include "ash/wm/desks/desk_drag_proxy.h"
 #include "ash/wm/desks/desk_mini_view.h"
 #include "ash/wm/desks/desk_mini_view_animations.h"
@@ -65,11 +66,6 @@
 
 namespace {
 
-// In the non-compact layout, this is the height allocated for elements other
-// than the desk preview (e.g. the DeskNameView, and the vertical paddings).
-// Note, the vertical paddings should exclude the preview border's insets.
-constexpr int kNonPreviewAllocatedHeight = 48;
-
 constexpr int kMiniViewsY = 16;
 
 // Spacing between mini views.
@@ -512,7 +508,9 @@
 // DesksBarView:
 
 DesksBarView::DesksBarView(OverviewGrid* overview_grid)
-    : overview_grid_(overview_grid) {
+    : DeskBarViewBase(overview_grid->root_window(),
+                      DeskBarViewBase::Type::kOverview),
+      overview_grid_(overview_grid) {
   SetPaintToLayer();
   layer()->SetFillsBoundsOpaquely(false);
 
@@ -643,48 +641,6 @@
     EndDragDesk(drag_view_, /*end_by_user=*/false);
 }
 
-// static
-constexpr int DesksBarView::kZeroStateBarHeight;
-
-// static
-int DesksBarView::GetExpandedBarHeight(aura::Window* root) {
-  return DeskPreviewView::GetHeight(root) + kNonPreviewAllocatedHeight;
-}
-
-// static
-std::unique_ptr<views::Widget> DesksBarView::CreateDesksWidget(
-    aura::Window* root,
-    const gfx::Rect& bounds) {
-  DCHECK(root);
-  DCHECK(root->IsRootWindow());
-
-  auto widget = std::make_unique<views::Widget>();
-  views::Widget::InitParams params(
-      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
-  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  params.activatable = views::Widget::InitParams::Activatable::kYes;
-  params.accept_events = true;
-  params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
-  // This widget will be parented to the currently-active desk container on
-  // |root|.
-  params.context = root;
-  params.bounds = bounds;
-  params.name = "VirtualDesksWidget";
-
-  // Even though this widget exists on the active desk container, it should not
-  // show up in the MRU list, and it should not be mirrored in the desks
-  // mini_views.
-  params.init_properties_container.SetProperty(kExcludeInMruKey, true);
-  params.init_properties_container.SetProperty(kHideInDeskMiniViewKey, true);
-  widget->Init(std::move(params));
-
-  auto* window = widget->GetNativeWindow();
-  window->SetId(kShellWindowId_DesksBarWindow);
-  ::wm::SetWindowVisibilityAnimationTransition(window, ::wm::ANIMATE_NONE);
-
-  return widget;
-}
-
 void DesksBarView::Init() {
   UpdateNewMiniViews(/*initializing_bar_view=*/true,
                      /*expanding_bar_view=*/false);
@@ -751,10 +707,6 @@
   }
 }
 
-bool DesksBarView::IsZeroState() const {
-  return mini_views_.empty() && DesksController::Get()->desks().size() == 1;
-}
-
 void DesksBarView::HandlePressEvent(DeskMiniView* mini_view,
                                     const ui::LocatedEvent& event) {
   if (mini_view->is_animating_to_remove())
@@ -1128,10 +1080,13 @@
 void DesksBarView::UpdateNewMiniViews(bool initializing_bar_view,
                                       bool expanding_bar_view) {
   const auto& desks = DesksController::Get()->desks();
-  if (initializing_bar_view)
+  if (initializing_bar_view) {
     UpdateDeskButtonsVisibility();
-  if (IsZeroState() && !expanding_bar_view)
+  }
+  if (IsZeroState() && !expanding_bar_view) {
     return;
+  }
+
   // This should not be called when a desk is removed.
   DCHECK_LE(mini_views_.size(), desks.size());
 
@@ -1156,12 +1111,7 @@
   }
 
   if (expanding_bar_view) {
-    UpdateDeskButtonsVisibility();
-    if (chromeos::features::IsJellyrollEnabled()) {
-      PerformZeroStateToExpandedStateMiniViewAnimationCrOSNext(this);
-    } else {
-      PerformZeroStateToExpandedStateMiniViewAnimation(this);
-    }
+    SwitchToExpandedState();
     return;
   }
 
@@ -1176,8 +1126,9 @@
 
   Layout();
 
-  if (initializing_bar_view)
+  if (initializing_bar_view) {
     return;
+  }
 
   // We need to compile lists of the mini views on either side of the new mini
   // views so that they can be moved to make room for the new mini views in the
@@ -1370,6 +1321,8 @@
 void DesksBarView::SwitchToZeroState() {
   DCHECK(!chromeos::features::IsJellyrollEnabled());
 
+  state_ = DeskBarViewBase::State::kZero;
+
   // In zero state, if the only desk is being dragged, we should end dragging.
   // Because the dragged desk's mini view is removed, the mouse released or
   // gesture ended events cannot be received. |drag_view_| will keep the stale
@@ -1392,6 +1345,17 @@
   PerformExpandedStateToZeroStateMiniViewAnimation(this, removed_mini_views);
 }
 
+void DesksBarView::SwitchToExpandedState() {
+  state_ = DeskBarViewBase::State::kExpanded;
+
+  UpdateDeskButtonsVisibility();
+  if (chromeos::features::IsJellyrollEnabled()) {
+    PerformZeroStateToExpandedStateMiniViewAnimationCrOSNext(this);
+  } else {
+    PerformZeroStateToExpandedStateMiniViewAnimation(this);
+  }
+}
+
 int DesksBarView::DetermineMoveIndex(int location_screen_x) const {
   const int views_size = static_cast<int>(mini_views_.size());
 
diff --git a/ash/wm/desks/desks_bar_view.h b/ash/wm/desks/desks_bar_view.h
index 7d5a239..78f0cf5 100644
--- a/ash/wm/desks/desks_bar_view.h
+++ b/ash/wm/desks/desks_bar_view.h
@@ -11,6 +11,7 @@
 #include "ash/ash_export.h"
 #include "ash/wm/desks/cros_next_default_desk_button.h"
 #include "ash/wm/desks/cros_next_desk_icon_button.h"
+#include "ash/wm/desks/desk_bar_view_base.h"
 #include "ash/wm/desks/desks_controller.h"
 #include "ash/wm/desks/templates/saved_desk_metrics_util.h"
 #include "base/callback_list.h"
@@ -33,8 +34,7 @@
 
 // A bar that resides at the top portion of the overview mode's ShieldView,
 // which contains the virtual desks mini_views, as well as the new desk button.
-class ASH_EXPORT DesksBarView : public views::View,
-                                public DesksController::Observer {
+class ASH_EXPORT DesksBarView : public DeskBarViewBase {
  public:
   explicit DesksBarView(OverviewGrid* overview_grid);
 
@@ -43,19 +43,6 @@
 
   ~DesksBarView() override;
 
-  static constexpr int kZeroStateBarHeight = 40;
-
-  // Returns the height of the expanded desks bar that exists on `root`. The
-  // height of zero state desks bar is `kZeroStateBarHeight`.
-  static int GetExpandedBarHeight(aura::Window* root);
-
-  // Creates and returns the widget that contains the DeskBarView in overview
-  // mode. The returned widget has no content view yet, and hasn't been shown
-  // yet.
-  static std::unique_ptr<views::Widget> CreateDesksWidget(
-      aura::Window* root,
-      const gfx::Rect& bounds);
-
   void set_is_bounds_animation_on_going(bool value) {
     is_bounds_animation_on_going_ = value;
   }
@@ -148,10 +135,6 @@
   void SetDragDetails(const gfx::Point& screen_location,
                       bool dragged_item_over_bar);
 
-  // Returns true if it is in zero state. It is the state of the desks bar when
-  // there's only a single desk available, in which case the bar is shown in a
-  // minimized state.
-  bool IsZeroState() const;
   // Handle the mouse press event from a desk preview.
   void HandlePressEvent(DeskMiniView* mini_view, const ui::LocatedEvent& event);
   // Handle the gesture long press event from a desk preview.
@@ -205,12 +188,26 @@
   void OnDeskNameChanged(const Desk* desk,
                          const std::u16string& new_name) override;
 
-  // This is called on initialization, creating a new desk through the
-  // NewDeskButton or ExpandedDesksBarButton, or expanding from zero state
-  // bar to the expanded desks bar. Performs the expanding animation if
-  // |expanding_bar_view| is true, otherwise animates the mini_views (also the
-  // ExpandedDesksBarButton) to their final positions if
-  // |initializing_bar_view| is false.
+  // This is used for the initialization, the expansion, or just the update of
+  // child components.
+  // Given input parameter values of {`initializing_bar_view`,
+  // `expanding_bar_view`}, this does different things as following.
+  //    1. {false, false}
+  //      When a desk is added from the expanded state, the bar remains
+  //      expanded.
+  //    2. {true, false}
+  //      When the bar is being initialized, the bar will switch to either the
+  //      zero state or the expanded state.
+  //    3. {false, true}
+  //      When the bar is being expanded, the bar will switch to the expanded
+  //      state. This is when a desk is added from the zero state, or by the
+  //      interaction of bar UI, such as clicking the default desk button,
+  //      dragging overview item over new desk button, clicking the library
+  //      button, etc.
+  //    4. {true, true}
+  //      Not a valid input.
+  // TODO(b/277969403): Improve and simplify this overloaded function by moving
+  // logic to `SwitchToZeroState` and `SwitchToExpandedState`.
   void UpdateNewMiniViews(bool initializing_bar_view, bool expanding_bar_view);
 
   // If the focused `view` is outside of the scroll view's visible bounds,
@@ -253,9 +250,14 @@
   // has been created for it yet.
   DeskMiniView* FindMiniViewForDesk(const Desk* desk) const;
 
-  // Animates the bar from expanded state to zero state. Clears `mini_views_`.
+  // Animates the bar from the expanded state to the zero state. It refreshes
+  // the bounds of the desk bar widget, and also updates child UI components,
+  // including desk mini views, the new desk button, and the library button.
   void SwitchToZeroState();
 
+  // Animates the bar from the zero state to the expanded state.
+  void SwitchToExpandedState();
+
   // Bring focus to the name view of the desk with `desk_index`.
   void NudgeDeskName(int desk_index);
 
diff --git a/ash/wm/desks/desks_constants.h b/ash/wm/desks/desks_constants.h
index daeb527..209cc8b 100644
--- a/ash/wm/desks/desks_constants.h
+++ b/ash/wm/desks/desks_constants.h
@@ -20,6 +20,14 @@
 // full desk change.
 constexpr int kTouchpadSwipeLengthForDeskChange = 420;
 
+// This is the height allocated for elements other than the desk preview (e.g.
+// the DeskNameView, and the vertical paddings). Note, the vertical paddings
+// should exclude the preview border's insets.
+constexpr int kDeskBarNonPreviewAllocatedHeight = 48;
+
+// This is the desk bar height for zero state.
+constexpr int kDeskBarZeroStateHeight = 40;
+
 }  // namespace ash
 
 #endif  // ASH_WM_DESKS_DESKS_CONSTANTS_H_
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index 09cea56b..5a3c5db 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -24,9 +24,11 @@
 #include "ash/wallpaper/wallpaper_controller_impl.h"
 #include "ash/wm/desks/cros_next_default_desk_button.h"
 #include "ash/wm/desks/cros_next_desk_icon_button.h"
+#include "ash/wm/desks/desk_bar_view_base.h"
 #include "ash/wm/desks/desk_mini_view.h"
 #include "ash/wm/desks/desk_name_view.h"
 #include "ash/wm/desks/desks_bar_view.h"
+#include "ash/wm/desks/desks_constants.h"
 #include "ash/wm/desks/desks_controller.h"
 #include "ash/wm/desks/desks_util.h"
 #include "ash/wm/desks/expanded_desks_bar_button.h"
@@ -1752,7 +1754,10 @@
     // library if we are currently in the zero state mode.
     gfx::Rect library_bounds = bounds_;
     library_bounds.Inset(gfx::Insets::TLBR(
-        DesksBarView::GetExpandedBarHeight(root_window_), 0, 0, 0));
+        DesksBarView::GetPreferredBarHeight(root_window_,
+                                            DesksBarView::Type::kOverview,
+                                            DesksBarView::State::kExpanded),
+        0, 0, 0));
 
     saved_desk_library_widget_->SetBounds(library_bounds);
   }
@@ -2186,8 +2191,8 @@
   if (!desks_util::ShouldDesksBarBeCreated() || desks_widget_)
     return;
 
-  desks_widget_ =
-      DesksBarView::CreateDesksWidget(root_window_, GetDesksWidgetBounds());
+  desks_widget_ = DeskBarViewBase::CreateDeskWidget(
+      root_window_, GetDesksWidgetBounds(), DeskBarViewBase::Type::kOverview);
 
   // The following order of function calls is significant: SetContentsView()
   // must be called before DesksBarView:: Init(). This is needed because the
@@ -2576,9 +2581,9 @@
                                    ->disable_app_id_check_for_saved_desks() ||
                                !full_restore::GetAppId(window).empty());
   int addend = increment ? 1 : -1;
-  if (!DeskTemplate::IsAppTypeSupported(window) || !has_restore_id)
+  if (!DeskTemplate::IsAppTypeSupported(window) || !has_restore_id) {
     num_unsupported_windows_ += addend;
-  else if (Shell::Get()->saved_desk_delegate()->IsIncognitoWindow(window)) {
+  } else if (Shell::Get()->saved_desk_delegate()->IsIncognitoWindow(window)) {
     num_incognito_windows_ += addend;
   }
 
@@ -2587,14 +2592,12 @@
 }
 
 int OverviewGrid::GetDesksBarHeight() const {
-  const bool should_show_zero_state_desks_bar =
-      desks_bar_view_ ? desks_bar_view_->IsZeroState()
-                      : !IsShowingSavedDeskLibrary() &&
-                            DesksController::Get()->GetNumberOfDesks() == 1;
-
-  return should_show_zero_state_desks_bar
-             ? DesksBarView::kZeroStateBarHeight
-             : DesksBarView::GetExpandedBarHeight(root_window_);
+  DeskBarViewBase::State state =
+      desks_bar_view_
+          ? desks_bar_view_->state()
+          : DesksBarView::GetPerferredState(DesksBarView::Type::kOverview);
+  return DesksBarView::GetPreferredBarHeight(
+      root_window_, DesksBarView::Type::kOverview, state);
 }
 
 }  // namespace ash
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index 3c92c52..a9c7e8ee0 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -36,6 +36,7 @@
 #include "ash/test/test_window_builder.h"
 #include "ash/wm/desks/desk.h"
 #include "ash/wm/desks/desks_bar_view.h"
+#include "ash/wm/desks/desks_constants.h"
 #include "ash/wm/desks/desks_test_util.h"
 #include "ash/wm/desks/desks_util.h"
 #include "ash/wm/desks/templates/saved_desk_save_desk_button.h"
@@ -1705,9 +1706,8 @@
 
   // Verify that originally the label is in the center of the workspace.
   // Midpoint of height minus shelf.
-  int expected_y = (300 - ShelfConfig::Get()->shelf_size() +
-                    DesksBarView::kZeroStateBarHeight) /
-                   2;
+  int expected_y =
+      (300 - ShelfConfig::Get()->shelf_size() + kDeskBarZeroStateHeight) / 2;
   EXPECT_EQ(gfx::Point(200, expected_y),
             no_windows_widget->GetWindowBoundsInScreen().CenterPoint());
 
@@ -1718,9 +1718,8 @@
   display_manager()->SetDisplayRotation(
       display.id(), display::Display::ROTATE_90,
       display::Display::RotationSource::ACTIVE);
-  expected_y = (400 - ShelfConfig::Get()->shelf_size() +
-                DesksBarView::kZeroStateBarHeight) /
-               2;
+  expected_y =
+      (400 - ShelfConfig::Get()->shelf_size() + kDeskBarZeroStateHeight) / 2;
   EXPECT_EQ(gfx::Point(150, expected_y),
             no_windows_widget->GetWindowBoundsInScreen().CenterPoint());
 }
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc
index 556495a..3b544285 100644
--- a/ash/wm/overview/overview_window_drag_controller.cc
+++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -120,8 +120,9 @@
   const DesksBarView* desks_bar_view = overview_grid->desks_bar_view();
   DCHECK(desks_bar_view);
 
-  const int expanded_desks_bar_height =
-      DesksBarView::GetExpandedBarHeight(overview_grid->root_window());
+  const int expanded_desks_bar_height = DesksBarView::GetPreferredBarHeight(
+      overview_grid->root_window(), DesksBarView::Type::kOverview,
+      DesksBarView::State::kExpanded);
 
   // We should always use the expanded desks bar height here even if the desks
   // bar is actually in zero state to calculate `scale_factor`. Because if zero
@@ -399,8 +400,9 @@
           GetItemSizeWhenOnDesksBar(grid.get(), window_original_size);
       grid_desks_bar_data.desks_bar_bounds = grid_desks_bar_data.shrink_bounds =
           gfx::RectF(grid->desks_bar_view()->GetBoundsInScreen());
-      const int expanded_height =
-          DesksBarView::GetExpandedBarHeight(grid->root_window());
+      const int expanded_height = DesksBarView::GetPreferredBarHeight(
+          grid->root_window(), DesksBarView::Type::kOverview,
+          DesksBarView::State::kExpanded);
       grid_desks_bar_data.desks_bar_bounds.set_height(expanded_height);
       grid_desks_bar_data.shrink_bounds.set_height(expanded_height);
       grid_desks_bar_data.shrink_bounds.Inset(gfx::InsetsF::VH(
diff --git a/ash/wm/overview/overview_window_drag_controller_unittest.cc b/ash/wm/overview/overview_window_drag_controller_unittest.cc
index 7c7d64e..395688b 100644
--- a/ash/wm/overview/overview_window_drag_controller_unittest.cc
+++ b/ash/wm/overview/overview_window_drag_controller_unittest.cc
@@ -11,6 +11,7 @@
 #include "ash/wm/desks/desk.h"
 #include "ash/wm/desks/desk_mini_view.h"
 #include "ash/wm/desks/desks_bar_view.h"
+#include "ash/wm/desks/desks_constants.h"
 #include "ash/wm/desks/desks_controller.h"
 #include "ash/wm/desks/desks_histogram_enums.h"
 #include "ash/wm/desks/desks_util.h"
@@ -176,8 +177,9 @@
   }
 
   int GetDesksBarViewExpandedStateHeight(const DesksBarView* desks_bar_view) {
-    return desks_bar_view->GetExpandedBarHeight(
-        desks_bar_view->GetWidget()->GetNativeWindow()->GetRootWindow());
+    return DesksBarView::GetPreferredBarHeight(
+        desks_bar_view->GetWidget()->GetNativeWindow()->GetRootWindow(),
+        DesksBarView::Type::kOverview, DesksBarView::State::kExpanded);
   }
 };
 
@@ -311,16 +313,14 @@
   const auto* desks_bar_view = overview_grid()->desks_bar_view();
   ASSERT_TRUE(desks_bar_view);
   // Check the height of the desks bar view. It should have height
-  // `kZeroStateBarHeight` while dragging `window`.
-  EXPECT_EQ(DesksBarView::kZeroStateBarHeight,
-            desks_bar_view->bounds().height());
+  // `kDeskBarZeroStateHeight` while dragging `window`.
+  EXPECT_EQ(kDeskBarZeroStateHeight, desks_bar_view->bounds().height());
 
   // Now drop `window`. Check the height of the desks bar view. It should still
-  // be `kZeroStateBarHeight`.
+  // be `kDeskBarZeroStateHeight`.
   auto* event_generator = GetEventGenerator();
   event_generator->ReleaseLeftButton();
-  EXPECT_EQ(DesksBarView::kZeroStateBarHeight,
-            desks_bar_view->bounds().height());
+  EXPECT_EQ(kDeskBarZeroStateHeight, desks_bar_view->bounds().height());
 
   // Click on the zero state new desk button to create a new desk. This
   // shouldn't end overview mode. The desks bar view should be transformed to
@@ -344,8 +344,7 @@
                          DeskCloseType::kCombineDesks);
   EXPECT_TRUE(overview_controller()->InOverviewSession());
   EXPECT_TRUE(desks_bar_view->IsZeroState());
-  EXPECT_EQ(DesksBarView::kZeroStateBarHeight,
-            desks_bar_view->bounds().height());
+  EXPECT_EQ(kDeskBarZeroStateHeight, desks_bar_view->bounds().height());
 }
 
 // Tests that dragging window in portrait mode won't cause overview items
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index 46f7e90..da7e501 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -4,6 +4,7 @@
 
 #include "ash/wm/window_state.h"
 
+#include <absl/cleanup/cleanup.h>
 #include <memory>
 #include <utility>
 
@@ -1202,40 +1203,14 @@
     return;
   }
 
-  // We'll need to pop out any window state that the `current_state_type` can
-  // not restore back to (i.e., whose restore order is equal or higher than
-  // `current_state_type`).
-  for (auto& state : base::Reversed(window_state_restore_history_)) {
-    if (CanRestoreState(current_state_type, state.window_state_type)) {
-      break;
-    }
-    // Retrieve and hold onto the restore state for the state type that we're
-    // entering into, so it can be used later, e.g., to update the restore
-    // bounds property.
-    if (IsEquivalent(state.window_state_type, current_state_type)) {
-      current_restore_state_ = std::move(state);
-    }
-    window_state_restore_history_.pop_back();
-  }
-  // If the state we're entering into is not in the history, but we also have
-  // existing restore bounds, then we want to use it. This can happen if, for
-  // example, a window was restored from full restore in a non-normal window
-  // state type, then it may have a truncated restore history but with restore
-  // bounds.
-  if (!current_restore_state_ && HasRestoreBounds()) {
-    current_restore_state_ = {
-        .window_state_type = current_state_type,
-        .actual_bounds_in_screen = GetCurrentBoundsInScreen(),
-        .restore_bounds_in_screen = GetRestoreBoundsInScreen(),
-    };
-  }
-
+  // Figure out if the previous state is restorable from the current state.
+  absl::optional<RestoreState> new_restore_state;
   if (IsValidForRestoreHistory(previous_state_type) &&
       CanRestoreState(current_state_type, previous_state_type)) {
-    window_state_restore_history_.push_back({
+    new_restore_state = {
         .window_state_type = previous_state_type,
         .actual_bounds_in_screen = GetCurrentBoundsInScreen(),
-    });
+    };
     // Save current restore bounds, if any. Also check that restore bounds are
     // not the same as current bounds, because when dragging a window, the
     // restore bounds is used temporarily to remember the original pre-drag
@@ -1245,51 +1220,86 @@
     // bounds, so we can remove this workaround.
     if (HasRestoreBounds() &&
         GetRestoreBoundsInScreen() != GetCurrentBoundsInScreen()) {
-      window_state_restore_history_.back().restore_bounds_in_screen =
-          GetRestoreBoundsInScreen();
+      new_restore_state->restore_bounds_in_screen = GetRestoreBoundsInScreen();
     }
   }
 
-  // The check for tablet mode has the same reason as
-  // UpdateRestorePropertiesFromRestoreHistory().
-  if (!IsTabletModeEnabled()) {
-    // Update the restore bounds so it can be used to update window bounds.
-    if (current_restore_state_ &&
-        current_restore_state_->restore_bounds_in_screen) {
-      SetRestoreBoundsInScreen(
-          *current_restore_state_->restore_bounds_in_screen);
+  // Prune the tree so that it will be restorable from the current state. If we
+  // are adding the previous state to the history, we need to use that instead
+  // of the current type.
+  auto restore_target_state_type = new_restore_state
+                                       ? new_restore_state->window_state_type
+                                       : current_state_type;
+  for (auto& state : base::Reversed(window_state_restore_history_)) {
+    if (CanRestoreState(restore_target_state_type, state.window_state_type)) {
+      break;
+    }
+    // Minimize is special because it sometimes interferes with the restore
+    // bounds of the window state. It is specially handled by retrieving the
+    // stored state's restore bounds. This can be tested by maximizing on one
+    // axis, minimizing, unminimizing, then restoring.
+    if (previous_state_type == WindowStateType::kMinimized &&
+        IsEquivalent(state.window_state_type, current_state_type)) {
+      restore_bounds_override_ = state.restore_bounds_in_screen;
+    }
+    window_state_restore_history_.pop_back();
+  }
+
+  if (new_restore_state) {
+    window_state_restore_history_.push_back(std::move(*new_restore_state));
+  }
+
+  // This is a special logic for windows that were created from full restore.
+  // In those cases, the full history of window states is truncated. We detect
+  // this by asserting that any non-normal windows that have no previous history
+  // must have a truncated history.
+  //
+  // Unfortunately this case is particularly tricky because the restore bounds
+  // will be set externally, using the same windows property key.
+  //
+  // If we detect that we are in full restore, we will artificially create a
+  // normal restore state in history to retain the bounds.
+  if (window_state_restore_history_.empty() && HasRestoreBounds()) {
+    if (!IsNormalStateType()) {
+      window_state_restore_history_.push_back({
+          .window_state_type = WindowStateType::kDefault,
+          // Not a mistake. We do not want to use the current bounds which can
+          // be invalid for the normal state.
+          .actual_bounds_in_screen = GetRestoreBoundsInScreen(),
+          .restore_bounds_in_screen = GetRestoreBoundsInScreen(),
+      });
     }
   }
 }
 
 void WindowState::UpdateRestorePropertiesFromRestoreHistory() {
+  absl::Cleanup override_reset = [this] { restore_bounds_override_.reset(); };
+
   // TODO(xdai): For now we don't save the restore history in tablet mode in the
   // window property, so that when exiting tablet mode, the window can still
   // restore back to its old window state (see the test case
   // TabletModeWindowManagerTest.UnminimizeInTabletMode). We should revisit this
   // logic.
-  if (!IsTabletModeEnabled()) {
-    window_->SetProperty(aura::client::kRestoreShowStateKey,
-                         chromeos::ToWindowShowState(GetRestoreWindowState()));
-    // Update restore bounds again, since it may have been modified by other
-    // bounds update logic, e.g. when unminimizing.
-    if (current_restore_state_ &&
-        current_restore_state_->restore_bounds_in_screen) {
-      // This means we had existing restore bounds, so propagate it.
-      SetRestoreBoundsInScreen(
-          *current_restore_state_->restore_bounds_in_screen);
-    } else if (auto bounds = GetBoundsForRestore(PeekNextRestoreState());
-               !bounds.IsEmpty()) {
-      // This means we're entering a new state not in the restore history, i.e.
-      // not restoring back to an earlier state, so we propagate the restorable
-      // bounds from the most recent restore state.
-      SetRestoreBoundsInScreen(bounds);
-    } else {
-      // There's no restore bounds from anywhere to propagate, so clear it.
-      ClearRestoreBounds();
-    }
+  if (IsTabletModeEnabled()) {
+    return;
   }
-  current_restore_state_.reset();
+
+  window_->SetProperty(aura::client::kRestoreShowStateKey,
+                       chromeos::ToWindowShowState(GetRestoreWindowState()));
+  // If an override exists with a restore bound, use it. Otherwise, use the
+  // tip of the version history stack.
+  if (restore_bounds_override_) {
+    // This means we had existing restore bounds, so propagate it.
+    SetRestoreBoundsInScreen(*restore_bounds_override_);
+  } else if (auto bounds = GetBoundsForRestore(PeekNextRestoreState());
+             !bounds.IsEmpty()) {
+    // Not restoring back to an earlier state, so we propagate the restorable
+    // bounds from the most recent restore state.
+    SetRestoreBoundsInScreen(bounds);
+  } else {
+    // There's no restore bounds from anywhere to propagate, so clear it.
+    ClearRestoreBounds();
+  }
 }
 
 const WindowState::RestoreState* WindowState::PeekNextRestoreState() const {
diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h
index 414d63b..935d34f 100644
--- a/ash/wm/window_state.h
+++ b/ash/wm/window_state.h
@@ -698,8 +698,14 @@
   // state types can be put in the restore history stack.
   std::vector<RestoreState> window_state_restore_history_;
 
-  // Holds the current working restore state.
-  absl::optional<RestoreState> current_restore_state_;
+  // Usually we want to use the tip of the window_state_restore_history_ to
+  // retrieve the restore_bounds. However, there are cases where we might want
+  // to explicitly set or store a specific restore bounds when transitioning
+  // between states. This typically happens because an operation might cause
+  // the restore bounds to become incorrect. If a value is present, it will have
+  // a higher precedent than whatever is at the tip of
+  // window_state_restore_history_.
+  absl::optional<gfx::Rect> restore_bounds_override_;
 
   // This is used to record where the current snap window state change request
   // comes from.
diff --git a/ash/wm/window_state_unittest.cc b/ash/wm/window_state_unittest.cc
index a9f777eb..f488022aa 100644
--- a/ash/wm/window_state_unittest.cc
+++ b/ash/wm/window_state_unittest.cc
@@ -1751,6 +1751,56 @@
   EXPECT_EQ(window_state->GetRestoreWindowState(), WindowStateType::kNormal);
 }
 
+TEST_F(WindowStateTest, SnapThenResize) {
+  UpdateDisplay("800x600");
+  const gfx::Rect work_area_bounds = GetPrimaryDisplay().work_area();
+
+  // Start with kDefault window state.
+  constexpr gfx::Rect default_bounds(20, 10, 200, 150);
+  std::unique_ptr<aura::Window> window = CreateAppWindow(default_bounds);
+  WindowState* window_state = WindowState::Get(window.get());
+  EXPECT_TRUE(window_state->IsNormalStateType());
+
+  const std::vector<WindowState::RestoreState>& restore_stack =
+      window_state->window_state_restore_history_for_testing();
+  EXPECT_TRUE(restore_stack.empty());
+  EXPECT_EQ(window_state->GetRestoreWindowState(), WindowStateType::kNormal);
+  EXPECT_EQ(window_state->GetRestoreBoundsInScreen(), gfx::Rect());
+
+  // Important! Change the restore bounds, so they are not the same. This will
+  // create a conflict between the window's current bounds and the restore
+  // bounds when restoring.
+  constexpr gfx::Rect moved_bounds(10, 10, 200, 150);
+  window->SetBounds(moved_bounds);
+  window_state->SetRestoreBoundsInScreen(default_bounds);
+
+  const WMEvent snap_left_event(WM_EVENT_SNAP_PRIMARY);
+  const gfx::Rect snapped_left_bounds(0, 0, work_area_bounds.width() / 2,
+                                      work_area_bounds.height());
+  window_state->OnWMEvent(&snap_left_event);
+  EXPECT_EQ(window->GetBoundsInScreen(), snapped_left_bounds);
+  EXPECT_EQ(restore_stack.size(), 1U);
+  EXPECT_EQ(window_state->GetRestoreBoundsInScreen(), default_bounds);
+
+  const int resize = 100;
+  const gfx::Rect resized_bounds(0, resize, work_area_bounds.width() / 2,
+                                 work_area_bounds.height() - resize);
+  {
+    // Drag the top of the window to unsnap and resize.
+    ui::test::EventGenerator* generator = GetEventGenerator();
+    generator->MoveMouseTo(snapped_left_bounds.top_center().x(),
+                           snapped_left_bounds.top_center().y());
+    generator->PressLeftButton();
+    generator->MoveMouseTo(snapped_left_bounds.top_center().x(), resize);
+    generator->ReleaseLeftButton();
+  }
+
+  EXPECT_TRUE(window_state->IsNormalStateType());
+  EXPECT_TRUE(restore_stack.empty());
+  EXPECT_EQ(window_state->GetCurrentBoundsInScreen(), resized_bounds);
+  EXPECT_EQ(window_state->GetRestoreBoundsInScreen(), gfx::Rect());
+}
+
 // Tests the restore behavior for default or normal window.
 TEST_F(WindowStateTest, NormalOrDefaultRestore) {
   // Start with kDefault window state.
diff --git a/base/BUILD.gn b/base/BUILD.gn
index b03c9723..3810322 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -480,6 +480,8 @@
     "metrics/dummy_histogram.h",
     "metrics/field_trial.cc",
     "metrics/field_trial.h",
+    "metrics/field_trial_list_including_low_anonymity.cc",
+    "metrics/field_trial_list_including_low_anonymity.h",
     "metrics/field_trial_param_associator.cc",
     "metrics/field_trial_param_associator.h",
     "metrics/field_trial_params.cc",
diff --git a/base/android/field_trial_list.cc b/base/android/field_trial_list.cc
index 64b1763..d2b01fca 100644
--- a/base/android/field_trial_list.cc
+++ b/base/android/field_trial_list.cc
@@ -11,6 +11,7 @@
 #include "base/base_jni_headers/FieldTrialList_jni.h"
 #include "base/lazy_instance.h"
 #include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_list_including_low_anonymity.h"
 #include "base/metrics/field_trial_params.h"
 
 using base::android::ConvertJavaStringToUTF8;
@@ -77,15 +78,39 @@
       env, parameters[ConvertJavaStringToUTF8(env, jparameter_key)]);
 }
 
+// JNI_FieldTrialList_LogActiveTrials() is static function, this makes friending
+// it a hassle because it must be declared in the file that the friend
+// declaration is in, but its declaration can't be included in multiple places
+// or things get messy and the linker gets mad. This helper class exists only to
+// friend the JNI function and is, in turn, friended by
+// FieldTrialListIncludingLowAnonymity which allows for the private
+// GetActiveFieldTrialGroups() to be reached.
+class AndroidFieldTrialListLogActiveTrialsFriendHelper {
+ private:
+  friend void ::JNI_FieldTrialList_LogActiveTrials(JNIEnv* env);
+
+  static bool AddObserver(base::FieldTrialList::Observer* observer) {
+    return base::FieldTrialListIncludingLowAnonymity::AddObserver(observer);
+  }
+
+  static void GetActiveFieldTrialGroups(
+      base::FieldTrial::ActiveGroups* active_groups) {
+    base::FieldTrialListIncludingLowAnonymity::GetActiveFieldTrialGroups(
+        active_groups);
+  }
+};
+
 static void JNI_FieldTrialList_LogActiveTrials(JNIEnv* env) {
   DCHECK(!g_trial_logger.IsCreated()); // This need only be called once.
 
   LOG(INFO) << "Logging active field trials...";
-  base::FieldTrialList::AddObserver(&g_trial_logger.Get());
+  AndroidFieldTrialListLogActiveTrialsFriendHelper::AddObserver(
+      &g_trial_logger.Get());
 
   // Log any trials that were already active before adding the observer.
   std::vector<base::FieldTrial::ActiveGroup> active_groups;
-  base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  AndroidFieldTrialListLogActiveTrialsFriendHelper::GetActiveFieldTrialGroups(
+      &active_groups);
   for (const base::FieldTrial::ActiveGroup& group : active_groups) {
     TrialLogger::Log(group.trial_name, group.group_name);
   }
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
index 06cb7bf..fa6a8cc 100644
--- a/base/metrics/field_trial.cc
+++ b/base/metrics/field_trial.cc
@@ -372,13 +372,14 @@
     StringPiece default_group_name,
     double entropy_value) {
   return new FieldTrial(trial_name, total_probability, default_group_name,
-                        entropy_value);
+                        entropy_value, /*is_low_anonymity=*/false);
 }
 
 FieldTrial::FieldTrial(StringPiece trial_name,
                        const Probability total_probability,
                        StringPiece default_group_name,
-                       double entropy_value)
+                       double entropy_value,
+                       bool is_low_anonymity)
     : trial_name_(trial_name),
       divisor_(total_probability),
       default_group_name_(default_group_name),
@@ -389,7 +390,8 @@
       forced_(false),
       group_reported_(false),
       trial_registered_(false),
-      ref_(FieldTrialList::FieldTrialAllocator::kReferenceNull) {
+      ref_(FieldTrialList::FieldTrialAllocator::kReferenceNull),
+      is_low_anonymity_(is_low_anonymity) {
   DCHECK_GT(total_probability, 0);
   DCHECK(!trial_name_.empty());
   DCHECK(!default_group_name_.empty())
@@ -472,7 +474,8 @@
     FieldTrial::Probability total_probability,
     StringPiece default_group_name,
     const FieldTrial::EntropyProvider& entropy_provider,
-    uint32_t randomization_seed) {
+    uint32_t randomization_seed,
+    bool is_low_anonymity) {
   // Check if the field trial has already been created in some other way.
   FieldTrial* existing_trial = Find(trial_name);
   if (existing_trial) {
@@ -483,8 +486,9 @@
   double entropy_value =
       entropy_provider.GetEntropyForTrial(trial_name, randomization_seed);
 
-  FieldTrial* field_trial = new FieldTrial(trial_name, total_probability,
-                                           default_group_name, entropy_value);
+  FieldTrial* field_trial =
+      new FieldTrial(trial_name, total_probability, default_group_name,
+                     entropy_value, is_low_anonymity);
   FieldTrialList::Register(field_trial, /*is_randomized_trial=*/true);
   return field_trial;
 }
@@ -609,16 +613,8 @@
 // static
 void FieldTrialList::GetActiveFieldTrialGroups(
     FieldTrial::ActiveGroups* active_groups) {
-  DCHECK(active_groups->empty());
-  if (!global_)
-    return;
-  AutoLock auto_lock(global_->lock_);
-
-  for (const auto& registered : global_->registered_) {
-    FieldTrial::ActiveGroup active_group;
-    if (registered.second->GetActiveGroup(&active_group))
-      active_groups->push_back(active_group);
-  }
+  GetActiveFieldTrialGroupsInternal(active_groups,
+                                    /*include_low_anonymity=*/false);
 }
 
 // static
@@ -805,7 +801,8 @@
 
 // static
 FieldTrial* FieldTrialList::CreateFieldTrial(StringPiece name,
-                                             StringPiece group_name) {
+                                             StringPiece group_name,
+                                             bool is_low_anonymity) {
   DCHECK(global_);
   DCHECK_GE(name.size(), 0u);
   DCHECK_GE(group_name.size(), 0u);
@@ -821,7 +818,8 @@
     return field_trial;
   }
   const int kTotalProbability = 100;
-  field_trial = new FieldTrial(name, kTotalProbability, group_name, 0);
+  field_trial =
+      new FieldTrial(name, kTotalProbability, group_name, 0, is_low_anonymity);
   // The group choice will be finalized in this method. So
   // |is_randomized_trial| should be false.
   FieldTrialList::Register(field_trial, /*is_randomized_trial=*/false);
@@ -832,21 +830,14 @@
 
 // static
 bool FieldTrialList::AddObserver(Observer* observer) {
-  if (!global_)
-    return false;
-  AutoLock auto_lock(global_->lock_);
-  global_->observers_.push_back(observer);
-  return true;
+  return FieldTrialList::AddObserverInternal(observer,
+                                             /*include_low_anonymity=*/false);
 }
 
 // static
 void FieldTrialList::RemoveObserver(Observer* observer) {
-  if (!global_)
-    return;
-  AutoLock auto_lock(global_->lock_);
-  Erase(global_->observers_, observer);
-  DCHECK_EQ(global_->num_ongoing_notify_field_trial_group_selection_calls_, 0)
-      << "Cannot call RemoveObserver while accessing FieldTrial::group_name().";
+  FieldTrialList::RemoveObserverInternal(observer,
+                                         /*include_low_anonymity=*/false);
 }
 
 // static
@@ -855,6 +846,7 @@
     return;
 
   std::vector<Observer*> local_observers;
+  std::vector<Observer*> local_observers_including_low_anonymity;
 
   {
     AutoLock auto_lock(global_->lock_);
@@ -870,9 +862,18 @@
     // lock. Since removing observers concurrently with this method is
     // disallowed, pointers should remain valid while observers are notified.
     local_observers = global_->observers_;
+    local_observers_including_low_anonymity =
+        global_->observers_including_low_anonymity_;
   }
 
-  for (Observer* observer : local_observers) {
+  if (!field_trial->is_low_anonymity_) {
+    for (Observer* observer : local_observers) {
+      observer->OnFieldTrialGroupFinalized(field_trial->trial_name(),
+                                           field_trial->group_name_internal());
+    }
+  }
+
+  for (Observer* observer : local_observers_including_low_anonymity) {
     observer->OnFieldTrialGroupFinalized(field_trial->trial_name(),
                                          field_trial->group_name_internal());
   }
@@ -1399,4 +1400,55 @@
   return true;
 }
 
+// static
+void FieldTrialList::GetActiveFieldTrialGroupsInternal(
+    FieldTrial::ActiveGroups* active_groups,
+    bool include_low_anonymity) {
+  DCHECK(active_groups->empty());
+  if (!global_) {
+    return;
+  }
+  AutoLock auto_lock(global_->lock_);
+
+  for (const auto& registered : global_->registered_) {
+    const FieldTrial& trial = *registered.second;
+    FieldTrial::ActiveGroup active_group;
+    if ((include_low_anonymity || !trial.is_low_anonymity_) &&
+        trial.GetActiveGroup(&active_group)) {
+      active_groups->push_back(active_group);
+    }
+  }
+}
+
+// static
+bool FieldTrialList::AddObserverInternal(Observer* observer,
+                                         bool include_low_anonymity) {
+  if (!global_) {
+    return false;
+  }
+  AutoLock auto_lock(global_->lock_);
+  if (include_low_anonymity) {
+    global_->observers_including_low_anonymity_.push_back(observer);
+  } else {
+    global_->observers_.push_back(observer);
+  }
+  return true;
+}
+
+// static
+void FieldTrialList::RemoveObserverInternal(Observer* observer,
+                                            bool include_low_anonymity) {
+  if (!global_) {
+    return;
+  }
+  AutoLock auto_lock(global_->lock_);
+  if (include_low_anonymity) {
+    Erase(global_->observers_including_low_anonymity_, observer);
+  } else {
+    Erase(global_->observers_, observer);
+  }
+  DCHECK_EQ(global_->num_ongoing_notify_field_trial_group_selection_calls_, 0)
+      << "Cannot call RemoveObserver while accessing FieldTrial::group_name().";
+}
+
 }  // namespace base
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index d62b550f..3560a83 100644
--- a/base/metrics/field_trial.h
+++ b/base/metrics/field_trial.h
@@ -99,6 +99,7 @@
 class ScopedFeatureList;
 }  // namespace test
 
+class CompareActiveGroupToFieldTrialMatcher;
 class FieldTrialList;
 struct LaunchOptions;
 
@@ -263,6 +264,12 @@
                                                StringPiece default_group_name,
                                                double entropy_value);
 
+  // Whether this field trial is low anonymity or not (see
+  // |FieldTrialListIncludingLowAnonymity|).
+  // TODO(crbug.com/1431156): remove this once all call sites have been properly
+  // migrated to use an appropriate observer.
+  bool is_low_anonymity() { return is_low_anonymity_; }
+
  private:
   // Allow tests to access our innards for testing purposes.
   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Registration);
@@ -290,6 +297,10 @@
   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, ClearParamsFromSharedMemory);
   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest,
                            TestGetRandomizedFieldTrialCount);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetLowAnonymity);
+
+  // MATCHER(CompareActiveGroupToFieldTrialMatcher, "")
+  friend class base::CompareActiveGroupToFieldTrialMatcher;
 
   friend class base::FieldTrialList;
 
@@ -307,7 +318,8 @@
   FieldTrial(StringPiece trial_name,
              Probability total_probability,
              StringPiece default_group_name,
-             double entropy_value);
+             double entropy_value,
+             bool is_low_anonymity);
 
   virtual ~FieldTrial();
 
@@ -384,6 +396,10 @@
   // Denotes whether benchmarking is enabled. In this case, field trials all
   // revert to the default group.
   static bool enable_benchmarking_;
+
+  // Whether this field trial is potentially low anonymity (eg. only a small
+  // set of users are included).
+  const bool is_low_anonymity_ = false;
 };
 
 //------------------------------------------------------------------------------
@@ -436,6 +452,10 @@
   // * SHA1 and NormalizedMurmurHash providers will use a non-zero value as a
   //   salt _instead_ of using the trial name.
   //
+  // Visibility of field trials with |is_low_anonymity| set to true is
+  // restricted to specific callers only, see
+  // |FieldTrialListIncludingLowAnonymity|.
+  //
   // This static method can be used to get a startup-randomized FieldTrial or a
   // previously created forced FieldTrial.
   static FieldTrial* FactoryGetFieldTrial(
@@ -443,7 +463,8 @@
       FieldTrial::Probability total_probability,
       StringPiece default_group_name,
       const FieldTrial::EntropyProvider& entropy_provider,
-      uint32_t randomization_seed = 0);
+      uint32_t randomization_seed = 0,
+      bool is_low_anonymity = false);
 
   // The Find() method can be used to test to see if a named trial was already
   // registered, or to retrieve a pointer to it from the global map.
@@ -486,6 +507,10 @@
   // called) with a snapshot of all registered FieldTrials for which the group
   // has been chosen and externally observed (via |group()|) and which have
   // not been disabled.
+  //
+  // This does not return low anonymity field trials. Callers who need access to
+  // low anonymity field trials should use
+  // |FieldTrialListIncludingLowAnonymity.GetActiveFieldTrialGroups()|.
   static void GetActiveFieldTrialGroups(
       FieldTrial::ActiveGroups* active_groups);
 
@@ -554,18 +579,30 @@
   // randomly selected state in a browser process into this non-browser process.
   // It returns NULL if there is a FieldTrial that is already registered with
   // the same |name| but has different finalized group string (|group_name|).
-  static FieldTrial* CreateFieldTrial(StringPiece name, StringPiece group_name);
+  //
+  // Visibility of field trials with |is_low_anonymity| set to true is
+  // restricted to specific callers only, see
+  // |FieldTrialListIncludingLowAnonymity|.
+  static FieldTrial* CreateFieldTrial(StringPiece name,
+                                      StringPiece group_name,
+                                      bool is_low_anonymity = false);
 
   // Add an observer to be notified when a field trial is irrevocably committed
   // to being part of some specific field_group (and hence the group_name is
   // also finalized for that field_trial). Returns false and does nothing if
   // there is no FieldTrialList singleton. The observer can be notified on any
   // sequence; it must be thread-safe.
+  //
+  // Low anonymity field trials are not notified to this observer. Callers
+  // who need to be notified of low anonymity field trials should use
+  // |FieldTrialListIncludingLowAnonymity.AddObserver()|.
   static bool AddObserver(Observer* observer);
 
   // Remove an observer. This cannot be invoked concurrently with
   // FieldTrial::group() (typically, this means that no other thread should be
   // running when this is invoked).
+  //
+  // Removes observers added via the |AddObserver()| method of this class.
   static void RemoveObserver(Observer* observer);
 
   // Notify all observers that a group has been finalized for |field_trial|.
@@ -646,6 +683,10 @@
   friend int SerializeSharedMemoryRegionMetadata();
   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, CheckReadOnlySharedMemoryRegion);
 
+  // Required so that |FieldTrialListIncludingLowAnonymity| can expose APIs from
+  // this class to its friends.
+  friend class FieldTrialListIncludingLowAnonymity;
+
 #if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_IOS)
   // Serialization is used to pass information about the shared memory handle
   // to child processes. This is achieved by passing a stringified reference to
@@ -730,9 +771,32 @@
   static bool CreateTrialsFromFieldTrialStatesInternal(
       const std::vector<FieldTrial::State>& entries);
 
+  // The same as |GetActiveFieldTrialGroups| but also gives access to low
+  // anonymity field trials.
+  // Restricted to specifically allowed friends - access via
+  // |FieldTrialListIncludingLowAnonymity::GetActiveFieldTrialGroups|.
+  static void GetActiveFieldTrialGroupsInternal(
+      FieldTrial::ActiveGroups* active_groups,
+      bool include_low_anonymity);
+
+  // The same as |AddObserver| but is notified for low anonymity field trials
+  // too.
+  // Restricted to specifically allowed friends - access via
+  // |FieldTrialListIncludingLowAnonymity::AddObserver|.
+  static bool AddObserverInternal(Observer* observer,
+                                  bool include_low_anonymity);
+
+  // The same as |RemoveObserver| but is notified for low anonymity field trials
+  // too.
+  // Restricted to specifically allowed friends - access via
+  // |FieldTrialListIncludingLowAnonymity::RemoveObserver|.
+  static void RemoveObserverInternal(Observer* observer,
+                                     bool include_low_anonymity);
+
   static FieldTrialList* global_;  // The singleton of this class.
 
   // Lock for access to |registered_|, |observers_|,
+  // |observers_including_low_anonymity_|,
   // |count_of_manually_created_field_trials_|.
   Lock lock_;
   RegistrationMap registered_ GUARDED_BY(lock_);
@@ -741,8 +805,13 @@
   size_t num_registered_randomized_trials_ GUARDED_BY(lock_) = 0;
 
   // List of observers to be notified when a group is selected for a FieldTrial.
+  // Excludes low anonymity field trials.
   std::vector<Observer*> observers_ GUARDED_BY(lock_);
 
+  // List of observers to be notified when a group is selected for a FieldTrial.
+  // Includes low anonymity field trials.
+  std::vector<Observer*> observers_including_low_anonymity_ GUARDED_BY(lock_);
+
   // Counts the ongoing calls to
   // FieldTrialList::NotifyFieldTrialGroupSelection(). Used to ensure that
   // RemoveObserver() isn't called while notifying observers.
diff --git a/base/metrics/field_trial_list_including_low_anonymity.cc b/base/metrics/field_trial_list_including_low_anonymity.cc
new file mode 100644
index 0000000..d672b86
--- /dev/null
+++ b/base/metrics/field_trial_list_including_low_anonymity.cc
@@ -0,0 +1,31 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/field_trial_list_including_low_anonymity.h"
+#include "base/metrics/field_trial.h"
+
+namespace base {
+
+// static
+void FieldTrialListIncludingLowAnonymity::GetActiveFieldTrialGroups(
+    FieldTrial::ActiveGroups* active_groups) {
+  return FieldTrialList::GetActiveFieldTrialGroupsInternal(
+      active_groups, /*include_low_anonymity=*/true);
+}
+
+// static
+bool FieldTrialListIncludingLowAnonymity::AddObserver(
+    FieldTrialList::Observer* observer) {
+  return FieldTrialList::AddObserverInternal(observer,
+                                             /*include_low_anonymity=*/true);
+}
+
+// static
+void FieldTrialListIncludingLowAnonymity::RemoveObserver(
+    FieldTrialList::Observer* observer) {
+  FieldTrialList::RemoveObserverInternal(observer,
+                                         /*include_low_anonymity=*/true);
+}
+
+}  // namespace base
diff --git a/base/metrics/field_trial_list_including_low_anonymity.h b/base/metrics/field_trial_list_including_low_anonymity.h
new file mode 100644
index 0000000..316e8a7
--- /dev/null
+++ b/base/metrics/field_trial_list_including_low_anonymity.h
@@ -0,0 +1,98 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_METRICS_FIELD_TRIAL_LIST_INCLUDING_LOW_ANONYMITY_H_
+#define BASE_METRICS_FIELD_TRIAL_LIST_INCLUDING_LOW_ANONYMITY_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/metrics/field_trial.h"
+#include "base/values.h"
+
+class AndroidFieldTrialListLogActiveTrialsFriendHelper;
+
+namespace content {
+class FieldTrialSynchronizer;
+}
+
+namespace variations {
+class ChildProcessFieldTrialSyncer;
+class EntropyProviders;
+class ProcessedStudy;
+struct SeedSimulationResult;
+class VariationsCrashKeys;
+class VariationsLayers;
+class VariationsSeedProcessorTestLowAnonymityHelper;
+SeedSimulationResult ComputeDifferences(
+    const std::vector<ProcessedStudy>& processed_studies,
+    const VariationsLayers& layers,
+    const EntropyProviders& entropy_providers);
+}  // namespace variations
+
+namespace version_ui {
+base::Value::List GetVariationsList();
+}
+
+namespace base {
+
+// Provides a way to restrict access to the full set of field trials, including
+// trials with low anonymity, to explicitly allowed callers.
+//
+// TODO(b/274900786): expose a public |GetActiveFieldTrialGroupsForTesting()| to
+// avoid requiring test code to be explicitly friended.
+// TODO(b/274900786): better document "low anonymity".
+class BASE_EXPORT FieldTrialListIncludingLowAnonymity {
+ public:
+  // Classes / functions which are allowed full access to all field trials
+  // should be listed as friends here, with a comment explaining why this does
+  // not risk revealing identifiable information externally.
+
+  // This is used only for local logging on Android.
+  friend class ::AndroidFieldTrialListLogActiveTrialsFriendHelper;
+
+  // Used to synchronize field trial status between the browser and child
+  // processes.
+  // Access to these trials within each of these is then allowed only to the
+  // other friend classes / methods listed here.
+  friend class content::FieldTrialSynchronizer;
+  friend class variations::ChildProcessFieldTrialSyncer;
+
+  // This is only used to simulate seed changes, not sent to Google servers.
+  friend variations::SeedSimulationResult variations::ComputeDifferences(
+      const std::vector<variations::ProcessedStudy>& processed_studies,
+      const variations::VariationsLayers& layers,
+      const variations::EntropyProviders& entropy_providers);
+
+  // Include all active field trials in crash reports, so that crashes are
+  // reproducible: https://www.google.com/intl/en/chrome/privacy/.
+  friend class variations::VariationsCrashKeys;
+
+  // This usage is to display field trials in chrome://version and other local
+  // internal UIs.
+  friend base::Value::List version_ui::GetVariationsList();
+
+  // Required for tests.
+  friend class TestFieldTrialObserverIncludingLowAnonymity;
+  friend class variations::VariationsSeedProcessorTestLowAnonymityHelper;
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest,
+                           GetActiveFieldTrialGroups_LowAnonymity);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ObserveIncludingLowAnonymity);
+
+ private:
+  // The same as |FieldTrialList::GetActiveFieldTrialGroups| but gives access to
+  // low anonymity field trials too.
+  static void GetActiveFieldTrialGroups(
+      FieldTrial::ActiveGroups* active_groups);
+
+  // Identical to |FieldTrialList::AddObserver| but also notifies of low
+  // anonymity trials.
+  static bool AddObserver(FieldTrialList::Observer* observer);
+
+  // Identical to |FieldTrialList::RemoveObserver| but for observers registered
+  // through the AddObserver() function of this class.
+  static void RemoveObserver(FieldTrialList::Observer* observer);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_FIELD_TRIAL_LIST_INCLUDING_LOW_ANONYMITY_H_
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
index 2699806..b1b4e426 100644
--- a/base/metrics/field_trial_unittest.cc
+++ b/base/metrics/field_trial_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial_list_including_low_anonymity.h"
 #include "base/metrics/field_trial_param_associator.h"
 #include "base/rand_util.h"
 #include "base/run_loop.h"
@@ -25,6 +26,7 @@
 #include "base/test/test_shared_memory_util.h"
 #include "base/test/test_timeouts.h"
 #include "build/build_config.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/multiprocess_func_list.h"
 
@@ -51,10 +53,12 @@
 scoped_refptr<FieldTrial> CreateFieldTrial(
     const std::string& trial_name,
     int total_probability,
-    const std::string& default_group_name) {
+    const std::string& default_group_name,
+    bool is_low_anonymity = false) {
   MockEntropyProvider entropy_provider(0.9);
   return FieldTrialList::FactoryGetFieldTrial(
-      trial_name, total_probability, default_group_name, entropy_provider);
+      trial_name, total_probability, default_group_name, entropy_provider, 0,
+      is_low_anonymity);
 }
 
 // A FieldTrialList::Observer implementation which stores the trial name and
@@ -116,6 +120,37 @@
 
 }  // namespace
 
+// Same as |TestFieldTrialObserver|, but registers for low anonymity field
+// trials too.
+class TestFieldTrialObserverIncludingLowAnonymity
+    : public FieldTrialList::Observer {
+ public:
+  TestFieldTrialObserverIncludingLowAnonymity() {
+    FieldTrialListIncludingLowAnonymity::AddObserver(this);
+  }
+  TestFieldTrialObserverIncludingLowAnonymity(
+      const TestFieldTrialObserverIncludingLowAnonymity&) = delete;
+  TestFieldTrialObserverIncludingLowAnonymity& operator=(
+      const TestFieldTrialObserverIncludingLowAnonymity&) = delete;
+
+  ~TestFieldTrialObserverIncludingLowAnonymity() override {
+    FieldTrialListIncludingLowAnonymity::RemoveObserver(this);
+  }
+
+  void OnFieldTrialGroupFinalized(const std::string& trial,
+                                  const std::string& group) override {
+    trial_name_ = trial;
+    group_name_ = group;
+  }
+
+  const std::string& trial_name() const { return trial_name_; }
+  const std::string& group_name() const { return group_name_; }
+
+ private:
+  std::string trial_name_;
+  std::string group_name_;
+};
+
 class FieldTrialTest : public ::testing::Test {
  public:
   FieldTrialTest() {
@@ -131,6 +166,13 @@
   test::ScopedFeatureList scoped_feature_list_;
 };
 
+MATCHER(CompareActiveGroupToFieldTrial, "") {
+  const base::FieldTrial::ActiveGroup& lhs = ::testing::get<0>(arg);
+  const base::FieldTrial* rhs = ::testing::get<1>(arg).get();
+  return lhs.trial_name == rhs->trial_name() &&
+         lhs.group_name == rhs->group_name_internal();
+}
+
 // Test registration, and also check that destructors are called for trials.
 TEST_F(FieldTrialTest, Registration) {
   const char name1[] = "name 1 test";
@@ -762,8 +804,8 @@
   for (int i = 0; i < kBucketCount; ++i) {
     const double entropy = i / static_cast<double>(kBucketCount);
 
-    scoped_refptr<FieldTrial> trial(
-        new FieldTrial("test", kBucketCount, "default", entropy));
+    scoped_refptr<FieldTrial> trial(new FieldTrial(
+        "test", kBucketCount, "default", entropy, /*is_low_anonymity=*/false));
     for (int j = 0; j < kBucketCount; ++j)
       trial->AppendGroup(NumberToString(j), 1);
 
@@ -775,8 +817,8 @@
   const double kEntropyValue = 1.0 - 1e-9;
   ASSERT_LT(kEntropyValue, 1.0);
 
-  scoped_refptr<FieldTrial> trial(
-      new FieldTrial("test", 2, "default", kEntropyValue));
+  scoped_refptr<FieldTrial> trial(new FieldTrial(
+      "test", 2, "default", kEntropyValue, /*is_low_anonymity=*/false));
   trial->AppendGroup("1", 1);
   trial->AppendGroup("2", 1);
 
@@ -1279,4 +1321,53 @@
             FieldTrialList::AllParamsToString(&MockEscapeQueryParamValue));
 }
 
+TEST_F(FieldTrialTest, GetActiveFieldTrialGroups_LowAnonymity) {
+  // Create a field trial with a single winning group.
+  scoped_refptr<FieldTrial> trial_1 = CreateFieldTrial("Normal", 10, "Default");
+  trial_1->AppendGroup("Winner 1", 10);
+  trial_1->Activate();
+
+  // Create a second field trial with a single winning group, marked as
+  // low-anonymity.
+  scoped_refptr<FieldTrial> trial_2 = CreateFieldTrial(
+      "Low anonymity", 10, "Default", /*is_low_anonymity=*/true);
+  trial_2->AppendGroup("Winner 2", 10);
+  trial_2->Activate();
+
+  // Check that |FieldTrialList::GetActiveFieldTrialGroups()| does not include
+  // the low-anonymity trial.
+  FieldTrial::ActiveGroups active_groups_for_metrics;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups_for_metrics);
+  EXPECT_THAT(
+      active_groups_for_metrics,
+      testing::UnorderedPointwise(CompareActiveGroupToFieldTrial(), {trial_1}));
+
+  // Check that
+  // |FieldTrialListIncludingLowAnonymity::GetActiveFieldTrialGroups()| includes
+  // both trials.
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialListIncludingLowAnonymity::GetActiveFieldTrialGroups(
+      &active_groups);
+  EXPECT_THAT(active_groups,
+              testing::UnorderedPointwise(CompareActiveGroupToFieldTrial(),
+                                          {trial_1, trial_2}));
+}
+
+TEST_F(FieldTrialTest, ObserveIncludingLowAnonymity) {
+  TestFieldTrialObserver observer;
+  TestFieldTrialObserverIncludingLowAnonymity low_anonymity_observer;
+
+  // Create a low-anonymity trial with one active group.
+  const char kTrialName[] = "TrialToObserve1";
+  scoped_refptr<FieldTrial> trial = CreateFieldTrial(
+      kTrialName, 100, kDefaultGroupName, /*is_low_anonymity=*/true);
+  trial->Activate();
+
+  // Only the low_anonymity_observer should be notified.
+  EXPECT_EQ("", observer.trial_name());
+  EXPECT_EQ("", observer.group_name());
+  EXPECT_EQ(kTrialName, low_anonymity_observer.trial_name());
+  EXPECT_EQ(kDefaultGroupName, low_anonymity_observer.group_name());
+}
+
 }  // namespace base
diff --git a/build/android/pylib/utils/device_dependencies.py b/build/android/pylib/utils/device_dependencies.py
index 8625d0e..5f3f1ed 100644
--- a/build/android/pylib/utils/device_dependencies.py
+++ b/build/android/pylib/utils/device_dependencies.py
@@ -8,7 +8,10 @@
 from pylib import constants
 
 _EXCLUSIONS = [
-    re.compile(r'.*OWNERS'),  # Should never be included.
+    # Misc files that exist to document directories
+    re.compile(r'.*METADATA'),
+    re.compile(r'.*OWNERS'),
+    re.compile(r'.*\.md'),
     re.compile(r'.*\.crx'),  # Chrome extension zip files.
     re.compile(r'.*/\.git.*'),  # Any '.git*' directories/files.
     re.compile(r'.*\.so'),  # Libraries packed into .apk.
@@ -16,6 +19,7 @@
     re.compile(r'.*\.py'),  # Some test_support targets include python deps.
     re.compile(r'.*\.apk'),  # Should be installed separately.
     re.compile(r'.*\.jar'),  # Never need java intermediates.
+    re.compile(r'.*\.crx'),  # Used by download_from_google_storage.
     re.compile(r'.*lib.java/.*'),  # Never need java intermediates.
 
     # Test filter files:
diff --git a/build/config/fuchsia/generate_runner_scripts.gni b/build/config/fuchsia/generate_runner_scripts.gni
index e745309..cf01659 100644
--- a/build/config/fuchsia/generate_runner_scripts.gni
+++ b/build/config/fuchsia/generate_runner_scripts.gni
@@ -15,7 +15,7 @@
   # Sets the Fuchsia Amber repository which will be used by default by the
   # generated installation scripts. If not specified, then no default directory
   # will be used.
-  default_fuchsia_build_dir_for_installation = ""
+  default_fuchsia_out_dir = ""
 
   # Sets the Fuchsia device node name which will be used by default by the
   # generated runner scripts. If not specficed, then no default node name will
@@ -62,9 +62,8 @@
 #                      --package - the path to a .FAR package to install.
 #                      --package_name - the name of the package to use as an
 #                                       entry point.
-#   include_fuchsia_build_dir: If true, adds
-#                              |default_fuchsia_build_dir_for_installation|
-#                              to executable_args (when set in GN args).
+#   include_fuchsia_out_dir: If true, adds |default_fuchsia_out_dir|
+#                            to executable_args (when set in GN args).
 template("fuchsia_run_script_with_packages") {
   if (defined(invoker.package_name)) {
     _pkg_shortname = invoker.package_name
@@ -82,7 +81,7 @@
                                  "executable",
                                  "executable_args",
                                  "data",
-                                 "include_fuchsia_build_dir",
+                                 "include_fuchsia_out_dir",
                                  "target",
                                ])
 
@@ -127,11 +126,11 @@
       executable_args = []
     }
 
-    if (defined(include_fuchsia_build_dir) && include_fuchsia_build_dir &&
-        default_fuchsia_build_dir_for_installation != "") {
+    if (defined(include_fuchsia_out_dir) && include_fuchsia_out_dir &&
+        default_fuchsia_out_dir != "") {
       executable_args += [
         "--fuchsia-out-dir",
-        default_fuchsia_build_dir_for_installation,
+        default_fuchsia_out_dir,
       ]
     }
   }
@@ -175,7 +174,7 @@
       pkg_shortname,
     ]
     output_name_format = "deploy_%package%"
-    include_fuchsia_build_dir = true
+    include_fuchsia_out_dir = true
   }
 }
 
diff --git a/build/config/ios/rules.gni b/build/config/ios/rules.gni
index dab03de..c6d4092 100644
--- a/build/config/ios/rules.gni
+++ b/build/config/ios/rules.gni
@@ -1627,6 +1627,11 @@
       ]
     }
 
+    # XCTestSupport framework is required as of Xcode 14.3 or later.
+    if (xcode_version_int >= 1430) {
+      extra_system_frameworks += [ "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestSupport.framework" ]
+    }
+
     _xctest_bundle = _xctest_target + "_bundle"
     if (!defined(bundle_deps)) {
       bundle_deps = []
@@ -1767,6 +1772,11 @@
       ]
     }
 
+    # XCTestSupport framework is required as of Xcode 14.3 or later.
+    if (xcode_version_int >= 1430) {
+      extra_system_frameworks += [ "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestSupport.framework" ]
+    }
+
     bundle_deps = []
     if (defined(invoker.bundle_deps)) {
       bundle_deps += invoker.bundle_deps
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index 7b710cc..fb69e2c 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-12.20230414.1.1
+12.20230415.3.1
diff --git a/build/fuchsia/test/common.py b/build/fuchsia/test/common.py
index 406af08..158b58ed 100644
--- a/build/fuchsia/test/common.py
+++ b/build/fuchsia/test/common.py
@@ -75,35 +75,17 @@
     raise NotImplementedError(f'State {state_str} not supported')
 
 
-def _retry(count: int, sleep: Optional[int] = None):
-    def first_func(func):
-        def wrapper(*args, **kwargs):
-            exception = None
-            for _ in range(count):
-                try:
-                    return func(*args, **kwargs)
-                # pylint: disable=broad-except
-                except Exception as generic_exception:
-                    exception = generic_exception
-                    logging.warning('Function %s failed. Retrying...',
-                                    str(func))
-                    if sleep:
-                        time.sleep(sleep)
-                # pylint: enable=broad-except
-            raise exception
-
-        return wrapper
-
-    return first_func
-
-
-@_retry(count=3, sleep=30)
-def get_target_state(target_id: Optional[str]) -> TargetState:
+def get_target_state(target_id: Optional[str],
+                     serial_num: Optional[str],
+                     num_attempts: int = 1) -> TargetState:
     """Return state of target or the default target.
 
     Args:
         target_id: Optional nodename of the target. If not given, default target
         is used.
+        serial_num: Optional serial number of target. Only usable if device is
+        in fastboot.
+        num_attempts: Optional number of times to attempt getting status.
 
     Returns:
         TargetState of the given node, if found.
@@ -112,24 +94,29 @@
         RuntimeError: If target cannot be found, or default target is not
             defined if |target_id| is not given.
     """
-    targets = json.loads(
-        run_ffx_command(('target', 'list'),
-                        configs=[_ENABLE_ZEDBOOT],
-                        check=True,
-                        capture_output=True,
-                        json_out=True).stdout.strip())
-    for target in targets:
-        if target_id is None and target['is_default']:
-            return _state_string_to_state(target['target_state'])
-        if target_id == target['nodename']:
-            return _state_string_to_state(target['target_state'])
+    for _ in range(num_attempts):
+        targets = json.loads(
+            run_ffx_command(('target', 'list'),
+                            check=True,
+                            configs=[_ENABLE_ZEDBOOT],
+                            capture_output=True,
+                            json_out=True).stdout.strip())
+        for target in targets:
+            if target_id is None and target['is_default']:
+                return _state_string_to_state(target['target_state'])
+            if target_id == target['nodename']:
+                return _state_string_to_state(target['target_state'])
+            if serial_num == target['serial']:
+                # Should only return Fastboot.
+                return _state_string_to_state(target['target_state'])
+        time.sleep(10)
 
     # Could not find a state for given target.
     error_target = target_id
     if target_id is None:
         error_target = 'default target'
 
-    raise RuntimeError(f'Could not find state for {error_target}')
+    raise RuntimeError(f'Could not find state for {error_target}.')
 
 
 def set_ffx_isolate_dir(isolate_dir: str) -> None:
@@ -483,6 +470,7 @@
 
 def boot_device(target_id: Optional[str],
                 mode: BootMode,
+                serial_num: Optional[str] = None,
                 must_boot: bool = False) -> None:
     """Boot device into desired mode, with fallback to SSH on failure.
 
@@ -492,9 +480,9 @@
         must_boot: Forces device to boot, regardless of current state.
     """
     # Skip boot call if already in the state and not skipping check.
+    state = get_target_state(target_id, serial_num, num_attempts=3)
+    wanted_state = _BOOTMODE_TO_STATE.get(mode)
     if not must_boot:
-        state = get_target_state(target_id)
-        wanted_state = _BOOTMODE_TO_STATE.get(mode)
         logging.debug('Current state %s. Want state %s', str(state),
                       str(wanted_state))
         must_boot = state != wanted_state
@@ -503,28 +491,66 @@
         logging.debug('Skipping boot - already in good state')
         return
 
-    _boot_device_ffx(target_id, mode)
-
-    exception = None
-    for _ in range(30):
-        try:
-            state = get_target_state(target_id)
-            if state == wanted_state:
-                return
-            raise RuntimeError('Mode is not correct. Expected '
-                               f'{wanted_state}, got {state}')
-        except RuntimeError as runtime_e:
-            exception = runtime_e
-            time.sleep(2)
-    if exception:
-        # Fallback to SSH, with no retry if we tried with ffx.
-        if state != _BOOTMODE_TO_STATE.get(mode):
-            _boot_device_dm(target_id, mode)
+    def _reboot(reboot_cmd, current_state: TargetState):
+        reboot_cmd()
+        # Check that we transition out of current state.
+        for _ in range(30):
+            try:
+                local_state = get_target_state(target_id, serial_num)
+                if local_state != current_state:
+                    # Changed states - can continue
+                    break
+            except RuntimeError:
+                logging.debug('Device disconnected...')
+                if current_state != TargetState.DISCONNECTED:
+                    # Changed states - can continue
+                    break
+            finally:
+                time.sleep(2)
         else:
-            raise exception
+            logging.warning(
+                'Device did not change from initial state. Exiting early')
+            return local_state or TargetState.DISCONNECTED
+
+        # Now we want to transition to the new state.
+        for _ in range(90):
+            try:
+                local_state = get_target_state(target_id, serial_num)
+                if local_state == wanted_state:
+                    return local_state
+            except RuntimeError:
+                logging.warning('Could not find target state.'
+                                ' Sleeping then retrying...')
+            finally:
+                time.sleep(2)
+        return local_state or TargetState.DISCONNECTED
+
+    state = _reboot(
+        (lambda: _boot_device_ffx(target_id, serial_num, state, mode)), state)
+
+    if state == TargetState.DISCONNECTED:
+        raise RuntimeError('Target could not be found!')
+
+    if state == wanted_state:
+        return
+
+    logging.warning(
+        'Booting with FFX to %s did not succeed. Attempting with DM', mode)
+
+    # Fallback to SSH, with no retry if we tried with ffx.:
+    _boot_device_dm(target_id, serial_num, state, mode)
+    state = _reboot(
+        (lambda: _boot_device_dm(target_id, serial_num, state, mode)), state)
+
+    if state != wanted_state:
+        raise RuntimeError(
+            f'Could not get device to desired state. Wanted {wanted_state},'
+            f' got {state}')
+    logging.debug('Got desired state: %s', state)
 
 
-def _boot_device_ffx(target_id: Optional[str], mode: BootMode):
+def _boot_device_ffx(target_id: Optional[str], serial_num: Optional[str],
+                     current_state: TargetState, mode: BootMode):
     cmd = ['target', 'reboot']
     if mode == BootMode.REGULAR:
         logging.info('Triggering regular boot')
@@ -535,17 +561,27 @@
     else:
         raise NotImplementedError(f'BootMode {mode} not supported')
 
-    run_ffx_command(cmd,
-                    target_id=target_id,
-                    configs=[_ENABLE_ZEDBOOT],
-                    check=False)
+    logging.debug('FFX reboot with command [%s]', ' '.join(cmd))
+    if current_state == TargetState.FASTBOOT:
+
+        run_ffx_command(cmd,
+                        configs=[_ENABLE_ZEDBOOT],
+                        target_id=serial_num,
+                        check=False)
+    else:
+        run_ffx_command(cmd,
+                        configs=[_ENABLE_ZEDBOOT],
+                        target_id=target_id,
+                        check=False)
 
 
-def _boot_device_dm(target_id: Optional[str], mode: BootMode):
+def _boot_device_dm(target_id: Optional[str], serial_num: Optional[str],
+                    current_state: TargetState, mode: BootMode):
     # Can only use DM if device is in regular boot.
-    state = get_target_state(target_id)
-    if state != TargetState.PRODUCT:
-        _boot_device_ffx(target_id, mode.REGULAR)
+    if current_state != TargetState.PRODUCT:
+        # Boot to regular.
+        _boot_device_ffx(target_id, serial_num, current_state,
+                         BootMode.REGULAR)
         if mode == BootMode.REGULAR:
             return
 
@@ -564,4 +600,5 @@
 
     # Boot commands can fail due to SSH connections timeout.
     full_cmd = ssh_prefix + ['--', 'dm', reboot_cmd]
+    logging.debug('DM reboot with command [%s]', ' '.join(full_cmd))
     subprocess.run(full_cmd, check=False)
diff --git a/build/fuchsia/test/flash_device.py b/build/fuchsia/test/flash_device.py
index b50272b..fd3750e 100755
--- a/build/fuchsia/test/flash_device.py
+++ b/build/fuchsia/test/flash_device.py
@@ -27,9 +27,13 @@
 _FF_LOCK_ACQ_TIMEOUT = _FF_LOCK_STALE_SECS
 
 
-def _get_system_info(target: Optional[str]) -> Tuple[str, str]:
+def _get_system_info(target: Optional[str],
+                     serial_num: Optional[str]) -> Tuple[str, str]:
     """Retrieves installed OS version from device.
 
+    Args:
+        target: Target to get system info of.
+        serial_num: Serial number of device to get system info of.
     Returns:
         Tuple of strings, containing (product, version number).
     """
@@ -37,7 +41,11 @@
     # TODO(b/242191374): Remove when devices in swarming are no longer booted
     # into zedboot.
     if running_unattended():
-        boot_device(target, BootMode.REGULAR)
+        try:
+            boot_device(target, BootMode.REGULAR, serial_num)
+        except (subprocess.CalledProcessError, RuntimeError):
+            logging.warning('Could not boot device. Assuming in ZEDBOOT')
+            return ('', '')
         wait_cmd = common.run_ffx_command(('target', 'wait', '-t', '180'),
                                           target,
                                           check=False)
@@ -47,8 +55,11 @@
     return get_system_info(target)
 
 
-def update_required(os_check, system_image_dir: Optional[str],
-                    target: Optional[str]) -> Tuple[bool, Optional[str]]:
+def update_required(
+        os_check,
+        system_image_dir: Optional[str],
+        target: Optional[str],
+        serial_num: Optional[str] = None) -> Tuple[bool, Optional[str]]:
     """Returns True if a system update is required and path to image dir."""
 
     if os_check == 'ignore':
@@ -67,7 +78,8 @@
                 'be found')
         system_image_dir = path
     if (os_check == 'check'
-            and get_sdk_hash(system_image_dir) == _get_system_info(target)):
+            and get_sdk_hash(system_image_dir) == _get_system_info(
+                target, serial_num)):
         return False, system_image_dir
     return True, system_image_dir
 
@@ -117,27 +129,16 @@
         ])
 
 
-def _remove_stale_flash_file_lock() -> None:
-    """Check if flash file lock is stale, and delete if so."""
-    try:
-        stat = os.stat(_FF_LOCK)
-        if time.time() - stat.st_mtime > _FF_LOCK_STALE_SECS:
-            os.remove(_FF_LOCK)
-    except FileNotFoundError:
-        logging.info('No lock file found - assuming it is up for grabs')
-
-
 def flash(system_image_dir: str,
           target: Optional[str],
           serial_num: Optional[str] = None) -> None:
     """Flash the device."""
-    _remove_stale_flash_file_lock()
     # Flash only with a file lock acquired.
     # This prevents multiple fastboot binaries from flashing concurrently,
     # which should increase the odds of flashing success.
     with lock(_FF_LOCK, timeout=_FF_LOCK_ACQ_TIMEOUT):
         if serial_num:
-            boot_device(target, BootMode.BOOTLOADER)
+            boot_device(target, BootMode.BOOTLOADER, serial_num)
             for _ in range(10):
                 time.sleep(10)
                 if common.run_ffx_command(('target', 'list', serial_num),
@@ -164,7 +165,8 @@
         should_pave: Optional bool on whether or not to pave or flash.
     """
     needs_update, actual_image_dir = update_required(os_check,
-                                                     system_image_dir, target)
+                                                     system_image_dir, target,
+                                                     serial_num)
 
     system_image_dir = actual_image_dir
     if needs_update:
@@ -176,7 +178,7 @@
                 # TODO(crbug.com/1405525): We should check the device state
                 # before and after rebooting it to avoid unnecessary reboot or
                 # undesired state.
-                boot_device(target, BootMode.RECOVERY)
+                boot_device(target, BootMode.RECOVERY, serial_num)
             try:
                 pave(system_image_dir, target)
                 time.sleep(180)
diff --git a/build/fuchsia/test/flash_device_unittests.py b/build/fuchsia/test/flash_device_unittests.py
index a1c72e3b..485be549 100755
--- a/build/fuchsia/test/flash_device_unittests.py
+++ b/build/fuchsia/test/flash_device_unittests.py
@@ -76,7 +76,7 @@
                 self.assertLogs():
             mock_find.return_value = 'path/to/image/dir'
             update_required, new_image_dir = flash_device.update_required(
-                'update', 'product-bundle', None)
+                'update', 'product-bundle', None, None)
             self.assertTrue(update_required)
             self.assertEqual(new_image_dir, 'path/to/image/dir')
             mock_find.assert_called_once_with('product-bundle')
@@ -115,6 +115,31 @@
             self.assertEqual(self._ffx_mock.call_count, 1)
             self.assertEqual(self._sdk_hash_mock.call_count, 1)
 
+    def test_update_system_info_catches_boot_failure(self) -> None:
+        """Test update when |os_check=check| catches boot_device exceptions."""
+
+        self._swarming_mock.return_value = True
+        with mock.patch('os.path.exists', return_value=True), \
+                mock.patch('flash_device._add_exec_to_flash_binaries'), \
+                mock.patch('flash_device.boot_device') as mock_boot, \
+                mock.patch('flash_device.get_system_info') as mock_sys_info, \
+                mock.patch('flash_device.subprocess.run'):
+            mock_boot.side_effect = RuntimeError('Incorrect state')
+            self._ffx_mock.return_value.stdout = \
+                '[{"title": "Build", "child": [{"value": "wrong.version"}, ' \
+                '{"value": "wrong_product"}]}]'
+            flash_device.update(_TEST_IMAGE_DIR,
+                                'check',
+                                None,
+                                should_pave=False)
+            # Regular boot is to check the versions.
+            mock_boot.assert_called_once_with(mock.ANY,
+                                              common.BootMode.REGULAR, None)
+            self.assertEqual(self._ffx_mock.call_count, 1)
+
+            # get_system_info should not even be called due to early exit.
+            mock_sys_info.assert_not_called()
+
     def test_update_system_info_mismatch(self) -> None:
         """Test update when |os_check| is 'check' and system info does not
         match."""
@@ -133,7 +158,7 @@
                                 should_pave=False)
             # Regular boot is to check the versions.
             mock_boot.assert_called_once_with(mock.ANY,
-                                              common.BootMode.REGULAR)
+                                              common.BootMode.REGULAR, None)
             self.assertEqual(self._ffx_mock.call_count, 3)
 
     def test_update_system_info_mismatch_adds_exec_to_flash_binaries(self
@@ -209,7 +234,8 @@
                                 'test_serial',
                                 should_pave=False)
             mock_boot.assert_called_once_with(mock.ANY,
-                                              common.BootMode.BOOTLOADER)
+                                              common.BootMode.BOOTLOADER,
+                                              'test_serial')
         self.assertEqual(self._ffx_mock.call_count, 3)
 
     def test_reboot_failure(self) -> None:
@@ -239,14 +265,14 @@
                                 should_pave=True)
 
             mock_boot.assert_called_once_with('some-target-id',
-                                              common.BootMode.RECOVERY)
+                                              common.BootMode.RECOVERY, None)
             mock_pave.assert_called_once_with(_TEST_IMAGE_DIR,
                                               'some-target-id')
 
     # pylint: enable=no-self-use
 
     def test_update_raises_error_if_unattended_with_no_target(self) -> None:
-        """Test update calls pave if specified."""
+        """Test update raises error if no target specified."""
 
         self._swarming_mock.return_value = True
         with mock.patch('time.sleep'), \
@@ -274,7 +300,8 @@
                                 'test_serial',
                                 should_pave=False)
             mock_boot.assert_called_once_with(mock.ANY,
-                                              common.BootMode.BOOTLOADER)
+                                              common.BootMode.BOOTLOADER,
+                                              'test_serial')
         self.assertEqual(self._ffx_mock.call_count, 2)
 
     # pylint: disable=no-self-use
@@ -300,38 +327,6 @@
             mock_flash.assert_called_once_with(_TEST_IMAGE_DIR,
                                                'some-target-id', None)
 
-    def test_remove_stale_removes_stale_file_lock(self) -> None:
-        """Test remove_stale_flash_file_lock removes stale file lock."""
-        with mock.patch('time.time') as mock_time, \
-             mock.patch('os.remove') as mock_remove, \
-             mock.patch('os.stat') as mock_stat:
-            mock_time.return_value = 60 * 20
-            # Set st_mtime
-            mock_stat.return_value = os.stat_result((0, ) * 8 + (100, 0))
-            flash_device._remove_stale_flash_file_lock()
-            mock_stat.assert_called_once_with(flash_device._FF_LOCK)
-            mock_remove.assert_called_once_with(flash_device._FF_LOCK)
-
-    def test_remove_stale_does_not_remove_non_stale_file(self) -> None:
-        """Test remove_stale_flash_file_lock does not remove fresh file."""
-        with mock.patch('time.time') as mock_time, \
-             mock.patch('os.remove') as mock_remove, \
-             mock.patch('os.stat') as mock_stat:
-            mock_time.return_value = 60 * 10
-            # Set st_mtime
-            mock_stat.return_value = os.stat_result((0, ) * 8 + (100, 0))
-            flash_device._remove_stale_flash_file_lock()
-            mock_remove.assert_not_called()
-
-    def test_remove_stale_does_not_raise_file_not_found(self) -> None:
-        """Test remove_stale_flash_file_lock does not raise FileNotFound."""
-        with mock.patch('time.time'), \
-             mock.patch('os.remove'), \
-             mock.patch('os.stat') as mock_stat:
-            mock_stat.side_effect = FileNotFoundError
-            flash_device._remove_stale_flash_file_lock()
-            mock_stat.assert_called_once_with(flash_device._FF_LOCK)
-
     # pylint: enable=no-self-use
 
     def test_main(self) -> None:
diff --git a/build/rust/run_bindgen.py b/build/rust/run_bindgen.py
index 8f80a3c..467da9e 100755
--- a/build/rust/run_bindgen.py
+++ b/build/rust/run_bindgen.py
@@ -54,7 +54,6 @@
 
   # Bindgen settings we use for Chromium
   genargs.append('--no-layout-tests')
-  genargs.append('--size_t-is-usize')
   # TODO(danakj): We need to point bindgen to
   # //third_party/rust-toolchain/bin/rustfmt.
   genargs.append('--no-rustfmt-bindings')
diff --git a/buildtools/deps_revisions.gni b/buildtools/deps_revisions.gni
index 774b3f7..4355068a 100644
--- a/buildtools/deps_revisions.gni
+++ b/buildtools/deps_revisions.gni
@@ -5,5 +5,5 @@
 declare_args() {
   # Used to cause full rebuilds on libc++ rolls. This should be kept in sync
   # with the libcxx_revision vars in //DEPS.
-  libcxx_revision = "5488b5c294dd4b9640adbef628f2dcd6f85a6c09"
+  libcxx_revision = "7df372d6fd11d11382866df8f549b352ef2a6520"
 }
diff --git a/cc/input/main_thread_scrolling_reason.h b/cc/input/main_thread_scrolling_reason.h
index 7bb2f73..4290b5d8 100644
--- a/cc/input/main_thread_scrolling_reason.h
+++ b/cc/input/main_thread_scrolling_reason.h
@@ -40,6 +40,8 @@
     kHasBackgroundAttachmentFixedObjects = 1 << 2,
     kThreadedScrollingDisabled = 1 << 3,
     kPopupNoThreadedInput = 1 << 4,
+    kPreferNonCompositedScrolling = 1 << 15,
+    kBackgroundNeedsRepaintOnScroll = 1 << 16,
 
     // Style-related scrolling on main reasons. Subpixel (LCD) text rendering
     // requires blending glyphs with the background at a specific screen
@@ -62,8 +64,13 @@
     kWheelEventHandlerRegion = 1 << 13,
     kTouchEventHandlerRegion = 1 << 14,
 
+    // The following reasons are listed above so they are grouped with other
+    // non-transient scrolling reasons:
+    // kPreferNonCompositedScrolling = 1 << 15,
+    // kBackgroundNeedsRepaintOnScroll = 1 << 16,
+
     // For blink::RecordScrollReasonsMetric() to know the number of used bits.
-    kMainThreadScrollingReasonLast = 14,
+    kMainThreadScrollingReasonLast = 16,
   };
 
   static const uint32_t kNonCompositedReasons =
@@ -74,7 +81,9 @@
   static bool MainThreadCanSetScrollReasons(uint32_t reasons) {
     constexpr uint32_t reasons_set_by_main_thread =
         kHasBackgroundAttachmentFixedObjects | kThreadedScrollingDisabled |
-        kPopupNoThreadedInput | kNonCompositedReasons;
+        kPopupNoThreadedInput | kPreferNonCompositedScrolling |
+        kBackgroundNeedsRepaintOnScroll | kNotOpaqueForTextAndLCDText |
+        kCantPaintScrollingBackgroundAndLCDText;
     return (reasons & reasons_set_by_main_thread) == reasons;
   }
 
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index e0483e1..b08bcff2 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -573,7 +573,11 @@
   transform.Translate(position_adjustment -
                       node->scroll_offset.OffsetFromOrigin());
   transform.Translate(StickyPositionOffset(node));
-  transform.Translate(AnchorScrollOffset(node));
+  if (node->anchor_scroll_containers_data_id >= 0) {
+    transform.Translate(AnchorScrollOffset(node));
+    // Make sure the damage rect is tracked.
+    node->transform_changed = true;
+  }
   transform.PreConcat(node->local);
   transform.Translate3d(gfx::Point3F() - node->origin);
 
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index b0110cee..d7b49d2 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -2352,6 +2352,50 @@
     ]
   }
 
+  # Defines a target that derives from the chrome public application. This
+  # can be either an APK or an app bundle module. This supports
+  # chrome_public_xxx targets (for Android L-M). For Android N+, see instead
+  # monochrome_public_apk_or_module_tmpl() below.
+  #
+  # Variables:
+  #  target_type: Determines the final target type. Should be one of
+  #    'android_apk', or 'android_app_bundle_module'.
+  #  apk_name: For 'android_apk' target types, name of the final APK without
+  #    an .apk suffix (e.g. 'ChromePublic').
+  #  is_base_module: For 'android_app_bundle_module' target types only,
+  #     set to true to indicate that this is a base application module
+  #     (instead of a feature module).
+  template("chrome_public_apk_or_module_tmpl") {
+    _is_bundle_module = invoker.target_type == "android_app_bundle_module"
+    chrome_public_common_apk_or_module_tmpl(target_name) {
+      forward_variables_from(invoker,
+                             [
+                               "add_view_trace_events",
+                               "apk_name",
+                               "bundle_target",
+                               "is_base_module",
+                               "target_type",
+                               "enable_lint",
+                               "enable_multidex",
+                               "lint_baseline_file",
+                               "lint_suppressions_dep",
+                               "lint_suppressions_file",
+                               "manual_jni_registration",
+                             ])
+      deps = chrome_public_shared_deps
+
+      if (_is_bundle_module) {
+        deps += [ ":chrome_bundle_module_pak_assets" ]
+      } else {
+        deps += [ ":chrome_apk_pak_assets" ]
+      }
+
+      shared_libraries = [ ":libchrome" ]
+
+      version_name = chrome_version_name
+    }
+  }
+
   chrome_public_apk_or_module_tmpl("chrome_public_apk") {
     target_type = "android_apk"
     apk_name = "ChromePublic"
@@ -2504,6 +2548,83 @@
     annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
   }
 
+  # Defines a target that derives from the monochrome public application. This
+  # can be either an APK or an app bundle module. Note that these only work
+  # on Android N+ devices, see chrome_public_apk_or_module_tmpl() for a template
+  # that supports generating targets for older Android releases.
+  #
+  # Variables:
+  #   target_type: Either 'android_apk' or 'android_app_bundle_module'.
+  #   apk_name: For APK target types, the final APK name without an .apk
+  #     suffix (e.g. "MonochromePublic").
+  #   is_base_module: For module target types, a boolean indicating whether
+  #     this is a base bundle module (instead of a feature one).
+  #   is_64_bit_browser: When compiling in a 64-bit configuration, a boolean
+  #     indicating whether the browser is 64-bit or 32-bit.
+  #   include_32_bit_webview: When compiling a 64-bit browser configuration, if
+  #     true, a 32-bit WebView library will also be built and included.
+  template("monochrome_public_apk_or_module_tmpl") {
+    _is_trichrome = defined(invoker.is_trichrome) && invoker.is_trichrome
+    _is_bundle = invoker.target_type == "android_app_bundle_module"
+
+    monochrome_public_common_apk_or_module_tmpl(target_name) {
+      forward_variables_from(invoker,
+                             [
+                               "add_view_trace_events",
+                               "apk_name",
+                               "bundle_target",
+                               "expected_android_manifest",
+                               "include_32_bit_webview",
+                               "include_64_bit_webview",
+                               "is_64_bit_browser",
+                               "is_base_module",
+                               "is_trichrome",
+                               "resource_ids_provider_dep",
+                               "static_library_provider",
+                               "target_type",
+                               "use_chromium_linker",
+                             ])
+
+      if (!_is_trichrome) {
+        # Resource allowlist used when generating R.java files and causes
+        # only the webview subset of resources to be marked as non-final.
+        # Strings in this target will also be kept in the base apk rather than placed in the language splits.
+        shared_resources_allowlist_target =
+            "//android_webview:system_webview_no_weblayer_apk"
+
+        # Ensure the localized resources for all locales are used, even when
+        # a smaller set is specified through aapt_locale_allowlist.
+        shared_resources_allowlist_locales = platform_pak_locales
+      }
+
+      deps = []
+      if (_is_bundle) {
+        deps += [
+          "//chrome/android:chrome_base_module_resources",
+
+          # deps in delegate_public_impl_java are put into the Chrome module, but the language deps
+          # are needed by the base module.
+          "//components/language/android:ulp_delegate_public_java",
+        ]
+      } else {
+        deps += [ ":delegate_public_impl_java" ]
+      }
+      if (!_is_trichrome) {
+        deps += [
+          "//android_webview:platform_service_bridge_upstream_implementation_java",
+          "//android_webview/nonembedded:icon_resources",
+          "//android_webview/nonembedded:monochrome_devui_launcher_icon_resources",
+        ]
+        if (!_is_bundle) {
+          deps += [ ":monochrome_java" ]
+        }
+        if (webview_includes_weblayer) {
+          deps += [ "//weblayer/browser/java:upstream_java" ]
+        }
+      }
+    }
+  }
+
   if (android_64bit_target_cpu && skip_secondary_abi_for_cq) {
     group("trichrome_library_apk") {
       deps = [ ":trichrome_library_64_apk" ]
@@ -2512,8 +2633,7 @@
       deps = [ ":monochrome_64_public_apk" ]
     }
   } else {
-    chrome_public_apk_or_module_tmpl("monochrome_public_apk") {
-      is_monochrome = true
+    monochrome_public_apk_or_module_tmpl("monochrome_public_apk") {
       apk_name = "MonochromePublic"
       target_type = "android_apk"
       if (android_64bit_target_cpu) {
@@ -2552,8 +2672,7 @@
   }
 
   if (android_64bit_target_cpu) {
-    chrome_public_apk_or_module_tmpl("monochrome_64_public_apk") {
-      is_monochrome = true
+    monochrome_public_apk_or_module_tmpl("monochrome_64_public_apk") {
       apk_name = "MonochromePublic64"
       target_type = "android_apk"
       is_64_bit_browser = true
@@ -2731,7 +2850,48 @@
         include_32_bit_webview = !skip_secondary_abi_for_cq
       }
 
-      deps = [ ":chrome_test_ar_java" ]
+      # This is where we would add the shared_libraries entry for
+      # :libchromefortest in the non-Monochrome version. However, doing so in the
+      # Monochrome version causes Chrome to crash on startup due to being unable
+      # to load the library, and looking at the libraries included in the APK
+      # shows both libchromefortest and libmonochrome, when only one should be
+      # present. The tests currently work fine with just libmonochrome, so keep
+      # it this way until we actually need the test-only library. This may be
+      # related to monochrome_public_common_apk_or_module_tmpl adding its own
+      # shared libraries, but chrome_public_common_apk_or_module_tmpl not. See
+      # https://crbug.com/974017.
+      deps = [
+        ":chrome_test_ar_java",
+        "//third_party/android_sdk:android_test_mock_java",
+      ]
+
+      # Include ArCore files directly instead of using bundles. This does
+      # require us to explicitly re-declare our dependency on ARCore, which
+      # otherwise should have already been included, since the native libraries
+      # need to know that it is available. Though we'd always need to forcibly
+      # include the manifest DEP here as well
+      deps += [
+        "//third_party/arcore-android-sdk-client:com_google_ar_core_java",
+        "//third_party/arcore-android-sdk-client:com_google_ar_core_java__ignored_manifest",
+      ]
+
+      _libarcore_dir = get_label_info(
+                           "//third_party/arcore-android-sdk-client:com_google_ar_core_java($default_toolchain)",
+                           "target_out_dir") + "/com_google_ar_core_java/jni"
+
+      # We store this as a separate .so in the APK and only load as needed.
+      if (android_64bit_target_cpu) {
+        if (skip_secondary_abi_for_cq) {
+          loadable_modules = [ "$_libarcore_dir/arm64-v8a/libarcore_sdk_c.so" ]
+        } else {
+          secondary_abi_loadable_modules =
+              [ "$_libarcore_dir/armeabi-v7a/libarcore_sdk_c.so" ]
+        }
+      } else {
+        loadable_modules = [ "$_libarcore_dir/armeabi-v7a/libarcore_sdk_c.so" ]
+      }
+
+      additional_apks = [ "//net/android:net_test_support_apk" ]
     }
   }
 
@@ -2954,19 +3114,22 @@
     ]
   }
 
-  template("chrome_bundle_tmpl") {
-    _is_monochrome = defined(invoker.is_monochrome) && invoker.is_monochrome
-    _is_trichrome = defined(invoker.is_trichrome) && invoker.is_trichrome
-    assert(_is_monochrome || _is_trichrome, "TODO: https://crbug.com/1426950")
-
+  template("monochrome_or_trichrome_public_bundle_tmpl") {
     _base_module_target_name = "${invoker.target_name}__base_bundle_module"
-    chrome_public_apk_or_module_tmpl(_base_module_target_name) {
+    _is_trichrome = defined(invoker.is_trichrome) && invoker.is_trichrome
+
+    if (_is_trichrome) {
+      _bundle_name = "TrichromeChrome${invoker.bundle_suffix}"
+    } else {
+      _bundle_name = "MonochromePublic${invoker.bundle_suffix}"
+    }
+
+    monochrome_public_apk_or_module_tmpl(_base_module_target_name) {
       forward_variables_from(invoker,
                              [
                                "add_view_trace_events",
                                "expected_android_manifest",
                                "is_64_bit_browser",
-                               "is_monochrome",
                                "is_trichrome",
                                "include_32_bit_webview",
                                "include_64_bit_webview",
@@ -2974,6 +3137,7 @@
                                "resource_ids_provider_dep",
                              ])
       target_type = "android_app_bundle_module"
+      is_base_module = true
       bundle_target = ":${invoker.target_name}"
 
       if (defined(invoker.expected_android_manifest_template)) {
@@ -2992,7 +3156,6 @@
                                "include_32_bit_webview",
                                "include_64_bit_webview",
                                "is_64_bit_browser",
-                               "is_monochrome",
                                "is_trichrome",
                                "lint_baseline_file",
                                "lint_min_sdk_version",
@@ -3002,19 +3165,20 @@
                                "expected_libs_and_assets",
                                "expected_proguard_config",
                              ])
+      is_monochrome = !_is_trichrome
       base_module_target = ":$_base_module_target_name"
+      bundle_name = _bundle_name
       manifest_package = chrome_public_manifest_package
-      if (_is_trichrome) {
-        bundle_name = "TrichromeChrome${invoker.bundle_suffix}"
-        module_descs = chrome_module_descs
-      } else if (_is_monochrome) {
-        bundle_name = "MonochromePublic${invoker.bundle_suffix}"
+      if (is_monochrome) {
         module_descs = monochrome_module_descs
+      } else {
+        module_descs = chrome_module_descs
       }
       chrome_deps = [ ":delegate_public_impl_java" ]
       if (!_is_trichrome) {
         chrome_deps += [ "//chrome/android:monochrome_java" ]
       }
+
       if (!is_java_debug) {
         proguard_android_sdk_dep = webview_framework_dep
       }
@@ -3043,9 +3207,7 @@
   } else {
     # Public webview targets don't work with non-public sdks.
     # https://crbug.com/1000763
-    chrome_bundle_tmpl("monochrome_public_bundle") {
-      is_monochrome = true
-
+    monochrome_or_trichrome_public_bundle_tmpl("monochrome_public_bundle") {
       # Monochrome bundle is used as our unified lint target, so it needs to set the
       # lowest shipping minSdkVersion to catch all potential NewApi errors.
       lint_min_sdk_version = default_min_sdk_version
@@ -3085,7 +3247,7 @@
       }
     }
 
-    chrome_bundle_tmpl("trichrome_chrome_bundle") {
+    monochrome_or_trichrome_public_bundle_tmpl("trichrome_chrome_bundle") {
       bundle_suffix = ""
       is_trichrome = true
       static_library_provider = ":trichrome_library_apk"
@@ -3198,14 +3360,13 @@
   }
 
   if (android_64bit_target_cpu) {
-    chrome_bundle_tmpl("monochrome_64_public_bundle") {
-      is_monochrome = true
+    monochrome_or_trichrome_public_bundle_tmpl("monochrome_64_public_bundle") {
       bundle_suffix = "64"
       is_64_bit_browser = true
       include_32_bit_webview = false
     }
 
-    chrome_bundle_tmpl("trichrome_chrome_64_bundle") {
+    monochrome_or_trichrome_public_bundle_tmpl("trichrome_chrome_64_bundle") {
       is_trichrome = true
       bundle_suffix = "64"
       is_64_bit_browser = true
@@ -3218,21 +3379,22 @@
     }
 
     if (!skip_secondary_abi_for_cq) {
-      chrome_bundle_tmpl("monochrome_32_public_bundle") {
-        is_monochrome = true
+      monochrome_or_trichrome_public_bundle_tmpl(
+          "monochrome_32_public_bundle") {
         bundle_suffix = "32"
         is_64_bit_browser = false
         include_64_bit_webview = false
       }
 
-      chrome_bundle_tmpl("monochrome_64_32_public_bundle") {
-        is_monochrome = true
+      monochrome_or_trichrome_public_bundle_tmpl(
+          "monochrome_64_32_public_bundle") {
         bundle_suffix = "6432"
         is_64_bit_browser = true
         include_32_bit_webview = true
       }
 
-      chrome_bundle_tmpl("trichrome_chrome_64_32_bundle") {
+      monochrome_or_trichrome_public_bundle_tmpl(
+          "trichrome_chrome_64_32_bundle") {
         is_trichrome = true
         bundle_suffix = "6432"
         is_64_bit_browser = true
@@ -3243,7 +3405,7 @@
               "expectations/$target_name.$target_cpu.libs_and_assets.expected"
         }
       }
-      chrome_bundle_tmpl("trichrome_chrome_32_bundle") {
+      monochrome_or_trichrome_public_bundle_tmpl("trichrome_chrome_32_bundle") {
         is_trichrome = true
         bundle_suffix = "32"
         is_64_bit_browser = false
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 6494241c..28fe242 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -43,8 +43,12 @@
   "zygote_preload_class=org.chromium.content_public.app.ZygotePreload",
 ]
 
-monochrome_android_manifest_jinja_variables =
-    [ "sandboxed_service_exported=true" ]
+monochrome_android_manifest_jinja_variables = [
+  "sandboxed_service_exported=true",
+
+  # TODO(crbug.com/1411557): Remove.
+  use_32bit_abi_jinja_variable,
+]
 
 # Generates an AndroidManifest.xml along with an optional second manifest
 # dependent on the original.
@@ -105,6 +109,8 @@
 # Variables:
 #   target_type: Either 'android_apk' or 'android_app_bundle_module'.
 #   apk_name: For APK target types, the final APK name without a suffix.
+#   is_base_module: For bundle module target types, true iff this is a base
+#     application module, instead of a feature module.
 #   shared_libraries: List of native shared libraries targets to include in
 #     the final target (e.g. [ ":libchrome" ]).
 #   is_monochrome: Indicates that this target contains chrome and webview
@@ -118,35 +124,29 @@
 #   Plus all other variables accepted by android_apk() or
 #   android_app_bundle_module(), depending on the target type.
 #
-template("chrome_common_apk_or_module_tmpl") {
-  _target_type = invoker.target_type
-  assert(_target_type == "android_apk" ||
-         _target_type == "android_app_bundle_module" ||
-         _target_type == "instrumentation_test_apk")
+template("chrome_public_common_apk_or_module_tmpl") {
+  assert(
+      invoker.target_type == "android_apk" ||
+          invoker.target_type == "android_app_bundle_module" ||
+          invoker.target_type == "instrumentation_test_apk",
+      "Invalid target_type definition, should be 'android_apk' or 'android_app_bundle_module'")
 
   _is_monochrome = defined(invoker.is_monochrome) && invoker.is_monochrome
   _is_trichrome = defined(invoker.is_trichrome) && invoker.is_trichrome
-  _is_bundle = _target_type == "android_app_bundle_module"
+  _is_bundle = invoker.target_type == "android_app_bundle_module"
 
-  _is_64_bit_browser =
-      android_64bit_target_cpu &&
-      (!defined(invoker.is_64_bit_browser) || invoker.is_64_bit_browser)
   if (_is_trichrome || _is_monochrome) {
     _include_64_bit_webview =
         android_64bit_target_cpu && (!defined(invoker.include_64_bit_webview) ||
                                      invoker.include_64_bit_webview)
     _include_32_bit_webview = !defined(invoker.include_32_bit_webview) ||
                               invoker.include_32_bit_webview
-    _include_primary_abi = !android_64bit_target_cpu || _is_64_bit_browser ||
-                           _include_64_bit_webview
-    _include_secondary_abi = android_64bit_target_cpu &&
-                             (!_is_64_bit_browser || _include_32_bit_webview)
-    if (_include_secondary_abi) {
-      _secondary_out_dir =
-          get_label_info("X($android_secondary_abi_toolchain)", "root_out_dir")
-      not_needed([ "_secondary_out_dir" ])
-    }
   }
+  _is_64_bit_browser =
+      android_64bit_target_cpu &&
+      (!defined(invoker.is_64_bit_browser) || invoker.is_64_bit_browser)
+  _is_secondary_abi_primary = !_is_64_bit_browser && android_64bit_target_cpu
+  not_needed([ "_is_secondary_abi_primary" ])
 
   assert(!(_is_monochrome && _is_trichrome),
          "Cannot be both trichrome and monochrome!")
@@ -154,6 +154,12 @@
          "If trichrome library is used, static_library_provider must be set " +
              "so that a dep can be added on the library APK.")
 
+  if (!defined(invoker.target_type)) {
+    _target_type = "android_apk"
+  } else {
+    _target_type = invoker.target_type
+  }
+
   if (_is_trichrome) {
     _version_code = TRICHROME_VERSION_MAP["${android_64bit_target_cpu}_${_is_64_bit_browser}_${_include_64_bit_webview}_${_include_32_bit_webview}"]
   } else if (_is_monochrome) {
@@ -163,139 +169,104 @@
     _version_code = chrome_modern_version_code
   }
 
-  if (defined(invoker.manifest_package)) {
-    _manifest_package = invoker.manifest_package
-  } else {
-    _manifest_package = chrome_public_manifest_package
-  }
-
-  _android_manifest = "$target_gen_dir/$target_name/AndroidManifest.xml"
-  _split_android_manifest =
-      "$target_gen_dir/$target_name/AndroidManifest_split.xml"
-  _android_manifest_target_name = "${target_name}__android_manifest"
-  split_manifest_template(_android_manifest_target_name) {
-    definitions_in_split = _is_bundle
-    split_input = "//chrome/android/java/AndroidManifest_split.xml"
-    split_output = _split_android_manifest
-    includes = []
-    output = _android_manifest
-    variables = default_chrome_public_jinja_variables +
-                [ "manifest_package=$_manifest_package" ]
-    if (_is_trichrome) {
-      input = "//chrome/android/java/AndroidManifest_trichrome_chrome.xml"
-      includes = [ "//chrome/android/java/AndroidManifest.xml" ]
-      variables +=
-          trichrome_jinja_variables + [ "trichrome_version=$_version_code" ]
-    } else if (_is_monochrome) {
-      input = "//chrome/android/java/AndroidManifest_monochrome.xml"
-      includes = [
-        "//android_webview/nonembedded/java/AndroidManifest.xml",
-        "//chrome/android/java/AndroidManifest.xml",
-      ]
-      variables += monochrome_android_manifest_jinja_variables
-      if (_is_64_bit_browser) {
-        variables += [ "webview_library=libmonochrome_64.so" ]
-      } else {
-        variables += [ "webview_library=libmonochrome.so" ]
-      }
+  # TODO(crbug.com/1411557): Remove option for custom manifest.
+  if (!defined(invoker.android_manifest)) {
+    if (defined(invoker.manifest_package)) {
+      _manifest_package = invoker.manifest_package
     } else {
-      input = "//chrome/android/java/AndroidManifest.xml"
+      _manifest_package = chrome_public_manifest_package
     }
-    if (_is_monochrome || _is_trichrome) {
-      _force_32_bit = _include_32_bit_webview && _include_64_bit_webview &&
-                      !_is_64_bit_browser
-      variables += [
-        "force_32_bit=$_force_32_bit",
-        "include_arcore_manifest_flag=$enable_arcore",
-      ]
-    }
-    if (defined(invoker.jinja_input)) {
-      includes += [ input ]
-      input = invoker.jinja_input
-    }
-    if (defined(invoker.jinja_extra_variables)) {
-      variables += invoker.jinja_extra_variables
-    }
-    if (defined(invoker.jinja_extra_includes)) {
-      includes += invoker.jinja_extra_includes
+
+    _android_manifest = "$target_gen_dir/$target_name/AndroidManifest.xml"
+
+    # TODO(crbug.com/1411557): Move out of manifest/ when downstream is updated.
+    # _split.xml is used in chrome_bundle template.
+    _split_android_manifest =
+        "$target_gen_dir/manifest/$target_name/AndroidManifest_split.xml"
+    _android_manifest_target_name = "${target_name}__android_manifest"
+    split_manifest_template(_android_manifest_target_name) {
+      definitions_in_split = _is_bundle
+      split_input = "//chrome/android/java/AndroidManifest_split.xml"
+      split_output = _split_android_manifest
+      includes = []
+      output = _android_manifest
+      variables = default_chrome_public_jinja_variables +
+                  [ "manifest_package=$_manifest_package" ]
+      if (_is_trichrome) {
+        input = "//chrome/android/java/AndroidManifest_trichrome_chrome.xml"
+        includes = [ "//chrome/android/java/AndroidManifest.xml" ]
+        variables +=
+            trichrome_jinja_variables + [ "trichrome_version=$_version_code" ]
+      } else if (_is_monochrome) {
+        input = "//chrome/android/java/AndroidManifest_monochrome.xml"
+        includes = [
+          "//android_webview/nonembedded/java/AndroidManifest.xml",
+          "//chrome/android/java/AndroidManifest.xml",
+        ]
+        variables += monochrome_android_manifest_jinja_variables
+        if (_is_64_bit_browser) {
+          variables += [ "webview_library=libmonochrome_64.so" ]
+        } else {
+          variables += [ "webview_library=libmonochrome.so" ]
+        }
+      } else {
+        input = "//chrome/android/java/AndroidManifest.xml"
+      }
+      if (_is_monochrome || _is_trichrome) {
+        _force_32_bit = _include_32_bit_webview && _include_64_bit_webview &&
+                        !_is_64_bit_browser
+        variables += [
+          "force_32_bit=$_force_32_bit",
+          "include_arcore_manifest_flag=$enable_arcore",
+        ]
+
+        # TODO(crbug.com/1411557): Remove block.
+        if (_is_64_bit_browser) {
+          variables -= [ use_32bit_abi_jinja_variable ]
+        }
+      }
+      if (defined(invoker.jinja_input)) {
+        includes += [ input ]
+        input = invoker.jinja_input
+      }
+      if (defined(invoker.jinja_extra_variables)) {
+        variables += invoker.jinja_extra_variables
+      }
+      if (defined(invoker.jinja_extra_includes)) {
+        includes += invoker.jinja_extra_includes
+      }
     }
   }
   target(_target_type, target_name) {
-    android_manifest = _android_manifest
-    android_manifest_dep = ":$_android_manifest_target_name"
-    manifest_package = _manifest_package
+    forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
+    forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
 
-    if (defined(invoker.min_sdk_version)) {
-      min_sdk_version = invoker.min_sdk_version
-    } else if (_is_trichrome) {
+    if (!defined(assert_no_deps)) {
+      assert_no_deps = []
+    }
+
+    # https://crbug.com/1415351
+    assert_no_deps += [
+      "//third_party/androidx:androidx_window_extensions_core_core_java",
+      "//third_party/androidx:androidx_window_sidecar_sidecar_java",
+      "//third_party/androidx:androidx_window_window_java_java",
+    ]
+
+    # TODO(crbug.com/1411557): Do not allows custom manifest dep.
+    if (defined(_android_manifest_target_name)) {
+      android_manifest = _android_manifest
+      android_manifest_dep = ":$_android_manifest_target_name"
+      manifest_package = _manifest_package
+    }
+
+    if (!defined(min_sdk_version) && _is_trichrome) {
       min_sdk_version = 29
     }
-    if (defined(invoker.version_name)) {
-      version_name = invoker.version_name
-    } else {
-      version_name = chrome_version_name
-    }
-    if (defined(invoker.version_code)) {
-      # Override for the actual versionCode, but not for trichrome_version.
-      version_code = invoker.version_code
-    } else {
-      version_code = _version_code
-    }
-    if (defined(invoker.expected_android_manifest)) {
+    if (defined(expected_android_manifest)) {
       expected_android_manifest_version_code_offset = chrome_version_code
       expected_android_manifest_library_version_offset = chrome_version_code
     }
 
-    if (_target_type == "android_apk") {
-      command_line_flags_file = "chrome-command-line"
-    }
-
-    if (_is_bundle) {
-      is_base_module = true
-
-      # Sets ISOLATED_SPLITS_ENABLED in BuildConfig.java.
-      isolated_splits_enabled = true
-    }
-
-    product_config_java_packages = [ "org.chromium.chrome.browser" ]
-
-    if (_is_monochrome) {
-      alternative_android_sdk_dep = webview_framework_dep
-      app_as_shared_lib = true
-
-      # Resource allowlist used when generating R.java files and causes
-      # only the webview subset of resources to be marked as non-final.
-      # Strings in this target will also be kept in the base apk rather than placed in the language splits.
-      shared_resources_allowlist_target =
-          "//android_webview:system_webview_no_weblayer_apk"
-
-      # Ensure the localized resources for all locales are used, even when
-      # a smaller set is specified through aapt_locale_allowlist.
-      shared_resources_allowlist_locales = platform_pak_locales
-
-      product_config_java_packages += [ webview_product_config_java_package ]
-
-      if (webview_includes_weblayer) {
-        product_config_java_packages += [ weblayer_product_config_java_package ]
-      }
-    }
-
-    if (enable_silent_java_assert_reporting) {
-      custom_assertion_handler = crash_reporting_assertion_handler
-    }
-
-    if (allow_jni_multiplexing) {
-      enable_jni_multiplexing = true
-    }
-
-    # TODO(agrieve): Make this the default for apks with minSdkVersion > 21.
-    if (_is_monochrome || _is_trichrome) {
-      no_xml_namespaces = true
-    }
-
-    # Include resource strings files only for supported locales.
-    aapt_locale_allowlist = platform_pak_locales
-
     resource_exclusion_regex = common_resource_exclusion_regex
     resource_exclusion_exceptions = common_resource_exclusion_exceptions
 
@@ -305,7 +276,7 @@
       "*ic_lock.*",  # Bottom edge seems misaligned.
     ]
 
-    # Most of these, with the exception of resource_exclusion_exceptions,
+    # Note most of these, with the exception of resource_exclusion_exceptions,
     # are currently duplicated in system_webview_apk_tmpl.gni.
 
     # Used only by alert dialog on tiny screens.
@@ -319,259 +290,256 @@
     # Instead of manually filtering, unused resource removal would be better:
     # https://crbug.com/636448
     resource_exclusion_regex += "|${_material_package}/xml.*badge_"
+    _material_package = "*com_google_android_material*"
 
-    if (!is_java_debug) {
-      # Android supports webp transparent resources properly since API level 18,
-      # so this can only be activated for modern ones (which target API >= 21).
-      png_to_webp = true
+    if (!_is_monochrome) {
+      product_config_java_packages = [ "org.chromium.chrome.browser" ]
+    }
 
-      proguard_enabled = true
-      proguard_configs = [ "//chrome/android/proguard/main.flags" ]
-      if (_is_monochrome) {
-        proguard_configs +=
-            [ "//android_webview/nonembedded/java/proguard.flags" ]
-      }
-      if (defined(invoker.proguard_configs)) {
-        proguard_configs += invoker.proguard_configs
-      }
+    # Android supports webp transparent resources properly since API level 18,
+    # so this can only be activated for modern ones (which target API >= 21).
+    if (!defined(png_to_webp)) {
+      png_to_webp = !is_java_debug
+    }
 
-      # We only optimize resources for bundles since APKs are not shipped.
-      # Resources only live in the base module atm as such we only need to set
-      # these on the base module
-      if (_is_bundle) {
-        # Removes metadata needed for Resources.getIdentifier("resource_name").
-        strip_resource_names = true
+    # We only optimize resources for bundles since APKs are not shipped.
+    # Resources only live in the base module atm as such we only need to set
+    # these on the base module
+    if (_is_bundle) {
+      # Removes metadata needed for Resources.getIdentifier("resource_name").
+      strip_resource_names = !is_java_debug
 
-        # Shortens resource file names in apk eg: res/drawable/button.xml -> res/a.xml
-        short_resource_paths = true
+      # Shortens resource file names in apk eg: res/drawable/button.xml -> res/a.xml
+      short_resource_paths = !is_java_debug
 
-        # Removes unused resources from the apk. Only enabled on official builds
-        # since it adds a slow step and serializes the build graph causing fewer
-        # expensive tasks (eg: proguarding, resource optimization) to be run in
-        # parallel by adding dependencies between them (adds around 10-20
-        # seconds on my machine).
-        strip_unused_resources = is_official_build
+      # Removes unused resources from the apk. Only enabled on official builds
+      # since it adds a slow step and serializes the build graph causing fewer
+      # expensive tasks (eg: proguarding, resource optimization) to be run in
+      # parallel by adding dependencies between them (adds around 10-20
+      # seconds on my machine).
+      strip_unused_resources = is_official_build
+    }
 
-        # Resources config for blocklisting resource names from obfuscation
-        resources_config_paths = [ "//chrome/android/aapt2.config" ]
-        if (_is_monochrome || _is_trichrome) {
-          resources_config_paths += [ "//android_webview/aapt2.config" ]
-        }
-        if (defined(invoker.resources_config_paths)) {
-          resources_config_paths += invoker.resources_config_paths
+    if (!defined(aapt_locale_allowlist)) {
+      # Include resource strings files only for supported locales.
+      aapt_locale_allowlist = platform_pak_locales
+    }
+
+    if (!defined(use_chromium_linker)) {
+      # The Chromium Linker depends on ASharedMemory_create() introduced in O.
+      use_chromium_linker = chromium_linker_supported && _is_trichrome
+    }
+
+    if (_is_trichrome) {
+      static_library_provider_use_secondary_abi = _is_secondary_abi_primary
+
+      # http://crbug.com/1042107.
+      if (is_component_build) {
+        if (android_64bit_target_cpu && _is_64_bit_browser) {
+          main_component_library = "libmonochrome_64.cr.so"
+        } else {
+          main_component_library = "libmonochrome.cr.so"
         }
       }
     }
 
-    deps = [
-      "//chrome/android:chrome_base_module_resources",
-      "//chrome/android:chrome_public_non_pak_assets",
-    ]
-
-    # TODO(agrieve): Make uncondtional when moving to trampoline.
-    if (_is_monochrome || _is_trichrome) {
-      deps += [ "//components/crash/android:handler_java" ]
-    }
-    if (_is_monochrome) {
-      deps += [ "//chrome/android:base_monochrome_module_java" ]
-    } else {
-      deps += [ "//chrome/android:base_module_java" ]
-    }
-    if (defined(invoker.deps)) {
-      deps += invoker.deps
-    }
-
-    if (!_is_trichrome) {
-      # These go in trichrome library.
+    if (!_is_monochrome && !_is_trichrome) {
       deps += [
+        "//components/crash/core/app:chrome_crashpad_handler_named_as_so",
         "//gin:v8_snapshot_assets",
         "//third_party/icu:icu_assets",
       ]
+      if (!defined(loadable_modules)) {
+        loadable_modules = []
+      }
+      loadable_modules += [ "$root_out_dir/libchrome_crashpad_handler.so" ]
+      if (!defined(library_always_compress)) {
+        library_always_compress = []
+      }
+      library_always_compress += [
+        "libchrome_crashpad_handler.so",
+        "libchromium_android_linker.so",
+      ]
+    }
 
-      # TODO(agrieve): This is excluded from trichrome in preparation for
-      # "synchronized proguarding", which we've since abandoned. Enable for
-      # trichrome, or just remove the version check altogether.
+    if (dfmify_dev_ui && !_is_bundle) {
+      # Dev UI is a feature in a DFM, and APKs don't use DFMs. To make the code
+      # available for APKs add a dependency on it.
+      deps += [ "//chrome/android/features/dev_ui:java" ]
+    }
+    if (enable_vr && !_is_bundle) {
+      # VR is a feature in a DFM, and APKs don't use DFMs, but we
+      # unconditionally include vr code in our native library. To make the code
+      # available for APKs, add a dependency on it.
+      deps += [ "//chrome/android/features/vr:java" ]
+    }
+
+    if (!is_java_debug) {
+      proguard_enabled = true
+      if (!defined(proguard_configs)) {
+        proguard_configs = []
+      }
+      proguard_configs += [ "//chrome/android/proguard/main.flags" ]
+    }
+
+    if (use_chromium_linker) {
+      if (_is_secondary_abi_primary) {
+        _secondary_linker = "//base/android/linker:chromium_android_linker($android_secondary_abi_toolchain)"
+        deps += [ _secondary_linker ]
+        _secondary_out_dir = get_label_info(_secondary_linker, "root_out_dir")
+        secondary_abi_loadable_modules +=
+            [ "$_secondary_out_dir/libchromium_android_linker$shlib_extension" ]
+      } else {
+        deps += [ "//base/android/linker:chromium_android_linker" ]
+        loadable_modules +=
+            [ "$root_out_dir/libchromium_android_linker$shlib_extension" ]
+      }
+    }
+    if (build_with_internal_optimization_guide) {
+      if (_is_secondary_abi_primary) {
+        _secondary_optimization_guide = "//components/optimization_guide/internal:optimization_guide_internal($android_secondary_abi_toolchain)"
+        deps += [ _secondary_optimization_guide ]
+        _secondary_out_dir =
+            get_label_info(_secondary_optimization_guide, "root_out_dir")
+        secondary_abi_loadable_modules +=
+            [ "$_secondary_out_dir/liboptimization_guide_internal.so" ]
+      } else {
+        deps += [ "//components/optimization_guide/internal:optimization_guide_internal" ]
+        loadable_modules +=
+            [ "$root_out_dir/liboptimization_guide_internal.so" ]
+      }
+    }
+    if (_target_type == "android_apk") {
+      command_line_flags_file = "chrome-command-line"
+    }
+    if (!_is_trichrome) {
       build_config_include_product_version_resource = true
       deps += [ "//chrome/android:product_version_resources" ]
     }
 
+    if (!_is_bundle || !(_is_monochrome || _is_trichrome)) {
+      deps += [ "//chrome/android:chrome_all_java" ]
+    }
+
     if (_is_bundle) {
       # Required to support macro resources.
       # See https://crbug.com/1278419
       deps += [ ":${target_name}__all_dfm_resources" ]
-    } else {
-      # For bundles, this exists in the "chrome" split.
-      deps += [ "//chrome/android:chrome_all_java" ]
-
-      if (dfmify_dev_ui) {
-        # For bundles, Dev UI is a feature in a DFM.
-        deps += [ "//chrome/android/features/dev_ui:java" ]
-      }
-      if (enable_vr) {
-        # For bundles, VR is a feature in a DFM.
-        deps += [ "//chrome/android/features/vr:java" ]
-      }
-    }
-
-    if (_is_monochrome) {
-      deps += [
-        "//android_webview/glue:glue_java",
-        "//android_webview/nonembedded:monochrome_devui_launcher_icon_resources",
-        "//android_webview/nonembedded:nonembedded_java",
-      ]
-
-      # For bundles, this lives in chrome split.
-      if (!_is_bundle) {
-        deps += [ "//chrome/android:monochrome_java" ]
-      }
-
-      if (_include_primary_abi) {
-        deps += [ "//android_webview:monochrome_webview_primary_abi_assets" ]
-      }
-      if (_include_secondary_abi) {
-        deps += [ "//android_webview:monochrome_webview_secondary_abi_assets" ]
-      }
-    }
-
-    if (_is_bundle && _is_monochrome) {
-      deps += [ "//chrome/android:monochrome_bundle_module_pak_assets" ]
-    } else if (_is_bundle && _is_trichrome) {
-      deps += [ "//chrome/android:trichrome_chrome_bundle_module_pak_assets" ]
-    } else if (_is_bundle) {
-      deps += [ "//chrome/android:chrome_bundle_module_pak_assets" ]
-    } else if (_is_monochrome) {
-      deps += [ "//chrome/android:monochrome_apk_pak_assets" ]
-    } else {
-      assert(!_is_trichrome)
-      deps += [ "//chrome/android:chrome_apk_pak_assets" ]
-    }
-
-    if (defined(invoker.add_upstream_only_deps) &&
-        invoker.add_upstream_only_deps) {
-      if (_is_monochrome) {
-        deps += upstream_only_webview_deps
-      } else if (!_is_trichrome) {
-        deps += [
-          "//chrome/android:chrome_public_apk_base_module_resources",
-          "//chrome/android:chrome_public_base_module_java",
-          "//chrome/android:chrome_public_non_pak_assets",
-          "//components/browser_ui/styles/android:chrome_public_apk_resources",
-        ]
-      }
-      if (_is_bundle) {
-        deps += [
-          # deps in delegate_public_impl_java are put into the Chrome module, but the language deps
-          # are needed by the base module.
-          "//components/language/android:ulp_delegate_public_java",
-        ]
-      } else {
-        deps += [ "//chrome/android:delegate_public_impl_java" ]
-      }
-    }
-
-    # https://crbug.com/1415351
-    assert_no_deps = [
-      "//third_party/androidx:androidx_window_extensions_core_core_java",
-      "//third_party/androidx:androidx_window_sidecar_sidecar_java",
-      "//third_party/androidx:androidx_window_window_java_java",
-    ]
-    if (defined(invoker.assert_no_deps)) {
-      assert_no_deps += invoker.assert_no_deps
     }
 
     # Unwind tables are included in the stack_unwinder DFM on Android, so they
     # aren't needed for bundle builds. However, we keep them for non-bundle
     # builds, such as test and development apks (e.g. chrome_public_apk), to
     # allow tests and developers to use them directly.
-    if (!defined(invoker.shared_libraries) && !_is_bundle &&
-        add_unwind_tables_in_chrome_32bit_apk &&
-        (target_cpu == "arm" ||
-         (target_cpu == "arm64" && !_is_64_bit_browser))) {
-      if (_is_monochrome || _is_trichrome) {
-        deps += [ "//chrome/android:libmonochrome_unwind_table_assets" ]
-      } else {
-        deps += [ "//chrome/android:libchrome_unwind_table_assets" ]
-      }
-    }
+    if (!_is_bundle && add_unwind_tables_in_chrome_32bit_apk) {
+      _needs_32bit_lib =
+          target_cpu == "arm" || ((_is_monochrome || _is_trichrome) &&
+                                  target_cpu == "arm64" && !_is_64_bit_browser)
 
-    data_deps = []
-    if (defined(invoker.data_deps)) {
-      data_deps += invoker.data_deps
+      if (_needs_32bit_lib) {
+        if (_is_monochrome || _is_trichrome) {
+          deps += [ "//chrome/android:libmonochrome_unwind_table_assets" ]
+        } else {
+          deps += [ "//chrome/android:libchrome_unwind_table_assets" ]
+        }
+      }
     }
 
     # Prefer to add this data_dep on the final target instead of java targets
     # like chrome_all_java so that all other targets can build in parallel with
     # lint.
     if (!disable_android_lint) {
+      if (!defined(data_deps)) {
+        data_deps = []
+      }
       data_deps += [ "//chrome/android:android_lint" ]
     }
 
-    shared_libraries = []
-    loadable_modules = []
-    if (android_64bit_target_cpu) {
-      secondary_abi_shared_libraries = []
-      secondary_abi_loadable_modules = []
-    }
-    if (defined(invoker.loadable_modules)) {
-      loadable_modules = invoker.loadable_modules
-    }
-    if (defined(invoker.secondary_abi_loadable_modules)) {
-      secondary_abi_loadable_modules = invoker.secondary_abi_loadable_modules
+    if (enable_silent_java_assert_reporting) {
+      custom_assertion_handler = crash_reporting_assertion_handler
     }
 
-    if (_is_64_bit_browser && build_hwasan_splits) {
-      _hwasan_toolchain = "//build/toolchain/android:android_clang_arm64_hwasan"
+    if (allow_jni_multiplexing) {
+      enable_jni_multiplexing = true
     }
 
-    if (defined(invoker.shared_libraries)) {
-      shared_libraries += invoker.shared_libraries
-    } else if (_is_monochrome) {
-      if (android_64bit_target_cpu) {
-        # Build //android_webview:monochrome with the opposite bitness that
-        # Chrome runs in.
-        if (_is_64_bit_browser) {
-          shared_libraries += [ "//chrome/android:libmonochrome_64" ]
-          if (_include_32_bit_webview) {
-            secondary_abi_shared_libraries += [ "//android_webview:monochrome_64($android_secondary_abi_toolchain)" ]
-          }
-          if (build_hwasan_splits) {
-            shared_libraries +=
-                [ "//chrome/android:libmonochrome_64($_hwasan_toolchain)" ]
-          }
-        } else {
-          if (_include_64_bit_webview) {
-            shared_libraries += [ "//android_webview:monochrome" ]
-          }
-          secondary_abi_shared_libraries += [
-            "//chrome/android:libmonochrome($android_secondary_abi_toolchain)",
-          ]
-        }
-      } else {
-        shared_libraries += [ "//chrome/android:libmonochrome" ]
+    if (!defined(version_name)) {
+      version_name = chrome_version_name
+    }
+    version_code = _version_code
+
+    # Override for the actual versionCode, but not for trichrome_version.
+    if (defined(invoker.version_code)) {
+      version_code = invoker.version_code
+    }
+  }
+}
+
+# The equivalent of chrome_common_apk_or_module_tmpl for all builds of
+# monochrome and trichrome chrome.
+template("monochrome_public_common_apk_or_module_tmpl") {
+  chrome_public_common_apk_or_module_tmpl(target_name) {
+    _overrides = {
+      _is_bundle_module = defined(invoker.target_type) &&
+                          invoker.target_type == "android_app_bundle_module"
+
+      if (_is_bundle_module) {
+        assert(
+            defined(invoker.is_base_module),
+            "_is_bundle_module is true but the invoker does not define is_base_module!")
       }
-    } else if (!_is_trichrome) {
-      shared_libraries += [ "//chrome/android:libchrome" ]
-    }
 
-    # TODO(agrieve): Enable for chrome_public_apk as well.
-    if (enable_arcore && (_is_monochrome || _is_trichrome)) {
-      # The arcore manifest needs to be merged into the base module because
-      # the Play Store verifies the com.google.ar.core.min_apk_version
-      # meta-data tag is in the base manifest.
-      deps += [
-        "//third_party/arcore-android-sdk-client:com_google_ar_core_java",
-        "//third_party/arcore-android-sdk-client:com_google_ar_core_java__ignored_manifest",
+      is_trichrome = defined(invoker.is_trichrome) && invoker.is_trichrome
+      is_monochrome = !is_trichrome
+
+      shared_libraries = []
+      if (defined(invoker.shared_libraries)) {
+        shared_libraries += invoker.shared_libraries
+      }
+      secondary_abi_shared_libraries = []
+      if (defined(invoker.secondary_abi_shared_libraries)) {
+        secondary_abi_shared_libraries += invoker.secondary_abi_shared_libraries
+      }
+      loadable_modules = []
+      if (defined(invoker.loadable_modules)) {
+        loadable_modules = invoker.loadable_modules
+      }
+      secondary_abi_loadable_modules = []
+      if (defined(invoker.secondary_abi_loadable_modules)) {
+        secondary_abi_loadable_modules = invoker.secondary_abi_loadable_modules
+      }
+      native_lib_placeholders = []
+      if (defined(invoker.native_lib_placeholders)) {
+        native_lib_placeholders = invoker.native_lib_placeholders
+      }
+      secondary_native_lib_placeholders = []
+      if (defined(invoker.secondary_native_lib_placeholders)) {
+        secondary_native_lib_placeholders =
+            invoker.secondary_native_lib_placeholders
+      }
+
+      deps = [
+        "//chrome/android:chrome_public_non_pak_assets",
+        "//components/crash/android:handler_java",
       ]
+      if (defined(invoker.deps)) {
+        deps += invoker.deps
+      }
 
-      # For Trichrome, the native library is added to TrichromeLibrary.apk so
-      # it's not needed here.
-      if (!_is_trichrome) {
-        _arcore_target = "//third_party/arcore-android-sdk-client:com_google_ar_core_J__unpack_aar"
-        _libarcore_dir = get_label_info(_arcore_target, "target_out_dir") +
-                         "/com_google_ar_core_java/jni"
+      if (_is_bundle_module && invoker.is_base_module && enable_arcore &&
+          is_monochrome) {
+        # AR DFM is disabled - set the loadable_modules /
+        # secondary_abi_loadable_modules to what would be brought in by the
+        # module. The AR Java will be brought in by the chrome_bundle target.
+        # This needs to happen for monochrome builds of base module if ARCore is
+        # enabled. For Trichrome, the native library is added to
+        # TrichromeLibrary.apk so it's not needed here.
+        _libarcore_dir = get_label_info(
+                             "//third_party/arcore-android-sdk-client:com_google_ar_core_java($default_toolchain)",
+                             "target_out_dir") + "/com_google_ar_core_java/jni"
 
         if (android_64bit_target_cpu) {
-          if (_is_64_bit_browser) {
+          if (invoker.is_64_bit_browser) {
             loadable_modules +=
                 [ "$_libarcore_dir/arm64-v8a/libarcore_sdk_c.so" ]
           } else {
@@ -583,138 +551,234 @@
               [ "$_libarcore_dir/armeabi-v7a/libarcore_sdk_c.so" ]
         }
       }
-    }
-    library_always_compress = []
-    if (defined(invoker.library_always_compress)) {
-      library_always_compress = invoker.library_always_compress
-    }
 
-    # TODO(agrieve): Use Crashpad trampoline in chrome_public_apk.
-    if (!_is_monochrome && !_is_trichrome) {
-      deps +=
-          [ "//components/crash/core/app:chrome_crashpad_handler_named_as_so" ]
-      loadable_modules += [ "$root_out_dir/libchrome_crashpad_handler.so" ]
-      library_always_compress += [ "libchrome_crashpad_handler.so" ]
-    } else if (!_is_trichrome) {
-      # Crashpad trampoline lives in TrichromeLibrary.apk.
-      # https://chromium.googlesource.com/chromium/src/+/main/docs/android_native_libraries.md#Crashpad-Packaging
-      if (_include_primary_abi) {
-        deps += [
-          "//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline",
-        ]
-        loadable_modules +=
-            [ "$root_out_dir/libcrashpad_handler_trampoline.so" ]
-      }
-      if (_include_secondary_abi) {
-        deps += [ "//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline($android_secondary_abi_toolchain)" ]
-        secondary_abi_loadable_modules +=
-            [ "$_secondary_out_dir/libcrashpad_handler_trampoline.so" ]
-      }
-    }
-
-    # The Chromium Linker depends on ASharedMemory_create() introduced in O.
-    use_chromium_linker = chromium_linker_supported && _is_trichrome
-
-    if (use_chromium_linker) {
-      if (android_64bit_target_cpu && !_is_64_bit_browser) {
-        deps += [ "//base/android/linker:chromium_android_linker($android_secondary_abi_toolchain)" ]
-        secondary_abi_loadable_modules +=
-            [ "$_secondary_out_dir/libchromium_android_linker$shlib_extension" ]
-      } else {
-        deps += [ "//base/android/linker:chromium_android_linker" ]
-        loadable_modules +=
-            [ "$root_out_dir/libchromium_android_linker$shlib_extension" ]
-      }
-      if (_is_64_bit_browser && build_hwasan_splits) {
-        deps += [
-          "//base/android/linker:chromium_android_linker($_hwasan_toolchain)",
-        ]
-        _hwasan_outdir = get_label_info(":($_hwasan_toolchain)", "root_out_dir")
-        loadable_modules +=
-            [ "$_hwasan_outdir/libchromium_android_linker$shlib_extension" ]
-      }
-    }
-
-    if (build_with_internal_optimization_guide) {
-      if (android_64bit_target_cpu && !_is_64_bit_browser) {
-        _secondary_optimization_guide = "//components/optimization_guide/internal:optimization_guide_internal($android_secondary_abi_toolchain)"
-        deps += [ _secondary_optimization_guide ]
-        secondary_abi_loadable_modules +=
-            [ "$_secondary_out_dir/liboptimization_guide_internal.so" ]
-      } else {
-        deps += [ "//components/optimization_guide/internal:optimization_guide_internal" ]
-        loadable_modules +=
-            [ "$root_out_dir/liboptimization_guide_internal.so" ]
-      }
-    }
-
-    if (_is_trichrome) {
-      if (android_64bit_target_cpu && !_is_64_bit_browser) {
-        static_library_provider_use_secondary_abi = true
+      if (_is_bundle_module) {
+        # Sets ISOLATED_SPLITS_ENABLED in BuildConfig.java.
+        isolated_splits_enabled = true
       }
 
-      # Include placeholder libraries to make Chrome multiarch in the same way
-      # as Monochrome, even though Chrome only runs with one of the two
-      # bitnesses. This allows the "32-bit" and "64-bit" versions of Chrome to
-      # depend on their respective versions of the shared library APK even
-      # though they're functionally the same.
-      if (_include_primary_abi && loadable_modules == []) {
-        native_lib_placeholders = [ "libdummy.so" ]
-      }
-      if (_include_secondary_abi && secondary_abi_loadable_modules == []) {
-        secondary_native_lib_placeholders = [ "libdummy.so" ]
-      }
+      if (_is_bundle_module && invoker.is_base_module) {
+        # The arcore manifest needs to be merged into the base module because
+        # the Play Store verifies the com.google.ar.core.min_apk_version
+        # meta-data tag is in the base manifest.
+        if (enable_arcore) {
+          deps += [
+            "//third_party/arcore-android-sdk-client:com_google_ar_core_java",
+            "//third_party/arcore-android-sdk-client:com_google_ar_core_java__ignored_manifest",
+          ]
+        }
 
-      # http://crbug.com/1042107.
-      if (is_component_build) {
-        if (_is_64_bit_browser) {
-          main_component_library = "libmonochrome_64.cr.so"
+        if (is_monochrome) {
+          deps += [ "//chrome/android:base_monochrome_module_java" ]
         } else {
-          main_component_library = "libmonochrome.cr.so"
+          deps += [ "//chrome/android:base_module_java" ]
+        }
+      }
+
+      if (android_64bit_target_cpu && (is_monochrome || is_trichrome)) {
+        _include_64_bit_webview = !defined(invoker.include_64_bit_webview) ||
+                                  invoker.include_64_bit_webview
+        _include_32_bit_webview = !defined(invoker.include_32_bit_webview) ||
+                                  invoker.include_32_bit_webview
+      }
+      if (is_monochrome) {
+        product_config_java_packages = [
+          "org.chromium.chrome.browser",
+          webview_product_config_java_package,
+        ]
+
+        if (webview_includes_weblayer) {
+          product_config_java_packages +=
+              [ weblayer_product_config_java_package ]
+        }
+
+        # Flag whether additional deps and libs should be included for each ABI.
+        _include_primary_support = false
+        _include_secondary_support = false
+
+        if (android_64bit_target_cpu) {
+          # Build //android_webview:monochrome with the opposite bitness that
+          # Chrome runs in.
+          if (invoker.is_64_bit_browser) {
+            _include_primary_support = true
+            shared_libraries += [ "//chrome/android:libmonochrome_64" ]
+            if (_include_32_bit_webview) {
+              secondary_abi_shared_libraries += [ "//android_webview:monochrome_64($android_secondary_abi_toolchain)" ]
+              _include_secondary_support = true
+            }
+          } else {
+            secondary_abi_shared_libraries +=
+                [ "//chrome/android:monochrome_secondary_abi_lib" ]
+            _include_secondary_support = true
+            if (_include_64_bit_webview) {
+              shared_libraries += [ "//android_webview:monochrome" ]
+              _include_primary_support = true
+            }
+          }
+        } else {
+          shared_libraries += [ "//chrome/android:libmonochrome" ]
+          _include_primary_support = true
+        }
+
+        deps += [
+          "//android_webview/glue:glue_java",
+          "//android_webview/nonembedded:nonembedded_java",
+        ]
+        if (!_is_bundle_module) {
+          deps += [ "//chrome/android:monochrome_java" ]
+        }
+
+        if (_include_primary_support) {
+          deps += [
+            "//android_webview:monochrome_webview_primary_abi_assets",
+            "//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline",
+          ]
+          loadable_modules +=
+              [ "$root_out_dir/libcrashpad_handler_trampoline.so" ]
+        }
+        if (_include_secondary_support) {
+          _trampoline =
+              "//third_party/crashpad/crashpad/handler:" +
+              "crashpad_handler_trampoline($android_secondary_abi_toolchain)"
+
+          deps += [
+            "//android_webview:monochrome_webview_secondary_abi_assets",
+            _trampoline,
+          ]
+
+          _secondary_out_dir = get_label_info(_trampoline, "root_out_dir")
+          secondary_abi_loadable_modules +=
+              [ "$_secondary_out_dir/libcrashpad_handler_trampoline.so" ]
+        }
+
+        if (defined(invoker.alternative_android_sdk_dep)) {
+          alternative_android_sdk_dep = invoker.alternative_android_sdk_dep
+        } else {
+          alternative_android_sdk_dep = webview_framework_dep
+        }
+        if (defined(invoker.app_as_shared_lib)) {
+          app_as_shared_lib = invoker.app_as_shared_lib
+        } else {
+          app_as_shared_lib = true
+        }
+        _pak_prefix = "monochrome"
+      }
+      if (is_trichrome) {
+        # Include placeholder libraries to make Chrome multiarch in the same way
+        # as Monochrome, even though Chrome only runs with one of the two
+        # bitnesses. This allows the "32-bit" and "64-bit" versions of Chrome to
+        # depend on their respective versions of the shared library APK even
+        # though they're functionally the same.
+        if (android_64bit_target_cpu) {
+          if (invoker.is_64_bit_browser) {
+            native_lib_placeholders += [ "libdummy.so" ]
+            if (_include_32_bit_webview) {
+              secondary_native_lib_placeholders += [ "libdummy.so" ]
+            }
+          } else {
+            secondary_native_lib_placeholders += [ "libdummy.so" ]
+            if (_include_64_bit_webview) {
+              native_lib_placeholders += [ "libdummy.so" ]
+            }
+          }
+        } else {
+          native_lib_placeholders += [ "libdummy.so" ]
+        }
+
+        _pak_prefix = "trichrome_chrome"
+      }
+
+      # The Chromium Linker depends on ASharedMemory_create() introduced in O.
+      use_chromium_linker = is_trichrome && chromium_linker_supported
+
+      if (build_hwasan_splits && android_64bit_target_cpu &&
+          invoker.is_64_bit_browser) {
+        _hwasan_toolchain =
+            "//build/toolchain/android:android_clang_arm64_hwasan"
+        shared_libraries +=
+            [ "//chrome/android:libmonochrome_64($_hwasan_toolchain)" ]
+
+        if (use_chromium_linker) {
+          shared_libraries += [
+            "//base/android/linker:chromium_android_linker($_hwasan_toolchain)",
+          ]
+        }
+      }
+
+      # We only optimize resources in bundles.
+      if (_is_bundle_module) {
+        # Resources config for blocklisting resource names from obfuscation
+        resources_config_paths = [
+          "//android_webview/aapt2.config",
+          "//chrome/android/aapt2.config",
+        ]
+        if (defined(invoker.resources_config_paths)) {
+          resources_config_paths += invoker.resources_config_paths
+        }
+      }
+
+      if (defined(invoker.never_incremental)) {
+        never_incremental = invoker.never_incremental
+      } else if (!defined(invoker.target_type) ||
+                 invoker.target_type == "android_apk") {
+        # Incremental install doesn't work for monochrome. See crbug.com/663492.
+      }
+
+      # Strip xml namespaces for monochrome. This should only be done for apks
+      # targeting API > 21 which for chrome is only Monochrome. This is due to
+      # how android public and private resource ids are namespaced.
+      if (defined(invoker.no_xml_namespaces)) {
+        no_xml_namespaces = invoker.no_xml_namespaces
+      } else {
+        no_xml_namespaces = true
+      }
+
+      if (_is_bundle_module) {
+        _pak_prefix += "_bundle_module"
+      } else {
+        _pak_prefix += "_apk"
+      }
+      deps += [ "//chrome/android:${_pak_prefix}_pak_assets" ]
+
+      if (!is_java_debug) {
+        proguard_configs = []
+        if (defined(invoker.proguard_configs)) {
+          proguard_configs += invoker.proguard_configs
+        }
+        if (is_monochrome) {
+          proguard_configs +=
+              [ "//android_webview/nonembedded/java/proguard.flags" ]
         }
       }
     }
 
-    forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
-    forward_variables_from(invoker,
-                           "*",
-                           TESTONLY_AND_VISIBILITY + [
-                                 "assert_no_deps",
-                                 "data_deps",
-                                 "deps",
-                                 "loadable_modules",
-                                 "manifest_package",
-                                 "proguard_configs",
-                                 "resources_config_paths",
-                                 "secondary_abi_loadable_modules",
-                                 "secondary_abi_shared_libraries",
-                                 "shared_libraries",
-                                 "version_code",
-                                 "version_name",
-                               ])
-  }
-}
-
-# For creating chrome targets without internal customizations.
-template("chrome_public_apk_or_module_tmpl") {
-  chrome_common_apk_or_module_tmpl(target_name) {
-    add_upstream_only_deps = true
-    forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
-    forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
-  }
-}
-
-# TODO(https://crbug.com/1427610): Remove.
-template("monochrome_public_common_apk_or_module_tmpl") {
-  chrome_common_apk_or_module_tmpl(target_name) {
-    forward_variables_from(invoker, "*")
-    if (!defined(is_monochrome)) {
-      is_trichrome = true
-    }
-  }
-}
-template("chrome_public_common_apk_or_module_tmpl") {
-  chrome_common_apk_or_module_tmpl(target_name) {
-    forward_variables_from(invoker, "*")
+    # The _overrides scope is used to ensure that:
+    # * Values set in invoker cannot accidentally clobber values set in
+    #   _overrides.
+    # * Values set in _overrides cannot accidentaly clobber values set in
+    #   invoker (since the forward_variables_from will fail).
+    _override_args = [
+      "alternative_android_sdk_dep",
+      "app_as_shared_lib",
+      "deps",
+      "is_monochrome",
+      "is_trichrome",
+      "isolated_splits_enabled",
+      "loadable_modules",
+      "native_lib_placeholders",
+      "never_incremental",
+      "no_xml_namespaces",
+      "product_config_java_packages",
+      "proguard_configs",
+      "resources_config_paths",
+      "secondary_abi_loadable_modules",
+      "secondary_abi_shared_libraries",
+      "secondary_native_lib_placeholders",
+      "shared_libraries",
+      "use_chromium_linker",
+      "webview_product_config_java_package",
+    ]
+    forward_variables_from(invoker, "*", _override_args)
+    forward_variables_from(_overrides, _override_args)
   }
 }
diff --git a/chrome/android/chrome_test_apk_tmpl.gni b/chrome/android/chrome_test_apk_tmpl.gni
index 106ee78..5ca00db6a 100644
--- a/chrome/android/chrome_test_apk_tmpl.gni
+++ b/chrome/android/chrome_test_apk_tmpl.gni
@@ -4,40 +4,50 @@
 
 import("//chrome/android/chrome_public_apk_tmpl.gni")
 
+# Dependencies that are common to any chrome_public derivative targets.
+chrome_public_shared_deps = [
+  "//chrome/android:chrome_app_java_resources",
+  "//chrome/android:chrome_public_apk_base_module_resources",
+  "//chrome/android:chrome_public_base_module_java",
+  "//chrome/android:chrome_public_non_pak_assets",
+  "//components/browser_ui/styles/android:chrome_public_apk_resources",
+  "//gin:v8_snapshot_assets",
+  "//third_party/icu:icu_assets",
+]
+
 chrome_public_test_manifest_package = "org.chromium.chrome.tests"
 
 template("chrome_test_apk_tmpl") {
-  chrome_public_apk_or_module_tmpl(target_name) {
+  chrome_public_common_apk_or_module_tmpl(target_name) {
     testonly = true
     target_type = "instrumentation_test_apk"
     bundles_supported = true
-
-    if (!defined(invoker.is_monochrome)) {
-      jinja_input = "//chrome/android/javatests/AndroidManifest.xml"
-      manifest_package = chrome_public_test_manifest_package
-    }
+    jinja_input = "//chrome/android/javatests/AndroidManifest.xml"
+    manifest_package = chrome_public_test_manifest_package
     shared_libraries = [ "//chrome/android:libchromefortest" ]
 
-    deps = [
-      "//chrome/android:chrome_public_base_module_java_for_test",
-      "//third_party/android_sdk:android_test_base_java",
-      "//third_party/android_sdk:android_test_mock_java",
-      "//third_party/android_sdk:android_test_runner_java",
-      "//third_party/androidx:androidx_test_runner_java",
-    ]
-    if (defined(invoker.deps)) {
-      deps += invoker.deps
-    }
+    deps = chrome_public_shared_deps + invoker.deps + [
+             "//chrome/android:chrome_apk_pak_assets",
+             "//chrome/android:chrome_public_base_module_java_for_test",
+             "//third_party/android_sdk:android_test_base_java",
+             "//third_party/android_sdk:android_test_mock_java",
+             "//third_party/android_sdk:android_test_runner_java",
+             "//third_party/androidx:androidx_test_runner_java",
+           ]
     if (add_unwind_tables_in_chrome_32bit_apk && current_cpu == "arm") {
       deps += [ "//chrome/android:libchromefortest_unwind_table_assets" ]
     }
+    if (enable_vr) {
+      # Contains VrFirstRunActivity, which is referenced by AndroidManifest.xml.
+      deps += [ "//chrome/android/features/vr:java" ]
+    }
 
-    # For EmbeddedTestServer.
     additional_apks = [ "//net/android:net_test_support_apk" ]
     if (defined(invoker.additional_apks)) {
       additional_apks += invoker.additional_apks
     }
     if (!is_java_debug) {
+      proguard_enabled = true
       proguard_configs = [ "//chrome/android/proguard/apk_for_test.flags" ]
       if (defined(invoker.proguard_configs)) {
         proguard_configs += invoker.proguard_configs
@@ -58,18 +68,54 @@
   }
 }
 
-# TODO(agrieve): Delete this and have all tests use chrome_test_apk_tmpl.
 template("monochrome_test_apk_tmpl") {
-  chrome_test_apk_tmpl(target_name) {
-    is_monochrome = true
-    manifest_package = chrome_public_manifest_package
+  monochrome_public_common_apk_or_module_tmpl(target_name) {
+    forward_variables_from(invoker,
+                           [
+                             "apk_name",
+                             "data_deps",
+                             "is_64_bit_browser",
+                             "include_64_bit_webview",
+                             "include_32_bit_webview",
+                             "loadable_modules",
+                             "proguard_configs",
+                             "secondary_abi_loadable_modules",
+                             "target_sdk_version",
+                           ])
+    testonly = true
+    target_type = "instrumentation_test_apk"
+
+    # TODO(agrieve): Add: manifest_package = chrome_public_test_manifest_package
 
     jinja_input = "//chrome/android/javatests/AndroidManifest_monochrome.xml"
     jinja_extra_includes = [ "//chrome/android/javatests/AndroidManifest.xml" ]
     jinja_extra_variables =
         [ "test_manifest_package=$chrome_public_test_manifest_package" ]
 
-    forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
-    forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
+    deps = chrome_public_shared_deps + invoker.deps + [
+             "//android_webview:platform_service_bridge_upstream_implementation_java",
+             "//chrome/android:chrome_public_base_module_java_for_test",
+             "//chrome/android:monochrome_apk_pak_assets",
+             "//third_party/android_sdk:android_test_base_java",
+             "//third_party/android_sdk:android_test_mock_java",
+             "//third_party/android_sdk:android_test_runner_java",
+             "//third_party/androidx:androidx_test_runner_java",
+           ]
+
+    if (webview_includes_weblayer) {
+      deps += [ "//weblayer/browser/java:upstream_java" ]
+    }
+
+    additional_apks = [ "//net/android:net_test_support_apk" ]
+    if (defined(invoker.additional_apks)) {
+      additional_apks += invoker.additional_apks
+    }
+    if (!is_java_debug) {
+      if (!defined(proguard_configs)) {
+        proguard_configs = []
+      }
+      proguard_enabled = true
+      proguard_configs += [ "//chrome/android/proguard/apk_for_test.flags" ]
+    }
   }
 }
diff --git a/chrome/android/expectations/trichrome_chrome_bundle__base.AndroidManifest.expected b/chrome/android/expectations/trichrome_chrome_bundle__base.AndroidManifest.expected
index 4f080e1..440a7d8 100644
--- a/chrome/android/expectations/trichrome_chrome_bundle__base.AndroidManifest.expected
+++ b/chrome/android/expectations/trichrome_chrome_bundle__base.AndroidManifest.expected
@@ -91,6 +91,7 @@
       android:networkSecurityConfig="@xml/network_security_config"
       android:roundIcon="@drawable/ic_launcher_round"
       android:supportsRtl="true"
+      android:use32bitAbi="true"
       android:zygotePreloadName="org.chromium.chrome.app.TrichromeZygotePreload">
     <activity  # DIFF-ANCHOR: ea1a94af
         android:name="com.google.android.gms.common.api.GoogleApiActivity"
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
index 577ff01..a3048e2 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
@@ -319,8 +319,7 @@
                             LargeMessageCardViewBinder::bind);
                 }
 
-                if (PriceTrackingFeatures.isPriceTrackingEnabled()
-                        && PriceTrackingFeatures.getPriceTrackingEnabled()) {
+                if (PriceTrackingFeatures.isPriceTrackingEnabled()) {
                     mPriceAnnotationsPrefObserver = key -> {
                         if (PriceTrackingUtilities.TRACK_PRICES_ON_TABS.equals(key)
                                 && !mTabModelSelector.isIncognitoSelected()
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceAlertsMessageCardTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceAlertsMessageCardTest.java
index 95d41bc2e..eaea36ee6 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceAlertsMessageCardTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceAlertsMessageCardTest.java
@@ -85,8 +85,7 @@
 public class PriceAlertsMessageCardTest {
     // clang-format on
     private static final String BASE_PARAMS =
-            "force-fieldtrial-params=Study.Group:enable_price_tracking/true"
-            + "/implicit_subscriptions_enabled/true";
+            "force-fieldtrial-params=Study.Group:implicit_subscriptions_enabled/true";
     private static final String ACTION_APP_NOTIFICATION_SETTINGS =
             "android.settings.APP_NOTIFICATION_SETTINGS";
     private static final String METRICS_IDENTIFIER =
@@ -107,6 +106,7 @@
     @Before
     public void setUp() {
         Intents.init();
+        PriceTrackingFeatures.setPriceTrackingEnabledForTesting(true);
         PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting(true);
         mMockNotificationManager = new MockNotificationManagerProxy();
         PriceDropNotificationManagerImpl.setNotificationManagerForTesting(mMockNotificationManager);
@@ -123,6 +123,7 @@
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
             mPriceDropNotificationManager.deleteChannelForTesting();
         }
+        PriceTrackingFeatures.setPriceTrackingEnabledForTesting(null);
         PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting(null);
         PriceDropNotificationManagerImpl.setNotificationManagerForTesting(null);
         ShoppingFeatures.setShoppingListEligibleForTesting(null);
@@ -169,10 +170,9 @@
 
     @Test
     @MediumTest
-    @CommandLineFlags.Add({"force-fieldtrial-params=Study.Group:enable_price_tracking/true"
-            + "/implicit_subscriptions_enabled/false"})
-    public void
-    testMessageCardNotShowing_ImplicitSubscriptionsParameterDisabled() {
+    @CommandLineFlags.
+    Add({"force-fieldtrial-params=Study.Group:implicit_subscriptions_enabled/false"})
+    public void testMessageCardNotShowing_ImplicitSubscriptionsParameterDisabled() {
         final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
         assertFalse(PriceTrackingUtilities.isPriceAlertsMessageCardEnabled());
 
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
index 174f072..ded9620e 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
@@ -50,7 +50,6 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
-import org.chromium.base.FeatureList;
 import org.chromium.base.test.UiThreadTest;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
@@ -779,7 +778,7 @@
 
     private void testPriceString(Tab tab, MockShoppingPersistedTabDataFetcher fetcher,
             int expectedVisibility, String expectedCurrentPrice, String expectedPreviousPrice) {
-        setPriceTrackingEnabledForTesting(true);
+        PriceTrackingFeatures.setPriceTrackingEnabledForTesting(true);
         testGridSelected(mTabGridView, mGridModel);
         PriceCardView priceCardView = mTabGridView.findViewById(R.id.price_info_box_outer);
         TextView currentPrice = mTabGridView.findViewById(R.id.current_price);
@@ -843,7 +842,7 @@
             ShoppingPersistedTabData.onDeferredStartup();
             ShoppingPersistedTabData.enablePriceTrackingWithOptimizationGuideForTesting();
             PersistedTabDataConfiguration.setUseTestConfig(true);
-            setPriceTrackingEnabledForTesting(true);
+            PriceTrackingFeatures.setPriceTrackingEnabledForTesting(true);
             mockCurrencyFormatter();
             mockUrlUtilities();
             mockOptimizationGuideResponse(OptimizationGuideDecision.TRUE, ANY_PRICE_TRACKING_DATA);
@@ -968,6 +967,7 @@
     @Override
     public void tearDownTest() throws Exception {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
+            PriceTrackingFeatures.setPriceTrackingEnabledForTesting(null);
             mStripMCP.destroy();
             mGridMCP.destroy();
             mSelectableMCP.destroy();
@@ -975,14 +975,4 @@
         });
         super.tearDownTest();
     }
-
-    private void setPriceTrackingEnabledForTesting(boolean value) {
-        FeatureList.TestValues testValues = new FeatureList.TestValues();
-
-        // Required by MockTab.
-        testValues.addFeatureFlagOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING, true);
-        testValues.addFieldTrialParamOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING,
-                PriceTrackingFeatures.PRICE_TRACKING_PARAM, String.valueOf(value));
-        FeatureList.setTestValues(testValues);
-    }
 }
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageServiceUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageServiceUnitTest.java
index 276ef84..24eb450b 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageServiceUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageServiceUnitTest.java
@@ -16,6 +16,7 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -82,11 +83,10 @@
         FeatureList.TestValues testValues = new FeatureList.TestValues();
         testValues.addFeatureFlagOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING, true);
         testValues.addFieldTrialParamOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING,
-                PriceTrackingFeatures.PRICE_TRACKING_PARAM, "true");
-        testValues.addFieldTrialParamOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING,
                 CommerceSubscriptionsServiceConfig.IMPLICIT_SUBSCRIPTIONS_ENABLED_PARAM, "true");
         FeatureList.setTestValues(testValues);
 
+        PriceTrackingFeatures.setPriceTrackingEnabledForTesting(true);
         PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting(true);
         PriceTrackingUtilities.SHARED_PREFERENCES_MANAGER.writeBoolean(
                 PriceTrackingUtilities.PRICE_WELCOME_MESSAGE_CARD, true);
@@ -104,6 +104,11 @@
         mMessageService.addObserver(mMessageObserver);
     }
 
+    @After
+    public void tearDown() {
+        PriceTrackingFeatures.setPriceTrackingEnabledForTesting(null);
+    }
+
     @Test(expected = AssertionError.class)
     public void testPrepareMessage_PriceWelcome_MessageDisabled() {
         PriceTrackingUtilities.SHARED_PREFERENCES_MANAGER.writeBoolean(
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
index 042463b..62fa2c3 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
@@ -474,6 +474,7 @@
         PseudoTab.clearForTesting();
         TabAttributeCache.clearAllForTesting();
         getGroupTitleSharedPreferences().edit().clear();
+        PriceTrackingFeatures.setPriceTrackingEnabledForTesting(null);
     }
 
     private static SharedPreferences getGroupTitleSharedPreferences() {
@@ -3883,9 +3884,9 @@
         FeatureList.TestValues testValues = new FeatureList.TestValues();
         testValues.addFeatureFlagOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING, true);
         testValues.addFieldTrialParamOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING,
-                PriceTrackingFeatures.PRICE_TRACKING_PARAM, String.valueOf(value));
-        testValues.addFieldTrialParamOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING,
                 PriceTrackingFeatures.PRICE_DROP_IPH_ENABLED_PARAM, String.valueOf(value));
         FeatureList.setTestValues(testValues);
+
+        PriceTrackingFeatures.setPriceTrackingEnabledForTesting(value);
     }
 }
diff --git a/chrome/android/java/AndroidManifest_monochrome.xml b/chrome/android/java/AndroidManifest_monochrome.xml
index f168f66..3cd9602a 100644
--- a/chrome/android/java/AndroidManifest_monochrome.xml
+++ b/chrome/android/java/AndroidManifest_monochrome.xml
@@ -22,6 +22,10 @@
 {% if force_32_bit is defined and force_32_bit == 'true' %}
 android:use32bitAbi="true"
 {% endif %}
+{# TODO(crbug.com/1411557): Remove #}
+{% if force_32_bit is not defined %}
+{{ use32bitAbi|default('') }}
+{% endif %}
 {% endblock %}
 
 {% block extra_keyset_definitions %}
diff --git a/chrome/android/java/AndroidManifest_trichrome_chrome.xml b/chrome/android/java/AndroidManifest_trichrome_chrome.xml
index f4fb656..7311fc6d 100644
--- a/chrome/android/java/AndroidManifest_trichrome_chrome.xml
+++ b/chrome/android/java/AndroidManifest_trichrome_chrome.xml
@@ -10,6 +10,7 @@
 {{ super() }}
 android:multiArch="true"
 android:extractNativeLibs="false"
+{{use32bitAbi|default('')}}
 {% endblock %}
 
 {% block extra_keyset_definitions %}
diff --git a/chrome/android/java/AndroidManifest_trichrome_library.xml b/chrome/android/java/AndroidManifest_trichrome_library.xml
index 928b193..9d5b717 100644
--- a/chrome/android/java/AndroidManifest_trichrome_library.xml
+++ b/chrome/android/java/AndroidManifest_trichrome_library.xml
@@ -28,6 +28,10 @@
         {% if force_32_bit is defined and force_32_bit == 'true' %}
         android:use32bitAbi="true"
         {% endif %}
+        {# TODO(crbug.com/1411557): Remove #}
+        {% if force_32_bit is not defined %}
+        {{ use32bitAbi|default('android:use32bitAbi="true"') }}
+        {% endif %}
       >
         <static-library android:name="{{ trichrome_library }}" android:version="{{ trichrome_version }}" />
     </application>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/creator/CreatorActionDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/app/creator/CreatorActionDelegateImpl.java
index 9d707dfb..1be1b8e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/creator/CreatorActionDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/creator/CreatorActionDelegateImpl.java
@@ -74,15 +74,16 @@
 
     @Override
     public void showSyncConsentActivity(int signinAccessPoint) {
-        SyncConsentActivityLauncherImpl.get().launchActivityIfAllowed(
-                mActivityContext, signinAccessPoint);
+        SyncConsentActivityLauncherImpl.get().launchActivityForPromoDefaultFlow(
+                mActivityContext, signinAccessPoint, null);
     }
 
     @Override
     public void showSignInInterstitial(int signinAccessPoint,
             BottomSheetController mBottomSheetController, WindowAndroid mWindowAndroid) {
         SigninBottomSheetCoordinator signinCoordinator =
-                new SigninBottomSheetCoordinator(mWindowAndroid, mBottomSheetController, mProfile);
+                new SigninBottomSheetCoordinator(mWindowAndroid, mBottomSheetController, mProfile,
+                        () -> { showSyncConsentActivity(signinAccessPoint); });
         signinCoordinator.show();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/feed/FeedActionDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/app/feed/FeedActionDelegateImpl.java
index e534575..e2800aa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/feed/FeedActionDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/feed/FeedActionDelegateImpl.java
@@ -148,8 +148,9 @@
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.FEED_BOC_SIGN_IN_INTERSTITIAL)) {
             SigninMetricsUtils.logSigninStartAccessPoint(signinAccessPoint);
             SigninMetricsUtils.logSigninUserActionForAccessPoint(signinAccessPoint);
-            SigninBottomSheetCoordinator signinCoordinator = new SigninBottomSheetCoordinator(
-                    windowAndroid, bottomSheetController, Profile.getLastUsedRegularProfile());
+            SigninBottomSheetCoordinator signinCoordinator =
+                    new SigninBottomSheetCoordinator(windowAndroid, bottomSheetController,
+                            Profile.getLastUsedRegularProfile(), null);
             signinCoordinator.show();
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
index 67ec2d55..9f668023 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
@@ -87,6 +87,7 @@
                 ChromeFeatureList.sCctRetainableStateInMemory,
                 ChromeFeatureList.sCctToolbarCustomizations,
                 ChromeFeatureList.sCloseTabSuggestions,
+                ChromeFeatureList.sCloseTabSaveTabList,
                 ChromeFeatureList.sCommandLineOnNonRooted,
                 ChromeFeatureList.sCriticalPersistedTabData,
                 ChromeFeatureList.sDiscoverMultiColumn,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
index 4d500ac0..afaaaaca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
@@ -192,6 +192,14 @@
             public void tabClosureUndone(Tab tab) {
                 saveTabListAsynchronously();
             }
+
+            @Override
+            public void onFinishingMultipleTabClosure(List<Tab> tabs) {
+                if (!mTabModelSelector.isIncognitoSelected()
+                        && ChromeFeatureList.sCloseTabSaveTabList.isEnabled()) {
+                    saveTabListAsynchronously();
+                }
+            }
         };
         mTabModelSelector.getModel(false).addObserver(mTabModelObserver);
         mTabModelSelector.getModel(true).addObserver(mTabModelObserver);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java
index bea7bd2..88c1919 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java
@@ -33,6 +33,7 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -453,9 +454,18 @@
             mFilesToDeleteCallback.onResult(filesToDelete);
 
             if (mTabContentManager != null && mThumbnailFileNames != null) {
+                HashSet<Integer> checkedTabIds = new HashSet<>();
                 for (String fileName : mThumbnailFileNames) {
+                    // Handle *.jpeg.
+                    int lastDotIdx = fileName.lastIndexOf(".");
+                    if (lastDotIdx != -1) {
+                        fileName = fileName.substring(0, lastDotIdx);
+                    }
                     try {
                         int tabId = Integer.parseInt(fileName);
+                        // Avoid double removal which could be expensive.
+                        if (!checkedTabIds.add(tabId)) continue;
+
                         if (shouldDeleteTabFile(tabId, tabWindowManager)) {
                             mTabContentManager.removeTabThumbnail(tabId);
                         }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java
index 798215c5..87bc0148 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java
@@ -185,12 +185,13 @@
     @Feature({"Preference"})
     @EnableFeatures({ChromeFeatureList.COMMERCE_PRICE_TRACKING + "<Study"})
     @CommandLineFlags.Add({"force-fieldtrials=Study/Group",
-            "force-fieldtrial-params=Study.Group:enable_price_tracking/true"
-                    + "/allow_disable_price_annotations/true"})
+            "force-fieldtrial-params=Study.Group:allow_disable_price_annotations/true"})
     public void
     testPriceTrackingAnnotations() {
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting(true));
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            PriceTrackingFeatures.setPriceTrackingEnabledForTesting(true);
+            PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting(true);
+        });
 
         final GoogleServicesSettings googleServicesSettings = startGoogleServicesSettings();
 
@@ -213,12 +214,13 @@
     @Feature({"Preference"})
     @EnableFeatures({ChromeFeatureList.COMMERCE_PRICE_TRACKING + "<Study"})
     @CommandLineFlags.Add({"force-fieldtrials=Study/Group",
-            "force-fieldtrial-params=Study.Group:enable_price_tracking/true"
-                    + "/allow_disable_price_annotations/false"})
+            "force-fieldtrial-params=Study.Group:allow_disable_price_annotations/false"})
     public void
     testPriceTrackingAnnotations_FeatureDisabled() {
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting(true));
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            PriceTrackingFeatures.setPriceTrackingEnabledForTesting(true);
+            PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting(true);
+        });
 
         final GoogleServicesSettings googleServicesSettings = startGoogleServicesSettings();
 
@@ -233,12 +235,13 @@
     @Feature({"Preference"})
     @EnableFeatures({ChromeFeatureList.COMMERCE_PRICE_TRACKING + "<Study"})
     @CommandLineFlags.Add({"force-fieldtrials=Study/Group",
-            "force-fieldtrial-params=Study.Group:enable_price_tracking/true"
-                    + "/allow_disable_price_annotations/true"})
+            "force-fieldtrial-params=Study.Group:allow_disable_price_annotations/true"})
     public void
     testPriceTrackingAnnotations_NotSignedIn() {
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting(false));
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            PriceTrackingFeatures.setPriceTrackingEnabledForTesting(true);
+            PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting(false);
+        });
 
         final GoogleServicesSettings googleServicesSettings = startGoogleServicesSettings();
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataDeferredStartupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataDeferredStartupTest.java
index 9dad76b..7667338 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataDeferredStartupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataDeferredStartupTest.java
@@ -24,6 +24,7 @@
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridge;
 import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridgeJni;
+import org.chromium.chrome.browser.price_tracking.PriceTrackingFeatures;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeBrowserTestRule;
@@ -75,6 +76,7 @@
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> { PersistedTabDataConfiguration.setUseTestConfig(true); });
         Profile.setLastUsedProfileForTesting(mProfileMock);
+        PriceTrackingFeatures.setPriceTrackingEnabledForTesting(false);
         doReturn(true).when(mNavigationHandle).isInPrimaryMainFrame();
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataLegacyTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataLegacyTest.java
index fcb9fcb..6dd463c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataLegacyTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataLegacyTest.java
@@ -25,6 +25,7 @@
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridge;
 import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridgeJni;
+import org.chromium.chrome.browser.price_tracking.PriceTrackingFeatures;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeBrowserTestRule;
 import org.chromium.chrome.test.util.browser.Features;
@@ -67,6 +68,7 @@
                 mOptimizationGuideBridgeJniMock,
                 HintsProto.OptimizationType.SHOPPING_PAGE_PREDICTOR.getNumber(),
                 OptimizationGuideDecision.TRUE, null);
+        PriceTrackingFeatures.setPriceTrackingEnabledForTesting(false);
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             ShoppingPersistedTabData.onDeferredStartup();
             PersistedTabDataConfiguration.setUseTestConfig(true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java
index d06bde1e..0e0e2eba 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java
@@ -33,6 +33,7 @@
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridge;
 import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridgeJni;
+import org.chromium.chrome.browser.price_tracking.PriceTrackingFeatures;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.MockTab;
 import org.chromium.chrome.browser.tab.Tab;
@@ -98,6 +99,7 @@
             PersistedTabDataConfiguration.setUseTestConfig(true);
         });
         Profile.setLastUsedProfileForTesting(mProfileMock);
+        PriceTrackingFeatures.setPriceTrackingEnabledForTesting(false);
         doReturn(true).when(mNavigationHandle).isInPrimaryMainFrame();
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarButtonIphTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarButtonIphTest.java
index 6048bc6e..a7ceb1d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarButtonIphTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarButtonIphTest.java
@@ -164,11 +164,10 @@
         FeatureList.TestValues testValues = new FeatureList.TestValues();
 
         // Enables price tracking.
-        testValues.addFeatureFlagOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING, true);
-        testValues.addFieldTrialParamOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING,
-                PriceTrackingFeatures.PRICE_TRACKING_PARAM, String.valueOf(true));
+        PriceTrackingFeatures.setPriceTrackingEnabledForTesting(true);
 
         // Enables the price tracking IPH.
+        testValues.addFeatureFlagOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING, true);
         testValues.addFieldTrialParamOverride(ChromeFeatureList.COMMERCE_PRICE_TRACKING,
                 PriceTrackingFeatures.PRICE_DROP_IPH_ENABLED_PARAM, String.valueOf(true));
         FeatureList.setTestValues(testValues);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhoneTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhoneTest.java
index f8ba27b5..065576b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhoneTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhoneTest.java
@@ -5,10 +5,12 @@
 package org.chromium.chrome.browser.toolbar.top;
 
 import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 
 import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.equalTo;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.atLeastOnce;
@@ -76,6 +78,7 @@
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.ui.test.util.DisableAnimationsTestRule;
 import org.chromium.ui.test.util.UiRestriction;
+import org.chromium.ui.test.util.ViewUtils;
 
 /**
  * Instrumentation tests for {@link ToolbarPhone}.
@@ -715,10 +718,9 @@
         // Show a button, this will inflate the optional button view and create its coordinator.
         TestThreadUtils.runOnUiThreadBlocking(() -> { mToolbar.updateOptionalButton(buttonData); });
 
-        CriteriaHelper.pollUiThread(()
-                                            -> mToolbar.getOptionalButtonViewForTesting() != null
-                        && mToolbar.getOptionalButtonViewForTesting().getVisibility()
-                                == View.VISIBLE);
+        CriteriaHelper.pollUiThread(() -> mToolbar.getOptionalButtonViewForTesting() != null);
+        ViewUtils.onViewWaiting(
+                allOf(equalTo(mToolbar.getOptionalButtonViewForTesting()), isDisplayed()));
 
         // Replace the coordinator with a mock, and set the button to visible with regular width.
         View optionalButtonView = mToolbar.findViewById(R.id.optional_toolbar_button_container);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java
index 9edea104..3a75134 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java
@@ -31,6 +31,7 @@
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.RequiresRestart;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -219,6 +220,7 @@
     @MediumTest
     @Feature({"BottomSheetController"})
     @Features.DisableFeatures({ChromeFeatureList.BOTTOM_SHEET_GTS_SUPPORT})
+    @RequiresRestart("Requires re-creating BottomSheetManager for flag change.")
     public void testSheetPeekAfterTabSwitcher() throws TimeoutException {
         requestContentInSheet(mLowPriorityContent, true);
         enterAndExitTabSwitcher();
@@ -259,6 +261,7 @@
     @MediumTest
     @Feature({"BottomSheetController"})
     @Features.DisableFeatures({ChromeFeatureList.BOTTOM_SHEET_GTS_SUPPORT})
+    @RequiresRestart("Requires re-creating BottomSheetManager for flag change.")
     public void testSheetHiddenAfterTabSwitcher() throws TimeoutException {
         // Open a second tab.
         Tab tab1 = mActivity.getActivityTab();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/app/tabmodel/TabPersistentStoreIntegrationTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/app/tabmodel/TabPersistentStoreIntegrationTest.java
index e3e34cc9..4430026 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/app/tabmodel/TabPersistentStoreIntegrationTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/app/tabmodel/TabPersistentStoreIntegrationTest.java
@@ -25,6 +25,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.android.util.concurrent.PausedExecutorService;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
 import org.robolectric.annotation.LooperMode;
 import org.robolectric.annotation.LooperMode.Mode;
 
@@ -35,6 +38,7 @@
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.homepage.HomepageManager;
 import org.chromium.chrome.browser.ntp.RecentlyClosedBridge;
 import org.chromium.chrome.browser.ntp.RecentlyClosedBridgeJni;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -68,6 +72,14 @@
 @LooperMode(Mode.PAUSED)
 @Features.EnableFeatures(ChromeFeatureList.TAB_STATE_V1_OPTIMIZATIONS)
 public class TabPersistentStoreIntegrationTest {
+    /** Shadow for {@link HomepageManager}. */
+    @Implements(HomepageManager.class)
+    static class ShadowHomepageManager {
+        @Implementation
+        public static boolean shouldCloseAppWithZeroTabs() {
+            return false;
+        }
+    }
     @Rule
     public JniMocker jniMocker = new JniMocker();
     @Rule
@@ -208,14 +220,7 @@
 
     private void doTestUndoTabClosurePersistsState() {
         AtomicInteger timesMetadataSaved = new AtomicInteger();
-        TabPersistentStoreObserver observer = new TabPersistentStoreObserver() {
-            @Override
-            public void onMetadataSavedAsynchronously(
-                    TabModelSelectorMetadata modelSelectorMetadata) {
-                timesMetadataSaved.incrementAndGet();
-            }
-        };
-        mTabPersistentStore.addObserver(observer);
+        observeOnMetadataSavedAsynchronously(timesMetadataSaved);
 
         // Setup the test: Create a tab and close it
         TabModel tabModel = mTabModelSelector.getModel(false);
@@ -233,6 +238,63 @@
         assertEquals(timesMetadataSavedBefore + 1, timesMetadataSaved.intValue());
     }
 
+    @Test
+    @SmallTest
+    @Feature({"TabPersistentStore"})
+    @Features.EnableFeatures(ChromeFeatureList.CRITICAL_PERSISTED_TAB_DATA)
+    public void testCloseTabPersistsState() {
+        AtomicInteger timesMetadataSaved = new AtomicInteger();
+        observeOnMetadataSavedAsynchronously(timesMetadataSaved);
+
+        // Setup the test: Create a tab and close it.
+        TabModel tabModel = mTabModelSelector.getModel(false);
+        Tab tab = MockTab.createAndInitialize(1, false, TabLaunchType.FROM_CHROME_UI);
+        tabModel.addTab(tab, 0, TabLaunchType.FROM_CHROME_UI, TabCreationState.LIVE_IN_FOREGROUND);
+
+        int timesMetadataSavedBefore = timesMetadataSaved.intValue();
+        // Step to test: Close tab.
+        tabModel.closeTab(tab, false, false, true);
+        runAllAsyncTasks();
+
+        // Step to test: Commit tab closure.
+        tabModel.commitTabClosure(1);
+        runAllAsyncTasks();
+
+        // Verify that metadata was saved.
+        assertEquals(timesMetadataSavedBefore + 1, timesMetadataSaved.intValue());
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"TabPersistentStore"})
+    @Config(manifest = Config.NONE, shadows = {ShadowHomepageManager.class})
+    @Features.EnableFeatures(ChromeFeatureList.CRITICAL_PERSISTED_TAB_DATA)
+    public void testCloseAllTabsPersistsState() {
+        AtomicInteger timesMetadataSaved = new AtomicInteger();
+        observeOnMetadataSavedAsynchronously(timesMetadataSaved);
+
+        // Setup the test: Create three tabs and close them all.
+        TabModel tabModel = mTabModelSelector.getModel(false);
+        Tab tab1 = MockTab.createAndInitialize(1, false, TabLaunchType.FROM_CHROME_UI);
+        tabModel.addTab(tab1, 0, TabLaunchType.FROM_CHROME_UI, TabCreationState.LIVE_IN_FOREGROUND);
+        Tab tab2 = MockTab.createAndInitialize(2, false, TabLaunchType.FROM_CHROME_UI);
+        tabModel.addTab(tab2, 1, TabLaunchType.FROM_CHROME_UI, TabCreationState.LIVE_IN_FOREGROUND);
+        Tab tab3 = MockTab.createAndInitialize(3, false, TabLaunchType.FROM_CHROME_UI);
+        tabModel.addTab(tab3, 2, TabLaunchType.FROM_CHROME_UI, TabCreationState.LIVE_IN_FOREGROUND);
+
+        int timesMetadataSavedBefore = timesMetadataSaved.intValue();
+        // Step to test: Close all tabs.
+        tabModel.closeAllTabs(false);
+        runAllAsyncTasks();
+
+        // Step to test: Commit tabs closure.
+        tabModel.commitAllTabClosures();
+        runAllAsyncTasks();
+
+        // Verify that metadata was saved.
+        assertEquals(timesMetadataSavedBefore + 1, timesMetadataSaved.intValue());
+    }
+
     private void runAllAsyncTasks() {
         // Run AsyncTasks
         mExecutor.runAll();
@@ -240,4 +302,15 @@
         // Wait for onPostExecute() of the AsyncTasks to run on the UI Thread.
         shadowOf(Looper.getMainLooper()).idle();
     }
+
+    private void observeOnMetadataSavedAsynchronously(AtomicInteger timesMetadataSaved) {
+        TabPersistentStoreObserver observer = new TabPersistentStoreObserver() {
+            @Override
+            public void onMetadataSavedAsynchronously(
+                    TabModelSelectorMetadata modelSelectorMetadata) {
+                timesMetadataSaved.incrementAndGet();
+            }
+        };
+        mTabPersistentStore.addObserver(observer);
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinatorTest.java
index ab27f6f..73332072 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinatorTest.java
@@ -93,6 +93,7 @@
         ChromeFeatureList.INTEREST_FEED_V2_AUTOPLAY,
         ChromeFeatureList.FEED_BACK_TO_TOP,
         ChromeFeatureList.FEED_MULTI_COLUMN,
+        ChromeFeatureList.FEED_USER_INTERACTION_RELIABILITY_REPORT,
         // TODO(crbug.com/1353777): Disabling the feature explicitly, because native is not
         // available to provide a default value. This should be enabled if the feature is enabled by
         // default or removed if the flag is removed.
diff --git a/chrome/android/modules/chrome_bundle_tmpl.gni b/chrome/android/modules/chrome_bundle_tmpl.gni
index 74783db4..1d18e0c8 100644
--- a/chrome/android/modules/chrome_bundle_tmpl.gni
+++ b/chrome/android/modules/chrome_bundle_tmpl.gni
@@ -35,7 +35,7 @@
       get_label_info(invoker.base_module_target, "target_gen_dir")
   _base_name = get_label_info(invoker.base_module_target, "name")
   _split_android_manifest =
-      "${_base_target_gen_dir}/${_base_name}/AndroidManifest_split.xml"
+      "${_base_target_gen_dir}/manifest/${_base_name}/AndroidManifest_split.xml"
 
   _chrome_module_desc = {
     name = "chrome"
diff --git a/chrome/android/monochrome_android_manifest_jinja_variables.gni b/chrome/android/monochrome_android_manifest_jinja_variables.gni
new file mode 100644
index 0000000..97c121a
--- /dev/null
+++ b/chrome/android/monochrome_android_manifest_jinja_variables.gni
@@ -0,0 +1,6 @@
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# TODO(crbug.com/1411557): Delete this file.
+import("//chrome/android/chrome_public_apk_tmpl.gni")
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt
index 480efc3e..56944867 100644
--- a/chrome/android/profiles/arm.newest.txt
+++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-114.0.5702.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-arm-114.0.5715.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 80dbf28..5b7aed8 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-114.0.5713.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-114.0.5715.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/android/trichrome.gni b/chrome/android/trichrome.gni
index 752aa8c..32ebe22 100644
--- a/chrome/android/trichrome.gni
+++ b/chrome/android/trichrome.gni
@@ -25,10 +25,16 @@
   trichrome_certdigest = default_trichrome_certdigest
 }
 
+# TODO(crbug.com/1411557): Remove variable once unused internally.
+use_32bit_abi_jinja_variable = "use32bitAbi=android:use32bitAbi=\"true\""
+
 trichrome_jinja_variables = [
   "trichrome_library=$trichrome_library_package",
   "trichrome_certdigest=$trichrome_certdigest",
   "zygote_preload_class=org.chromium.chrome.app.TrichromeZygotePreload",
+
+  # TODO(crbug.com/1411557): Remove variable once unused internally.
+  use_32bit_abi_jinja_variable,
 ]
 
 template("trichrome_library_apk_tmpl") {
@@ -38,77 +44,83 @@
        invoker.include_64_bit_webview) && android_64bit_target_cpu
   _include_32_bit_webview =
       !defined(invoker.include_32_bit_webview) || invoker.include_32_bit_webview
-  _include_primary_abi =
-      !android_64bit_target_cpu || _is_64_bit_browser || _include_64_bit_webview
-  _include_secondary_abi = android_64bit_target_cpu &&
-                           (!_is_64_bit_browser || _include_32_bit_webview)
-  if (_include_secondary_abi) {
-    _secondary_out_dir =
-        get_label_info("X($android_secondary_abi_toolchain)", "root_out_dir")
-  }
   _version_code = TRICHROME_VERSION_MAP["${android_64bit_target_cpu}_${_is_64_bit_browser}_${_include_64_bit_webview}_${_include_32_bit_webview}"]
 
-  if (defined(invoker.manifest_package)) {
-    _manifest_package = invoker.manifest_package
-  } else {
-    _manifest_package = trichrome_library_package
-  }
-  _android_manifest = "$target_gen_dir/$target_name/AndroidManifest.xml"
-  _android_manifest_target_name = "${target_name}__android_manifest"
-  jinja_template(_android_manifest_target_name) {
-    input = "//chrome/android/java/AndroidManifest_trichrome_library.xml"
-    output = _android_manifest
-    _force_32_bit = _include_32_bit_webview && _include_64_bit_webview &&
-                    !_is_64_bit_browser
-    variables = trichrome_jinja_variables + [
-                  "force_32_bit=$_force_32_bit",
-                  "manifest_package=$_manifest_package",
-                  "trichrome_version=$_version_code",
-                ]
+  # TODO(crbug.com/1411557): Remove option for custom manifest.
+  if (!defined(invoker.android_manifest)) {
+    if (defined(invoker.manifest_package)) {
+      _manifest_package = invoker.manifest_package
+    } else {
+      _manifest_package = trichrome_library_package
+    }
+    _android_manifest = "$target_gen_dir/$target_name/AndroidManifest.xml"
+    _android_manifest_target_name = "${target_name}__android_manifest"
+    jinja_template(_android_manifest_target_name) {
+      input = "//chrome/android/java/AndroidManifest_trichrome_library.xml"
+      output = _android_manifest
+      _force_32_bit = _include_32_bit_webview && _include_64_bit_webview &&
+                      !_is_64_bit_browser
+      variables = trichrome_jinja_variables + [
+                    "force_32_bit=$_force_32_bit",
+                    "manifest_package=$_manifest_package",
+                    "trichrome_version=$_version_code",
+                  ]
 
-    if (defined(invoker.jinja_extra_variables)) {
-      variables += invoker.jinja_extra_variables
+      # TODO(crbug.com/1411557): Remove block.
+      if (_is_64_bit_browser) {
+        variables -= [ use_32bit_abi_jinja_variable ]
+      }
+      if (defined(invoker.jinja_extra_variables)) {
+        variables += invoker.jinja_extra_variables
+      }
     }
   }
   android_apk(target_name) {
-    android_manifest = _android_manifest
-    android_manifest_dep = ":$_android_manifest_target_name"
-    manifest_package = _manifest_package
+    if (defined(_android_manifest_target_name)) {
+      android_manifest = _android_manifest
+      android_manifest_dep = ":$_android_manifest_target_name"
+      manifest_package = _manifest_package
+    }
 
     if (defined(invoker.expected_android_manifest)) {
       expected_android_manifest_version_code_offset = chrome_version_code
       expected_android_manifest_library_version_offset = chrome_version_code
     }
 
-    omit_dex = true
+    # TODO(torne): since there's no real java code in the library right now,
+    # leave out the build hooks and let them get compiled into each APK. Later
+    # this should probably be in the library.
+    no_build_hooks = true
     include_size_info = is_official_build
+
     alternative_android_sdk_dep = webview_framework_dep
     r_java_root_package_name = "trichrome_lib"
     app_as_shared_lib = true
-    version_name = chrome_version_name
-    version_code = _version_code
-    min_sdk_version = 29
 
     # No support for this has been added, also not supported by test runner
     # since trichrome library is used in "additional_apks" in the trichrome
     # bundle smoke tests.
     never_incremental = true
 
+    version_name = chrome_version_name
+    version_code = _version_code
+    min_sdk_version = 29
+
     # TODO(torne): using icon_resources just to get a temporary icon
     deps = [
       "//android_webview/nonembedded:icon_resources",
       "//third_party/icu:icu_assets",
     ]
-    if (_include_primary_abi) {
-      deps += [ "//gin:v8_snapshot_assets" ]
-    }
-    if (_include_secondary_abi) {
-      deps += [ "//gin:v8_snapshot_secondary_abi_assets" ]
-    }
     if (defined(invoker.deps)) {
       deps += invoker.deps
     }
 
+    omit_dex = true
+
+    # Flag whether additional deps and libs should be included for each ABI.
+    _include_primary_support = false
+    _include_secondary_support = false
+
     if (android_64bit_target_cpu) {
       # Include the actual browser-bitness libmonochrome library, dependencies
       # (crashpad and linker), and an opposite-bitness placeholder library to
@@ -116,54 +128,64 @@
       # precompiled for both architectures.
       if (_is_64_bit_browser) {
         shared_libraries = [ "//chrome/android:libmonochrome_64" ]
+        _include_primary_support = true
         if (_include_32_bit_webview) {
           secondary_native_lib_placeholders = [ "libdummy.so" ]
         }
-        if (build_hwasan_splits) {
-          _hwasan_toolchain =
-              "//build/toolchain/android:android_clang_arm64_hwasan"
-          shared_libraries +=
-              [ "//chrome/android:libmonochrome_64($_hwasan_toolchain)" ]
-        }
       } else {
         secondary_abi_shared_libraries =
             [ "//chrome/android:monochrome_secondary_abi_lib" ]
+        _include_secondary_support = true
         if (invoker.include_64_bit_webview) {
           native_lib_placeholders = [ "libdummy.so" ]
         }
       }
     } else {
       shared_libraries = [ "//chrome/android:libmonochrome" ]
+      _include_primary_support = true
     }
 
-    # https://chromium.googlesource.com/chromium/src/+/main/docs/android_native_libraries.md#Crashpad-Packaging
-    loadable_modules = []
-    secondary_abi_loadable_modules = []
-    if (_include_primary_abi) {
+    if (_include_primary_support) {
       deps += [
+        "//gin:v8_snapshot_assets",
         "//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline",
       ]
-      loadable_modules += [ "$root_out_dir/libcrashpad_handler_trampoline.so" ]
+      loadable_modules = [ "$root_out_dir/libcrashpad_handler_trampoline.so" ]
     }
-    if (_include_secondary_abi) {
-      deps += [ "//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline($android_secondary_abi_toolchain)" ]
-      secondary_abi_loadable_modules +=
+    if (_include_secondary_support) {
+      _trampoline =
+          "//third_party/crashpad/crashpad/handler:" +
+          "crashpad_handler_trampoline($android_secondary_abi_toolchain)"
+      deps += [
+        "//gin:v8_snapshot_secondary_abi_assets",
+        _trampoline,
+      ]
+      _secondary_out_dir = get_label_info(_trampoline, "root_out_dir")
+      secondary_abi_loadable_modules =
           [ "$_secondary_out_dir/libcrashpad_handler_trampoline.so" ]
     }
 
     if (enable_arcore) {
-      _arcore_target = "//third_party/arcore-android-sdk-client:com_google_ar_core_J__unpack_aar"
-      _libarcore_dir = get_label_info(_arcore_target, "target_out_dir") +
-                       "/com_google_ar_core_java/jni"
-      deps += [ "//third_party/arcore-android-sdk-client:com_google_ar_core_J__unpack_aar" ]
+      _libarcore_dir = get_label_info(
+                           "//third_party/arcore-android-sdk-client:com_google_ar_core_java($default_toolchain)",
+                           "target_out_dir") + "/com_google_ar_core_java/jni"
+      not_needed([ "_libarcore_dir" ])
 
-      if (_include_primary_abi) {
+      _arcore_extra_deps = [ "//third_party/arcore-android-sdk-client:com_google_ar_core_J__unpack_aar" ]
+      not_needed([ "_arcore_extra_deps" ])
+
+      if (_include_primary_support) {
         loadable_modules +=
             [ "$_libarcore_dir/$android_app_abi/libarcore_sdk_c.so" ]
+        deps += _arcore_extra_deps
       }
-      if (_include_secondary_abi) {
-        secondary_abi_loadable_modules +=
-            [ "$_libarcore_dir/$android_app_secondary_abi/libarcore_sdk_c.so" ]
+      if (_include_secondary_support) {
+        if (enable_arcore) {
+          secondary_abi_loadable_modules += [
+            "$_libarcore_dir/$android_app_secondary_abi/libarcore_sdk_c.so",
+          ]
+          deps += _arcore_extra_deps
+        }
       }
     }
     forward_variables_from(invoker,
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 9ef05ee..63c1a59f 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -1497,6 +1497,9 @@
         <message name="IDS_PROFILE_SWITCH_PROMO_SCREENREADER" desc="Text announced by screenreaders to explain how to switch between profiles.">
           <ph name="SHORTCUT">$1<ex>CTRL+SHIFT+M</ex></ph> can switch between Chromium profiles
         </message>
+        <message name="IDS_PASSWORD_MANAGER_IPH_BODY_WEB_APP_PROFILE_SWITCH" desc="Body of the in Product Help for profile switching shown in the password manager web app.">
+          You can switch to see passwords from another Chromium profile
+        </message>
       </if>
 
       <!-- Strings for full restore notifications -->
diff --git a/chrome/app/chromium_strings_grd/IDS_PASSWORD_MANAGER_IPH_BODY_WEB_APP_PROFILE_SWITCH.png.sha1 b/chrome/app/chromium_strings_grd/IDS_PASSWORD_MANAGER_IPH_BODY_WEB_APP_PROFILE_SWITCH.png.sha1
new file mode 100644
index 0000000..d0176d4
--- /dev/null
+++ b/chrome/app/chromium_strings_grd/IDS_PASSWORD_MANAGER_IPH_BODY_WEB_APP_PROFILE_SWITCH.png.sha1
@@ -0,0 +1 @@
+afb68a43b82bdfb62e28068c5371185ebfa12e0d
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index d6a4f9a..5a2728e 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4487,20 +4487,17 @@
 
       <if expr="enable_extensions">
         <!-- Extension blocked action bubble -->
-        <message name="IDS_EXTENSION_RELOAD_PAGE_BUBBLE_HEADING" desc="Heading of the bubble to tell users that in order to run an extension, they'll need to refresh the page.">
-          Reload page to use this extension
+        <message name="IDS_EXTENSION_SITE_RELOAD_PAGE_BUBBLE_HEADING" desc="Heading of the bubble to tell users that in order to run or not run an extension, they'll need to refresh the page. Deliberately similar to IDS_PAGE_INFO_INFOBAR_TEXT, but used for an different permission setting so they are not combined. If updating the one, please update the other or consult the extensions and privacy teams.">
+          To apply your updated settings to this site, reload this page
         </message>
         <message name="IDS_EXTENSION_RELOAD_PAGE_BUBBLE_OK_BUTTON" desc="The text of the button to proceed with the page refresh for running an extension.">
           Reload
         </message>
         <message name="IDS_EXTENSION_RELOAD_PAGE_BUBBLE_ALLOW_SINGLE_EXTENSION_TITLE" desc="Title of the bubble to tell users that in order to run or block an extension, they'll need to refresh the page.">
-          Reload the page to use "<ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph>"
+          To apply your updated settings for "<ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph>" to this site, reload this page
         </message>
         <message name="IDS_EXTENSION_RELOAD_PAGE_BUBBLE_ALLOW_MULTIPLE_EXTENSIONS_TITLE" desc="Title of the bubble to tell users that in order to run or block an extension, they'll need to refresh the page.">
-          Reload the page to use these extensions
-        </message>
-        <message name="IDS_EXTENSION_RELOAD_PAGE_BUBBLE_UPDATE_PERMISSIONS_TITLE" desc="Title of the bubble to tell users that in order to apply the changes selected, they'll need to refresh the page.">
-          Reload the page to apply your changes
+          To apply your updated settings to this site for these extensions, reload this page
         </message>
       </if>
 
@@ -8541,9 +8538,6 @@
         <message name="IDS_PASSWORD_MANAGER_UNSYNCED_CREDENTIALS_BUBBLE_DESCRIPTION_GPM" desc="The description text of the 'save unsynced credentials' bubble.">
           Google Password Manager couldn't save these passwords in your Google Account. You can save them to this device.
         </message>
-        <message name="IDS_PASSWORD_MANAGER_IPH_BODY_WEB_APP_PROFILE_SWITCH" desc="Body of the in Product Help for profile switching shown in the password manager web app.">
-          You can choose the profile that you want to see the passwords from
-        </message>
 
         <if expr="not use_titlecase">
           <message name="IDS_PASSWORD_MANAGER_SAVE_UNSYNCED_CREDENTIALS_BUTTON_GPM" desc="Button text for the 'save unsynced credentials' bubble's save option.">
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSION_RELOAD_PAGE_BUBBLE_ALLOW_MULTIPLE_EXTENSIONS_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSION_RELOAD_PAGE_BUBBLE_ALLOW_MULTIPLE_EXTENSIONS_TITLE.png.sha1
index 97b49a6..e0455bff 100644
--- a/chrome/app/generated_resources_grd/IDS_EXTENSION_RELOAD_PAGE_BUBBLE_ALLOW_MULTIPLE_EXTENSIONS_TITLE.png.sha1
+++ b/chrome/app/generated_resources_grd/IDS_EXTENSION_RELOAD_PAGE_BUBBLE_ALLOW_MULTIPLE_EXTENSIONS_TITLE.png.sha1
@@ -1 +1 @@
-54c699878482736ca7e7becabfba34c0fe29649b
+a547cd59051eda8280b9264e6e05b0053a29a8d5
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSION_RELOAD_PAGE_BUBBLE_ALLOW_SINGLE_EXTENSION_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSION_RELOAD_PAGE_BUBBLE_ALLOW_SINGLE_EXTENSION_TITLE.png.sha1
index f513ee8..b72fa39 100644
--- a/chrome/app/generated_resources_grd/IDS_EXTENSION_RELOAD_PAGE_BUBBLE_ALLOW_SINGLE_EXTENSION_TITLE.png.sha1
+++ b/chrome/app/generated_resources_grd/IDS_EXTENSION_RELOAD_PAGE_BUBBLE_ALLOW_SINGLE_EXTENSION_TITLE.png.sha1
@@ -1 +1 @@
-a5178af55de41f0deb75ce3f189f120871c664d5
\ No newline at end of file
+d325911985ce4ead7ada28f962adc6bcf7ee010d
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSION_RELOAD_PAGE_BUBBLE_HEADING.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSION_RELOAD_PAGE_BUBBLE_HEADING.png.sha1
deleted file mode 100644
index 2e9e2d2..0000000
--- a/chrome/app/generated_resources_grd/IDS_EXTENSION_RELOAD_PAGE_BUBBLE_HEADING.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-9cb9758f3ba90246f84b8ff897ee353432782ac1
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSION_RELOAD_PAGE_BUBBLE_UPDATE_PERMISSIONS_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSION_RELOAD_PAGE_BUBBLE_UPDATE_PERMISSIONS_TITLE.png.sha1
deleted file mode 100644
index e34b0caa..0000000
--- a/chrome/app/generated_resources_grd/IDS_EXTENSION_RELOAD_PAGE_BUBBLE_UPDATE_PERMISSIONS_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-71adcd3a7e5695f91d7a32b0a9287d71084b6403
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSION_SITE_RELOAD_PAGE_BUBBLE_HEADING.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSION_SITE_RELOAD_PAGE_BUBBLE_HEADING.png.sha1
new file mode 100644
index 0000000..9d4ecdc
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_EXTENSION_SITE_RELOAD_PAGE_BUBBLE_HEADING.png.sha1
@@ -0,0 +1 @@
+6cdaa4d769d0fc94324998bca7fe1a5ddf542747
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_PASSWORD_MANAGER_IPH_BODY_WEB_APP_PROFILE_SWITCH.png.sha1 b/chrome/app/generated_resources_grd/IDS_PASSWORD_MANAGER_IPH_BODY_WEB_APP_PROFILE_SWITCH.png.sha1
deleted file mode 100644
index d8b596a..0000000
--- a/chrome/app/generated_resources_grd/IDS_PASSWORD_MANAGER_IPH_BODY_WEB_APP_PROFILE_SWITCH.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-b2d60b56c13c68d6281b58c1cb5e9c890d1d32b6
\ No newline at end of file
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index 6c120cd..0b34b072 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -1591,6 +1591,9 @@
         <message name="IDS_PROFILE_SWITCH_PROMO_SCREENREADER" desc="Text announced by screenreaders to explain how to switch between profiles.">
           <ph name="SHORTCUT">$1<ex>CTRL+SHIFT+M</ex></ph> can switch between Chrome profiles
         </message>
+        <message name="IDS_PASSWORD_MANAGER_IPH_BODY_WEB_APP_PROFILE_SWITCH" desc="Body of the in Product Help for profile switching shown in the password manager web app.">
+          You can switch to see passwords from another Chrome profile
+        </message>
       </if>
 
       <!-- Strings for full restore notifications -->
diff --git a/chrome/app/google_chrome_strings_grd/IDS_PASSWORD_MANAGER_IPH_BODY_WEB_APP_PROFILE_SWITCH.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_PASSWORD_MANAGER_IPH_BODY_WEB_APP_PROFILE_SWITCH.png.sha1
new file mode 100644
index 0000000..b70b787
--- /dev/null
+++ b/chrome/app/google_chrome_strings_grd/IDS_PASSWORD_MANAGER_IPH_BODY_WEB_APP_PROFILE_SWITCH.png.sha1
@@ -0,0 +1 @@
+f347984c4a28979ffc1f7f3c6f4c5ec6cbce20bb
\ No newline at end of file
diff --git a/chrome/app/password_manager_ui_strings.grdp b/chrome/app/password_manager_ui_strings.grdp
index 58037e78..9b312a04 100644
--- a/chrome/app/password_manager_ui_strings.grdp
+++ b/chrome/app/password_manager_ui_strings.grdp
@@ -459,4 +459,7 @@
       Manage passkeys
     </message>
   </if>
+  <message name="IDS_PASSWORD_MANAGER_UI_NO_PASSWORDS_FOUND" desc="Text displayed in the passwords page when there are no passwords matching search query.">
+    No passwords found
+  </message>
 </grit-part>
diff --git a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_NO_PASSWORDS_FOUND.png.sha1 b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_NO_PASSWORDS_FOUND.png.sha1
new file mode 100644
index 0000000..b26fef7
--- /dev/null
+++ b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_NO_PASSWORDS_FOUND.png.sha1
@@ -0,0 +1 @@
+9875dcd62a31780a262939b5ca73c8b2b05e1804
\ No newline at end of file
diff --git a/chrome/app/resources/chromium_strings_zh-TW.xtb b/chrome/app/resources/chromium_strings_zh-TW.xtb
index 6ad9afd..f4666b7 100644
--- a/chrome/app/resources/chromium_strings_zh-TW.xtb
+++ b/chrome/app/resources/chromium_strings_zh-TW.xtb
@@ -309,7 +309,7 @@
 <translation id="7617377681829253106">Chromium 變得更進步了</translation>
 <translation id="7649070708921625228">說明</translation>
 <translation id="7682213815243802460">你可以前往 Chrome 設定進一步瞭解這些功能。</translation>
-<translation id="7682601070171973634">Chromium 正在探索新功能,讓網站能在使用較少資料的情況下提供相同的瀏覽體驗</translation>
+<translation id="7682601070171973634">Chromium 團隊正在研究新功能,設法讓網站減少存取個人資訊的情況,同時讓使用者享有相同的瀏覽體驗</translation>
 <translation id="7686590090926151193">Chromium 不是你的預設瀏覽器</translation>
 <translation id="7689606757190482937">進行同步處理即可在你的所有裝置上享有個人化的 Chromium 體驗</translation>
 <translation id="7745317241717453663">登出後,系統會將你的瀏覽資料從這個裝置上刪除。日後如要重新取得你的資料,請以 <ph name="USER_EMAIL" /> 身分登入 Chromium。</translation>
diff --git a/chrome/app/resources/generated_resources_af.xtb b/chrome/app/resources/generated_resources_af.xtb
index 3ae500e..40372f8 100644
--- a/chrome/app/resources/generated_resources_af.xtb
+++ b/chrome/app/resources/generated_resources_af.xtb
@@ -390,7 +390,6 @@
 <translation id="1333965224356556482">Moenie werwe toelaat om jou ligging te sien nie</translation>
 <translation id="1335282218035876586">Jou Chromebook ontvang nie meer sekuriteit- en sagtewareopdaterings nie. Gradeer jou Chromebook op vir die beste ervaring.</translation>
 <translation id="133535873114485416">Voorkeurinvoer</translation>
-<translation id="1335437153193710305">Jy kan kies watter profiel se wagwoorde jy wil sien</translation>
 <translation id="1335929031622236846">Skryf jou toestel in</translation>
 <translation id="1336902454946927954">Jou sekuriteitsleutel is gesluit omdat jou vingerafdruk nie herken kon word nie. Voer jou PIN in om dit te ontsluit.</translation>
 <translation id="1338631221631423366">Bind tans saam …</translation>
@@ -3328,7 +3327,6 @@
 <translation id="383669374481694771">Dit is algemene inligting oor hierdie toestel en hoe dit gebruik word (soos batteryvlak, stelsel- en programaktiwiteit en foute). Die data sal gebruik word om Android beter te maak, en sommige saamgestelde inligting sal ook Google-programme en -vennote, soos Android-ontwikkelaars, help om hul programme en produkte beter te maak.</translation>
 <translation id="3838085852053358637">Kon nie uitbreiding laai nie</translation>
 <translation id="3838486795898716504">Meer <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Voeg gestoorde wagwoorde by Google Wagwoordbestuurder</translation>
 <translation id="383891835335927981">Geen werwe is in- of uitgezoem nie</translation>
 <translation id="3839509547554145593">Aktiveer muisrolleesversnelling</translation>
 <translation id="3839516600093027468">Blokkeer <ph name="HOST" /> altyd om die knipbord te sien</translation>
diff --git a/chrome/app/resources/generated_resources_am.xtb b/chrome/app/resources/generated_resources_am.xtb
index 321ddff..7c04900c 100644
--- a/chrome/app/resources/generated_resources_am.xtb
+++ b/chrome/app/resources/generated_resources_am.xtb
@@ -389,7 +389,6 @@
 <translation id="1333965224356556482">ጣቢያዎች አካባቢዎን እንዲያዩ አይፍቀዱ</translation>
 <translation id="1335282218035876586">የእርስዎ Chromebook ከእንግዲህ የደህንነት እና የሶፍትዌር ዝማኔዎችን አይቀበልም። ምርጡን ተሞክሮ ለማግኘት የእርስዎን Chromebook ያልቁ።</translation>
 <translation id="133535873114485416">ተመራጭ ግቤት</translation>
-<translation id="1335437153193710305">የይለፍ ቃላቱን ሊመለከቱበት የሚፈልጉትን መገለጫ መምረጥ ይችላሉ</translation>
 <translation id="1335929031622236846">መሣሪያዎን ያስመዝግቡ</translation>
 <translation id="1336902454946927954">የእርስዎ የደህነት ቁልፍ የእርስዎ የጣት አሻራ ተለይቶ ሊታወቅ ስለሚችል ተቆልፏል። ለመክፈት የእርስዎን ፒን ያስገቡ።</translation>
 <translation id="1338631221631423366">በማጣመር ላይ…</translation>
@@ -3322,7 +3321,6 @@
 <translation id="383669374481694771">ይህ ስለዚህ መሣሪያ እና እንዴት ጥቅም ኣይ እንደሚውል በተመለከተ ያለ አጠቃላይ መረጃ (እንደ የባትሪ ደረጃ፣ የሥርዓትና የመተግበሪያ እንቅስቃሴ፣ እና ስህተቶች) ነው። ውሂቡ Androidን ለማሻሻል ጥቅም ላይ ይውላል፣ እና አንዳንድ የተዋሃደ መረጃ እንዲሁም የGoogle መተግበሪያዎች እና እንደ የAndroid ገንቢዎች ያሉ አጋሮች የእነሱ መተግበሪያዎች እና ምርቶች የተሻሉ እንዲያደርጉ ያግዛቸዋል።</translation>
 <translation id="3838085852053358637">ቅጥያን መጫን አልተሳካም</translation>
 <translation id="3838486795898716504">ተጨማሪ <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">የተቀመጡ የይለፍ ቃላትን ወደ Google የይለፍ ቃል አስተዳዳሪ ያክሉ</translation>
 <translation id="383891835335927981">ምንም ጣቢያዎች አልጎሉም ወይም አላነሱም</translation>
 <translation id="3839509547554145593">የመዳፊት ሽብለላ ማፍጠኛን አንቃ</translation>
 <translation id="3839516600093027468"><ph name="HOST" /> የቅንጥብ ሰሌዳው እንዳይመለከት አግድ</translation>
diff --git a/chrome/app/resources/generated_resources_ar.xtb b/chrome/app/resources/generated_resources_ar.xtb
index fc5849c..a7e99dfc 100644
--- a/chrome/app/resources/generated_resources_ar.xtb
+++ b/chrome/app/resources/generated_resources_ar.xtb
@@ -392,7 +392,6 @@
 <translation id="1333965224356556482">عدم السماح للمواقع الإلكترونية بالوصول إلى موقعك الجغرافي</translation>
 <translation id="1335282218035876586">‏لم تعُد تحديثات الأمان والبرامج متوفّرة لجهاز Chromebook الخاص بك. ننصحك بترقية جهاز Chromebook الخاص بك للحصول على أفضل تجربة استخدام.</translation>
 <translation id="133535873114485416">الإدخال المفضَّل</translation>
-<translation id="1335437153193710305">يمكنك اختيار الملف الشخصي الذي تريد الاطّلاع على كلمات المرور منه.</translation>
 <translation id="1335929031622236846">تسجيل الجهاز</translation>
 <translation id="1336902454946927954">تم قفل مفتاح الأمان لأنه لم يتم التعرّف على بصمة الإصبع. لفتح القفل، أدخِل رقم التعريف الشخصي.</translation>
 <translation id="1338631221631423366">جارٍ الإقران…</translation>
@@ -3320,7 +3319,6 @@
 <translation id="383669374481694771">‏هذه معلومات عامة حول هذا الجهاز وطريقة استخدامه (مثل مستوى البطارية، ونشاط النظام والتطبيقات، والأخطاء). وسيتم استخدام هذه البيانات في تحسين Android، كما ستساعد بعض المعلومات المجمّعة في تحسين تطبيقات Google والتطبيقات والمنتجات الخاصة بشركائها، مثل مطوّري البرامج المتوافقة مع Android.</translation>
 <translation id="3838085852053358637">فشل تحميل الإضافة</translation>
 <translation id="3838486795898716504">مزيد من <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">‏يمكنك إضافة كلمات المرور المحفوظة إلى "مدير كلمات المرور في Google".</translation>
 <translation id="383891835335927981">لم يتم تكبير أو تصغير أي مواقع إلكترونية</translation>
 <translation id="3839509547554145593">تفعيل تسريع تمرير الماوس</translation>
 <translation id="3839516600093027468">حظر <ph name="HOST" /> دائمًا من الاطلاع على الحافظة</translation>
diff --git a/chrome/app/resources/generated_resources_as.xtb b/chrome/app/resources/generated_resources_as.xtb
index 8ba8af0f..04719ffa 100644
--- a/chrome/app/resources/generated_resources_as.xtb
+++ b/chrome/app/resources/generated_resources_as.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">ছাইটক আপোনাৰ অৱস্থান চোৱাৰ অনুমতি নিদিব</translation>
 <translation id="1335282218035876586">আপোনাৰ Chromebookএ আৰু সুৰক্ষা আৰু ছফ্টৱেৰ সম্পৰ্কীয় আপডে’ট লাভ কৰি থকা নাই। শ্ৰেষ্ঠ অভিজ্ঞতা পাবলৈ আপোনাৰ Chromebook আপগ্ৰে’ড কৰক।</translation>
 <translation id="133535873114485416">পচন্দৰ ইনপুট</translation>
-<translation id="1335437153193710305">আপুনি সেই প্ৰ’ফাইলটো বাছনি কৰিব পাৰে য’ৰ পৰা আপুনি পাছৱৰ্ডসমূহ চাব বিচাৰে</translation>
 <translation id="1335929031622236846">আপোনাৰ ডিভাইচটো পঞ্জীয়ন কৰক</translation>
 <translation id="1336902454946927954">আপোনাৰ ফিংগাৰপ্ৰিণ্ট চিনাক্ত কৰিব পৰা নগ’ল বাবে আপোনাৰ সুৰক্ষা সম্পর্কীয় চাবিটো লক কৰা হৈছে। এইটো আনলক কৰিবলৈ, আপোনাৰ পিনটো দিয়ক।</translation>
 <translation id="1338631221631423366">পেয়াৰ কৰি থকা হৈছে…</translation>
@@ -3326,7 +3325,6 @@
 <translation id="383669374481694771">এইখিনি হৈছে এই ডিভাইচটোৰ আৰু সেইটোৰ ব্যৱহাৰৰ বিষয়ে (সাধাৰণ তথ্য যেনে- বেটাৰীৰ স্তৰ, ছিষ্টেম আৰু এপৰ কাৰ্যকলাপ আৰু তাত হোৱা আসোঁৱাহৰ)। এই ডেটাখিনি Androidক উন্নত কৰিবলৈ ব্যৱহাৰ কৰা হ’ব আৰু কিছুমান একত্ৰিত তথ্যই Google এপ্‌ আৰু Android বিকাশকৰ্তাৰ দৰে অংশীদাৰকো তেওঁলোকৰ এপ্‌ আৰু প্ৰ’ডাক্টক অধিক উন্নত কৰাত সহায় কৰিব।</translation>
 <translation id="3838085852053358637">এক্সটেনশ্বনটো ল’ড কৰিব পৰা নগ’ল</translation>
 <translation id="3838486795898716504">অধিক <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">ছেভ কৰা পাছৱৰ্ডসমূহ Google Password Managerত যোগ দিয়ক</translation>
 <translation id="383891835335927981">কোনো ছাইট জুম ইন বা আউট কৰা হোৱা নাই</translation>
 <translation id="3839509547554145593">মাউছ স্ক্ৰ’লৰ এক্সিলাৰেশ্বন সক্ষম কৰক</translation>
 <translation id="3839516600093027468"><ph name="HOST" />এ ক্লিপব’ৰ্ড চোৱাটো সদায় অৱৰোধ কৰক</translation>
diff --git a/chrome/app/resources/generated_resources_az.xtb b/chrome/app/resources/generated_resources_az.xtb
index e4d3d00..1cd914c 100644
--- a/chrome/app/resources/generated_resources_az.xtb
+++ b/chrome/app/resources/generated_resources_az.xtb
@@ -386,7 +386,6 @@
 <translation id="1333965224356556482">Saytlara məkanınıza baxmaq icazəsi verməyin</translation>
 <translation id="1335282218035876586">Chromebook artıq təhlükəsizlik və proqram təminatı güncəllənmələri qəbul etmir. Keyfiyyətli təcrübə üçün Chromebook-u təkmilləşdirin.</translation>
 <translation id="133535873114485416">Tərcih edilmiş daxiletmə</translation>
-<translation id="1335437153193710305">Parollarını görmək istədiyiniz profili seçə bilərsiniz</translation>
 <translation id="1335929031622236846">Cihazınızı qeydiyyatdan keçirin</translation>
 <translation id="1336902454946927954">Barmaq izinizi tanımaq mümkün olmadığı üçün təhlükəsizlik açarınız kilidləndi. Onu kiliddən çıxarmaq üçün PIN'nizi daxil edin.</translation>
 <translation id="1338631221631423366">Birləşdirilir…</translation>
@@ -3312,7 +3311,6 @@
 <translation id="383669374481694771">Bu ümumi məlumat bu cihaz və ondan istifadə haqqındadır (məsələn, batareya səviyyəsi, sistem və tətbiq fəaliyyəti və xətalar). Data Android məhsullarını təkmilləşdirmək məqsədilə istifadə olunacaq. Bəzi ümumiləşdirilmiş məlumatlar Google tətbiqlərinə və Android developerləri kimi partnyorlara tətbiq və məhsullarını təkmilləşdirməkdə kömək edəcək.</translation>
 <translation id="3838085852053358637">Artırmanı yükləmək alınmadı</translation>
 <translation id="3838486795898716504">Daha çox <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Saxlanmış parolları Google Parol Menecerinə əlavə edin</translation>
 <translation id="383891835335927981">Heç bir sayt yaxınlaşdırılmayıb və ya uzaqlaşdırılmayıb</translation>
 <translation id="3839509547554145593">Siçanın sürüşdürmə sürətini aktivləşdirin</translation>
 <translation id="3839516600093027468">Həmişə <ph name="HOST" /> hostunun buferi görməsini blok edin</translation>
diff --git a/chrome/app/resources/generated_resources_be.xtb b/chrome/app/resources/generated_resources_be.xtb
index fbf2138..33b19eb 100644
--- a/chrome/app/resources/generated_resources_be.xtb
+++ b/chrome/app/resources/generated_resources_be.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">Не даваць сайтам доступ да інфармацыі пра ваша месцазнаходжанне</translation>
 <translation id="1335282218035876586">Прылада Chromebook больш не атрымлівае абнаўленні праграмнага забеспячэння і сістэмы бяспекі. Для максімальнай зручнасці работы абнавіце Chromebook.</translation>
 <translation id="133535873114485416">Пажаданы спосаб уводу</translation>
-<translation id="1335437153193710305">Можна выбраць профіль, пароль ад якога вы хочаце паглядзець</translation>
 <translation id="1335929031622236846">Зарэгіструйце прыладу</translation>
 <translation id="1336902454946927954">Ключ бяспекі заблакіраваны, бо ваш адбітак пальца не быў распазнаны. Каб разблакіраваць ключ, увядзіце PIN-код.</translation>
 <translation id="1338631221631423366">Ідзе спалучэнне…</translation>
@@ -3314,7 +3313,6 @@
 <translation id="383669374481694771">Гэта агульная інфармацыя пра гэту прыладу і яе выкарыстанне (напрыклад, пра ўзровень зараду акумулятара, дзеянні ў сістэме і праграмах, памылкі). Даныя будуць выкарыстоўвацца для ўдасканалення сістэмы Android, а пэўная згрупаваная інфармацыя дапаможа ўдасканаліць праграмы Google і будзе карыснай для партнёраў кампаніі, напрыклад для распрацоўшчыкаў Android, у паляпшэнні праграм і прадуктаў.</translation>
 <translation id="3838085852053358637">Не ўдалося загрузіць пашырэнне</translation>
 <translation id="3838486795898716504">Яшчэ адна старонка "<ph name="PAGE_TITLE" />"</translation>
-<translation id="3838487810283346084">Дадавайце захаваныя паролі ў Менеджар пароляў Google</translation>
 <translation id="383891835335927981">Маштаб на сайтах не змяняўся</translation>
 <translation id="3839509547554145593">Уключыць паскарэнне прагорткі мышшу</translation>
 <translation id="3839516600093027468">Заўсёды блакіраваць хосту <ph name="HOST" /> доступ да буфера абмену</translation>
diff --git a/chrome/app/resources/generated_resources_bg.xtb b/chrome/app/resources/generated_resources_bg.xtb
index 1053913b..d9b32a76 100644
--- a/chrome/app/resources/generated_resources_bg.xtb
+++ b/chrome/app/resources/generated_resources_bg.xtb
@@ -390,7 +390,6 @@
 <translation id="1333965224356556482">Да не се разрешава на сайтовете да виждат местоположението ви</translation>
 <translation id="1335282218035876586">Вашият Chromebook вече не получава актуализации за сигурност и софтуерни актуализации. За най-добра практическа работа преминете към нов Chromebook.</translation>
 <translation id="133535873114485416">Предпочитано въвеждане</translation>
-<translation id="1335437153193710305">Можете да изберете потребителския профил, от който да виждате паролите</translation>
 <translation id="1335929031622236846">Регистрирайте устройството си</translation>
 <translation id="1336902454946927954">Ключът ви за сигурност е заключен, защото пръстовият ви отпечатък не бе разпознат. Въведете ПИН кода си, за да отключите ключа.</translation>
 <translation id="1338631221631423366">Извършва се сдвояване...</translation>
@@ -3324,7 +3323,6 @@
 <translation id="383669374481694771">Това е обща информация за устройството и употребата му (например за нивото на батерията, активността на системата и приложенията, както и за грешките). Тези данни ще се използват за подобряването на Android, а част от обобщената информация ще помогне и на приложенията и партньорите ни, например програмисти за Android, да усъвършенстват приложенията и продуктите си.</translation>
 <translation id="3838085852053358637">Зареждането на разширението не бе успешно</translation>
 <translation id="3838486795898716504">Още от „<ph name="PAGE_TITLE" />“</translation>
-<translation id="3838487810283346084">Добавяне на запазените пароли към Google Мениджър на пароли</translation>
 <translation id="383891835335927981">Няма сайтове с увеличен или намален мащаб</translation>
 <translation id="3839509547554145593">Активиране на ускорено превъртане с мишката</translation>
 <translation id="3839516600093027468">Забраняване винаги на <ph name="HOST" /> да преглежда буферната памет</translation>
diff --git a/chrome/app/resources/generated_resources_bn.xtb b/chrome/app/resources/generated_resources_bn.xtb
index 85522f57..53490d2 100644
--- a/chrome/app/resources/generated_resources_bn.xtb
+++ b/chrome/app/resources/generated_resources_bn.xtb
@@ -392,7 +392,6 @@
 <translation id="1333965224356556482">সাইটগুলিকে আপনার লোকেশন দেখার অনুমতি দেয় না</translation>
 <translation id="1335282218035876586">আপনার Chromebook আর নিরাপত্তা এবং সফ্টওয়্যার সংক্রান্ত আপডেট পাচ্ছে না। সেরা অভিজ্ঞতার জন্য আপনার Chromebook আপগ্রেড করুন।</translation>
 <translation id="133535873114485416">পছন্দের ইনপুট</translation>
-<translation id="1335437153193710305">আপনি যে প্রোফাইলের জন্য পাসওয়ার্ড দেখতে চান সেটি বেছে নিতে পারেন</translation>
 <translation id="1335929031622236846">আপনার ডিভাইস এনরোল করুন</translation>
 <translation id="1336902454946927954">আপনার 'নিরাপত্তা' কী লক করে রাখা হয়েছে, কারণ আপনার ফিঙ্গারপ্রিন্ট শনাক্ত করা যায়নি। এটি আনলক করতে, আপনার পিন এন্টার করুন।</translation>
 <translation id="1338631221631423366">পেয়ার করা হচ্ছে...</translation>
@@ -3142,6 +3141,7 @@
 <translation id="369489984217678710">পাসওয়ার্ড এবং অন্যান্য সাইন-ইন ডেটা</translation>
 <translation id="369522892592566391">{NUM_FILES,plural, =0{নিরাপত্তা পরীক্ষা করা হয়েছে। আপনার ডেটা আপলোড করা হবে।}=1{নিরাপত্তা পরীক্ষা করা হয়েছে। আপনার ফাইল আপলোড করা হবে।}one{নিরাপত্তা পরীক্ষা করা হয়েছে। আপনার ফাইলগুলি আপলোড করা হবে।}other{নিরাপত্তা পরীক্ষা করা হয়েছে। আপনার ফাইলগুলি আপলোড করা হবে।}}</translation>
 <translation id="3696817060563289264">টেক্সট শনাক্তকরণ ফাইল ডাউনলোড করা হয়েছে</translation>
+<translation id="3697716475445175867">শেষ যখন খোলা হয়েছে</translation>
 <translation id="3698471669415859717">রিভিউ হয়ে গেছে</translation>
 <translation id="3698825735945432002">ফিল্টারের ধরন</translation>
 <translation id="3699624789011381381">ইমেল আইডি</translation>
@@ -3330,7 +3330,6 @@
 <translation id="383669374481694771">আপনার ডিভাইস এবং সেটি কীভাবে ব্যবহার করবেন (যেমন, ব্যাটারি লেভেল, সিস্টেম ও অ্যাপ অ্যাক্টিভিটি এবং সমস্যা) সেই বিষয়ে কিছু সাধারণ তথ্য এখানে দেওয়া হয়েছে। এই ডেটা Android পরিষেবাকে আরও ভাল করতে ব্যবহার করা হবে। এছাড়া, কিছু একত্রিত তথ্য Google অ্যাপ এবং Android ডেভেলপারদের মতন পার্টনারদের তাদের তৈরি করা অ্যাপ ও প্রোডাক্টের মান আরও ভাল করতে সাহায্য করবে।</translation>
 <translation id="3838085852053358637">এক্সটেনশন লোড করা যায়নি</translation>
 <translation id="3838486795898716504">আরও <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">সেভ করা পাসওয়ার্ড Google Password Manager-এ যোগ করুন</translation>
 <translation id="383891835335927981">কোনো সাইটের জুম বাড়ানো বা কমানো হয়নি</translation>
 <translation id="3839509547554145593">মাউসের মাধ্যমে স্ক্রল করার ক্ষেত্রে অ্যাক্সিলারেশন চালু করুন</translation>
 <translation id="3839516600093027468">ক্লিপবোর্ড দেখা থেকে <ph name="HOST" /> কে সবসময় ব্লক করুন</translation>
@@ -6376,6 +6375,7 @@
 <translation id="6596816719288285829">আইপি অ্যাড্রেস</translation>
 <translation id="6597017209724497268">নমুনাগুলি</translation>
 <translation id="6597331566371766302">নিচের এক্সটেনশন আপনার অ্যাডমিনিস্ট্রেটরের মাধ্যমে ব্লক করা হয়েছে:</translation>
+<translation id="659894938503552850">সবচেয়ে নতুন</translation>
 <translation id="6601262427770154296">ব্যবহারকারীর অভিধান ম্যানেজ করুন</translation>
 <translation id="6601612474695404578">পৃষ্ঠা লোড করতে কিছু সাইট থার্ড পার্টি কুকি ব্যবহার করে। সাইট কাজ না করলে আপনি কুকি অনুমোদন করে চেষ্টা করতে পারেন।</translation>
 <translation id="6602937173026466876">আপনার প্রিন্টার অ্যাক্সেস করুন</translation>
@@ -8158,6 +8158,7 @@
 <translation id="8161293209665121583">ওয়েব পৃষ্ঠার রিডার মোড</translation>
 <translation id="8161604891089629425">আউটলাইন ফন্ট</translation>
 <translation id="8162984717805647492">{NUM_TABS,plural, =1{ট্যাবটি নতুন উইন্ডোতে খুলুন}one{ট্যাবগুলি নতুন উইন্ডোতে খুলুন}other{ট্যাবগুলি নতুন উইন্ডোতে খুলুন}}</translation>
+<translation id="8163708146810922598">সবচেয়ে পুরনো</translation>
 <translation id="8165997195302308593">Crostini-এর পোর্ট ফরওয়ার্ড করা</translation>
 <translation id="816704878106051517">{COUNT,plural, =1{একটি ফোন নম্বর}one{#টি ফোন নম্বর}other{#টি ফোন নম্বর}}</translation>
 <translation id="8168071266284693455">আপনার সব ডিভাইসে বুকমার্ক, পাসওয়ার্ড, ইতিহাস এবং আরও অনেক কিছু সিঙ্ক করা আছে</translation>
@@ -8672,6 +8673,7 @@
 <translation id="8637688295594795546">সিস্টেম আপডেট উপলভ্য৷ ডাউনলোড করতে প্রস্তুত হচ্ছে...</translation>
 <translation id="8639047128869322042">ক্ষতিকর সফ্টওয়্যার খোঁজা হচ্ছে...</translation>
 <translation id="8639635302972078117">ব্যবহার এবং ডায়াগনস্টিক বিষয়ক ডেটা পাঠান। বর্তমানে এই ডিভাইসটি অটোমেটিক Google-কে ডায়াগনস্টিক, ডিভাইস এবং অ্যাপ ব্যবহারের ডেটা পাঠাচ্ছে। এটি আপনার সন্তানকে শনাক্ত করতে ব্যবহার করা হবে না এবং সিস্টেম ও অ্যাপের স্টেবিলিটি বাড়াতে ও অন্যান্য উন্নতিতে সাহায্য করবে। কিছু একত্রিত করা ডেটা Android ডেভেলপারের মতো Google অ্যাপ এবং পার্টনারদেরও সাহায্য করবে। অতিরিক্ত 'ওয়েব ও অ্যাপ অ্যাক্টিভিটি' সেটিং আপনার সন্তানের ডিভাইসের জন্য চালু করা থাকলে, এই ডেটা তাদের Google অ্যাকাউন্টে সেভ করা হতে পারে।</translation>
+<translation id="8640575194957831802">শেষ যখন খোলা হয়েছে</translation>
 <translation id="8642900771896232685">২ সেকেন্ড</translation>
 <translation id="8642947597466641025">পাঠ্যকে আরও বড় করুন</translation>
 <translation id="8643403533759285912">গ্রুপ মুছুন</translation>
diff --git a/chrome/app/resources/generated_resources_bs.xtb b/chrome/app/resources/generated_resources_bs.xtb
index 05f327d..a867fca8 100644
--- a/chrome/app/resources/generated_resources_bs.xtb
+++ b/chrome/app/resources/generated_resources_bs.xtb
@@ -393,7 +393,6 @@
 <translation id="1333965224356556482">Nemoj dozvoliti web lokacijama prikaz lokacije</translation>
 <translation id="1335282218035876586">Chromebook više ne prima sigurnosna i softverska ažuriranja. Nadogradite Chromebook za najbolje iskustvo.</translation>
 <translation id="133535873114485416">Preferirani način unosa</translation>
-<translation id="1335437153193710305">Možete odabrati profil s kojeg želite vidjeti lozinke</translation>
 <translation id="1335929031622236846">Prijavite uređaj</translation>
 <translation id="1336902454946927954">Vaš sigurnosni ključ je zaključan jer prepoznavanje vašeg otiska prsta nije uspjelo. Da ga otključate, unesite PIN.</translation>
 <translation id="1338631221631423366">Uparivanje...</translation>
@@ -3329,7 +3328,6 @@
 <translation id="383669374481694771">Ovo su opće informacije o ovom uređaju i načinu na koji se koristi (kao što je nivo napunjenosti baterije, aktivnosti sistema i aplikacija te greške). Ovi podaci će se koristiti da se poboljša Android, a neki zbirni podaci će također pomoći Google aplikacijama i partnerima, kao što su Androidovi programeri, da poboljšaju svoje aplikacije i proizvode.</translation>
 <translation id="3838085852053358637">Učitavanje ekstenzije nije uspjelo</translation>
 <translation id="3838486795898716504">Više: <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Dodajte sačuvane lozinke u Google upravitelja lozinki</translation>
 <translation id="383891835335927981">Nijedna web lokacija nije uvećana ili umanjena</translation>
 <translation id="3839509547554145593">Omogući ubrzanje klizanja miša</translation>
 <translation id="3839516600093027468">Uvijek blokiraj pristup međumemoriji web lokaciji <ph name="HOST" /></translation>
diff --git a/chrome/app/resources/generated_resources_ca.xtb b/chrome/app/resources/generated_resources_ca.xtb
index 43a652a..9b6f174 100644
--- a/chrome/app/resources/generated_resources_ca.xtb
+++ b/chrome/app/resources/generated_resources_ca.xtb
@@ -388,7 +388,6 @@
 <translation id="1333965224356556482">No permetis que els llocs web vegin la teva ubicació</translation>
 <translation id="1335282218035876586">El teu Chromebook ja no rep actualitzacions de seguretat ni de programari. Compra't un Chromebook nou per gaudir de la millor experiència.</translation>
 <translation id="133535873114485416">Mètode d'introducció preferit</translation>
-<translation id="1335437153193710305">Pots triar de quin perfil vols veure les contrasenyes</translation>
 <translation id="1335929031622236846">Inscriu el dispositiu</translation>
 <translation id="1336902454946927954">La clau de seguretat està bloquejada perquè la teva empremta digital no s'ha pogut reconèixer. Per desbloquejar-la, introdueix el PIN.</translation>
 <translation id="1338631221631423366">S'està vinculant...</translation>
@@ -3313,7 +3312,6 @@
 <translation id="383669374481694771">Es tracta d'informació general sobre aquest dispositiu i sobre com es fa servir, com ara els errors, el nivell de bateria i l'activitat al sistema i en aplicacions. Les dades s'utilitzaran per millorar Android i part de la informació agregada també ajudarà les aplicacions i els partners de Google, com ara els desenvolupadors d'Android, a millorar les seves aplicacions i els seus productes.</translation>
 <translation id="3838085852053358637">No s'ha pogut carregar l'extensió</translation>
 <translation id="3838486795898716504">Més <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Afegeix les contrasenyes desades al gestor de contrasenyes de Google</translation>
 <translation id="383891835335927981">No s'ha ampliat ni reduït cap lloc</translation>
 <translation id="3839509547554145593">Activa l'acceleració de desplaçament del ratolí tàctil</translation>
 <translation id="3839516600093027468">No permetis mai que <ph name="HOST" /> vegi el porta-retalls</translation>
diff --git a/chrome/app/resources/generated_resources_cs.xtb b/chrome/app/resources/generated_resources_cs.xtb
index ab50e6fcb0..7c2742a 100644
--- a/chrome/app/resources/generated_resources_cs.xtb
+++ b/chrome/app/resources/generated_resources_cs.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Pro Linux je doporučeno alespoň <ph name="INSTALL_SIZE" /> místa. Místo uvolníte smazáním souborů ze zařízení.</translation>
 <translation id="1038643060055067718">Řádky:</translation>
 <translation id="1039337018183941703">Neplatný nebo poškozený soubor</translation>
+<translation id="1040761927998636252">Záložka bez názvu pro <ph name="URL" /></translation>
 <translation id="1041175011127912238">Tato stránka nereaguje</translation>
 <translation id="1041263367839475438">Dostupná zařízení</translation>
 <translation id="1042174272890264476">Počítač je dodáván s integrovanou knihovnou RLZ prohlížeče <ph name="SHORT_PRODUCT_NAME" />. RLZ přiřadí značku, která slouží k vyhodnocení vyhledávání a využití prohlížečů <ph name="SHORT_PRODUCT_NAME" />, které pocházejí z konkrétní propagační kampaně. Tato značka není jedinečná a neumožňuje osobní identifikaci. Tyto značky jsou někdy v prohlížeči <ph name="PRODUCT_NAME" /> uváděny v dotazech ve Vyhledávání Google.</translation>
@@ -389,7 +390,6 @@
 <translation id="1333965224356556482">Nepovolovat webům přístup k poloze</translation>
 <translation id="1335282218035876586">Váš Chromebook již nedostává aktualizace zabezpečení a softwaru. Pokud chcete, aby vše fungovalo co nejlépe, upgradujte na nový.</translation>
 <translation id="133535873114485416">Preferovaná metoda zadávání</translation>
-<translation id="1335437153193710305">Můžete vybrat profil, ze kterého chcete zobrazovat hesla</translation>
 <translation id="1335929031622236846">Zaregistrujte své zařízení</translation>
 <translation id="1336902454946927954">Bezpečnostní klíč je uzamčen, protože se nepodařilo rozpoznat váš otisk prstu. Chcete-li ho odemknout, zadejte PIN.</translation>
 <translation id="1338631221631423366">Párování…</translation>
@@ -3314,7 +3314,6 @@
 <translation id="383669374481694771">Toto jsou obecné informace o zařízení a způsobu jeho používání (např. stav baterie, aktivita systému a aplikací nebo chyby). Data budou využívána k vylepšení systému Android. Některé souhrnné informace pomohou s vylepšováním aplikací a služeb také našim partnerům, například vývojářům Androidu.</translation>
 <translation id="3838085852053358637">Rozšíření se nepodařilo načíst</translation>
 <translation id="3838486795898716504">Další stránka <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Přidejte si uložená hesla do Správce hesel Google</translation>
 <translation id="383891835335927981">Žádný web nemá nastaveno přiblížení či oddálení zobrazení</translation>
 <translation id="3839509547554145593">Zapnout zrychlení posouvání myší</translation>
 <translation id="3839516600093027468">Webu <ph name="HOST" /> přístup ke schránce vždy blokovat</translation>
diff --git a/chrome/app/resources/generated_resources_cy.xtb b/chrome/app/resources/generated_resources_cy.xtb
index 1333a96..144b44c2 100644
--- a/chrome/app/resources/generated_resources_cy.xtb
+++ b/chrome/app/resources/generated_resources_cy.xtb
@@ -394,7 +394,6 @@
 <translation id="1333965224356556482">Peidio â chaniatáu i wefannau weld eich lleoliad</translation>
 <translation id="1335282218035876586">Nid yw eich Chromebook bellach yn derbyn diweddariadau diogelwch a meddalwedd. Uwchraddiwch eich Chromebook ar gyfer y profiad gorau.</translation>
 <translation id="133535873114485416">Mewnbwn a ffefrir</translation>
-<translation id="1335437153193710305">Gallwch ddewis y proffil rydych chi am weld y cyfrineiriau ohono</translation>
 <translation id="1335929031622236846">Cofrestrwch eich dyfais</translation>
 <translation id="1336902454946927954">Mae'ch allwedd ddiogelwch wedi'i chloi oherwydd na ellid adnabod eich olion bysedd. I'w ddatgloi, rhowch eich PIN.</translation>
 <translation id="1338631221631423366">Wrthi'n paru…</translation>
@@ -3331,7 +3330,6 @@
 <translation id="383669374481694771">Dyma wybodaeth gyffredinol am y ddyfais hon a sut mae'n cael ei defnyddio (megis lefel batri, gweithgarwch system ac apiau, a gwallau). Defnyddir y data i wella Android, a bydd rhywfaint o wybodaeth gyfun hefyd yn helpu apiau a phartneriaid Google, megis datblygwyr Android, i wella eu hapiau a'u cynhyrchion.</translation>
 <translation id="3838085852053358637">Methu â llwytho'r estyniad</translation>
 <translation id="3838486795898716504">Rhagor o <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Ychwanegu cyfrineiriau sydd wedi'u cadw at Reolwr Cyfrineiriau Google</translation>
 <translation id="383891835335927981">Nid oes unrhyw wefannau wedi cael eu chwyddo na'u pellhau</translation>
 <translation id="3839509547554145593">Galluogi cyflymu sgrolio gyda llygoden</translation>
 <translation id="3839516600093027468">Rhwystro <ph name="HOST" /> bob amser rhag gweld y clipfwrdd</translation>
diff --git a/chrome/app/resources/generated_resources_da.xtb b/chrome/app/resources/generated_resources_da.xtb
index 2d3dab5..c94dbe7 100644
--- a/chrome/app/resources/generated_resources_da.xtb
+++ b/chrome/app/resources/generated_resources_da.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Du bør have mindst <ph name="INSTALL_SIZE" /> ledig plads for at installere Linux. Du kan frigøre plads ved at slette filer fra enheden.</translation>
 <translation id="1038643060055067718">Linjer:</translation>
 <translation id="1039337018183941703">Ugyldig eller beskadiget fil</translation>
+<translation id="1040761927998636252">Unavngivet bogmærke for <ph name="URL" /></translation>
 <translation id="1041175011127912238">Denne side svarer ikke</translation>
 <translation id="1041263367839475438">Tilgængelige enheder</translation>
 <translation id="1042174272890264476">Computeren leveres også med <ph name="SHORT_PRODUCT_NAME" />s RLZ-samling indbygget. RLZ tildeler et ikke-unikt, ikke-personligt identificerbart tag til at måle søgninger og <ph name="SHORT_PRODUCT_NAME" />-brug, der er drevet af en bestemt kampagne. Disse etiketter vises nogle gange i Googles søgeforespørgsler i <ph name="PRODUCT_NAME" />.</translation>
@@ -183,7 +184,7 @@
 <translation id="1150565364351027703">Solbriller</translation>
 <translation id="1151917987301063366">Tillad altid, at <ph name="HOST" /> kan få adgang til sensorer</translation>
 <translation id="1152181876167086799">Tillad, at alle udvidelser læser og ændrer <ph name="SITE_NAME" /></translation>
-<translation id="1152346050262092795">Angiv din adgangskode igen for at bekræfte din konto.</translation>
+<translation id="1152346050262092795">Angiv din adgangskode igen for at verificere din konto.</translation>
 <translation id="1153636665119721804">Google-programmet Avanceret beskyttelse</translation>
 <translation id="1155545602507378023">Nej, kun denne enhed</translation>
 <translation id="1155816283571436363">Opretter forbindelse til din telefon</translation>
@@ -390,7 +391,6 @@
 <translation id="1333965224356556482">Tillad ikke, at websites ser din lokation</translation>
 <translation id="1335282218035876586">Din Chromebook modtager ikke længere sikkerheds- og softwareopdateringer. Opgrader din Chromebook for at få den bedst mulige oplevelse.</translation>
 <translation id="133535873114485416">Foretrukket input</translation>
-<translation id="1335437153193710305">Du kan vælge den profil, du vil se adgangskoderne fra</translation>
 <translation id="1335929031622236846">Tilmeld din enhed</translation>
 <translation id="1336902454946927954">Din sikkerhedsnøgle er låst, fordi dit fingeraftryk ikke blev genkendt. Du kan låse den op ved at angive din pinkode.</translation>
 <translation id="1338631221631423366">Parrer...</translation>
@@ -1009,7 +1009,7 @@
 <translation id="1831848493690504725">Vi kan ikke få forbindelse til Google via det forbundne netværk. Prøv at vælge et andet netværk eller tjekke dine netværksindstillinger eller proxyindstillinger (hvis du bruger en proxy).</translation>
 <translation id="1832459821645506983">Ja tak</translation>
 <translation id="1832511806131704864">Telefonændring opdateret</translation>
-<translation id="1832848789136765277">Bekræft din identitet for at sikre, at du altid har adgang til dine synkroniserede data</translation>
+<translation id="1832848789136765277">Verificer din identitet for at sikre, at du altid har adgang til dine synkroniserede data</translation>
 <translation id="1834503245783133039">Downloaden blev ikke fuldført: <ph name="FILE_NAME" /></translation>
 <translation id="1835261175655098052">Opgraderer Linux</translation>
 <translation id="1835612721186505600">Brug kameratilladelsen til at give apps og websites adgang</translation>
@@ -1259,7 +1259,7 @@
 <translation id="2055585478631012616">Du logges ud af disse websites, også i åbne faner</translation>
 <translation id="205560151218727633">Google Assistent-logo</translation>
 <translation id="2058456167109518507">Der blev registreret en enhed</translation>
-<translation id="2058581283817163201">Bekræft med denne telefon</translation>
+<translation id="2058581283817163201">Verificer med denne telefon</translation>
 <translation id="2059913712424898428">Tidszone</translation>
 <translation id="2060375639911876205">Fjern eSIM-profil</translation>
 <translation id="2061366302742593739">Intet at vise</translation>
@@ -2610,7 +2610,7 @@
 <translation id="3214531106883826119"><ph name="BEGIN_BOLD" />Bemærk!<ph name="END_BOLD" /> En lignende stemme eller en optagelse af den kan muligvis bruges til at få adgang til det personlige indhold, der tilhører <ph name="SUPERVISED_USER_NAME" />.</translation>
 <translation id="3217843140356091325">Vil du oprette en genvej?</translation>
 <translation id="321834671654278338">Afinstallationsprogram til Linux</translation>
-<translation id="3220943972464248773">Bekræft din identitet for at synkronisere dine adgangskoder</translation>
+<translation id="3220943972464248773">Verificer din identitet for at synkronisere dine adgangskoder</translation>
 <translation id="3222066309010235055">Forhåndsgengivelse: <ph name="PRERENDER_CONTENTS_NAME" /></translation>
 <translation id="3222779980972075989">Slut til <ph name="USB_VM_NAME" /></translation>
 <translation id="3223531857777746191">Knappen Nulstil</translation>
@@ -2851,7 +2851,7 @@
 <translation id="3439970425423980614">Åbner PDF i fremviseren</translation>
 <translation id="3440663250074896476">Flere handlinger for <ph name="BOOKMARK_NAME" /></translation>
 <translation id="3441653493275994384">Skærm</translation>
-<translation id="3441663102605358937">Log ind på <ph name="ACCOUNT" /> igen for at bekræfte denne konto</translation>
+<translation id="3441663102605358937">Log ind på <ph name="ACCOUNT" /> igen for at verificere denne konto</translation>
 <translation id="3442674350323953953">Giv Google tilladelse til at bruge dine hardwaredata til at hjælpe med at forbedre <ph name="DEVICE_OS" />. Hvis du afviser, bliver disse data stadig sendt til Google med henblik på at levere de rigtige opdateringer, men de bliver ikke gemt eller brugt udover det.</translation>
 <translation id="3443744348829035122"><ph name="BRAND" /> oplevede timeout</translation>
 <translation id="3443754338602062261">Du har allerede adgangskoder til disse konti i <ph name="BRAND" />. Hvis du vælger at importere én af adgangskoderne nedenfor, vil den erstatte den eksisterende adgangskode.</translation>
@@ -3328,7 +3328,6 @@
 <translation id="383669374481694771">Dette er generelle oplysninger om denne enhed og brugen af den (f.eks. batteriniveau, system- og appaktivitet samt fejl). Dataene bruges til at forbedre Android, og visse samlede oplysninger kan også hjælpe partnere som f.eks. Android-udviklere med at forbedre deres apps og produkter.</translation>
 <translation id="3838085852053358637">Udvidelsen kunne ikke indlæses</translation>
 <translation id="3838486795898716504">Flere <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Føj gemte adgangskoder til Google Adgangskodeadministrator</translation>
 <translation id="383891835335927981">Der er ikke zoomet ind eller ud på nogen websites</translation>
 <translation id="3839509547554145593">Aktivér acceleration af rulning på mus</translation>
 <translation id="3839516600093027468">Bloker altid <ph name="HOST" /> fra at se udklipsholderen</translation>
@@ -3349,7 +3348,7 @@
 <translation id="3854976556788175030">Papirbakken er fuld</translation>
 <translation id="3855441664322950881">Pak udvidelse</translation>
 <translation id="3855676282923585394">Importer bogmærker og indstillinger...</translation>
-<translation id="3856096718352044181">Bekræft, at dette er en gyldig udbyder, eller prøv igen senere</translation>
+<translation id="3856096718352044181">Verificer, at dette er en gyldig udbyder, eller prøv igen senere</translation>
 <translation id="3856800405688283469">Vælg tidszone</translation>
 <translation id="3857807444929313943">Løft, og berør igen</translation>
 <translation id="3858860766373142691">Navn</translation>
@@ -3999,7 +3998,7 @@
 <translation id="4445446646109808714">Slutbrugerlicensaftale: <ph name="EULA_LINK" /></translation>
 <translation id="4446933390699670756">Spejlet</translation>
 <translation id="4448914100439890108">Skjul adgangskoden for <ph name="USERNAME" /> på <ph name="DOMAIN" /></translation>
-<translation id="4449948729197510913">Dit brugernavn tilhører din organisations virksomhedskonto. Hvis du vil tilmelde enheder på kontoen, skal du først bekræfte ejerskab af domænet i Administrationskonsol. Du skal have administratorrettigheder på kontoen for at bekræfte.</translation>
+<translation id="4449948729197510913">Dit brugernavn tilhører din organisations virksomhedskonto. Hvis du vil tilmelde enheder på kontoen, skal du først verificere ejerskab af domænet i Administrationskonsol. Du skal have administratorrettigheder på kontoen for at verificere.</translation>
 <translation id="4449996769074858870">Denne fane afspiller lyd.</translation>
 <translation id="4450974146388585462">Diagnosticer</translation>
 <translation id="445099924538929605"><ph name="DEVICE_OS" /> har registreret en aktiv TMP-enhed, som kan gemme dine data på en mere sikker måde.</translation>
@@ -4147,7 +4146,7 @@
 <translation id="457386861538956877">Flere...</translation>
 <translation id="4574741712540401491">•  <ph name="LIST_ITEM_TEXT" /></translation>
 <translation id="4576541033847873020">Par Bluetooth-enhed</translation>
-<translation id="4576763597586015380">Hvis du vil fortsætte med at gemme adgangskoder på din Google-konto, skal du bekræfte din identitet</translation>
+<translation id="4576763597586015380">Hvis du vil fortsætte med at gemme adgangskoder på din Google-konto, skal du verificere din identitet</translation>
 <translation id="4579453506923101210">Glem den tilsluttede telefon</translation>
 <translation id="4579581181964204535"><ph name="HOST_NAME" /> kunne ikke castes.</translation>
 <translation id="4579876313423027742">Gå til <ph name="LINK_BEGIN" />indstillingerne for Chrome-browseren<ph name="LINK_END" /> for at gå til browsernotifikationerne</translation>
@@ -6096,7 +6095,7 @@
 <translation id="6361850914223837199">Info om fejl:</translation>
 <translation id="6362853299801475928">&amp;Rapporter et problem...</translation>
 <translation id="6363786367719063276">Se logfiler</translation>
-<translation id="6363990818884053551">Bekræft din identitet for at starte synkroniseringen</translation>
+<translation id="6363990818884053551">Verificer din identitet for at starte synkroniseringen</translation>
 <translation id="6365069501305898914">Facebook</translation>
 <translation id="6365411474437319296">Tilføj familie og venner</translation>
 <translation id="6367097275976877956">Vil du aktivere ChromeVox, der er den indbyggede skærmlæser til ChromeOS? Tryk på mellemrumstasten for at aktivere.</translation>
@@ -6626,7 +6625,7 @@
 <translation id="6824584962142919697">&amp;Inspect elements (Undersøg elementer)</translation>
 <translation id="6824725898506587159">Administrer sprog</translation>
 <translation id="6825184156888454064">Sorter efter navn</translation>
-<translation id="6826872289184051766">Bekræft via USB</translation>
+<translation id="6826872289184051766">Verificer via USB</translation>
 <translation id="6827121912381363404">Tillad, at alle udvidelser kan læse og ændre <ph name="PERMITTED_SITE" /></translation>
 <translation id="6827517233063803343">Dine apps og indstillinger synkroniseres på tværs af alle de ChromeOS-enheder, hvor du er logget ind med din Google-konto. Du kan se muligheder for synkronisering af browseren i <ph name="LINK_BEGIN" />indstillingerne for Chrome<ph name="LINK_END" />.</translation>
 <translation id="6827767090350758381">Gamle versioner af Chrome-apps kan ikke åbnes på Windows-enheder efter december 2022. Kontakt din administrator, hvis du vil opdatere til en ny version af denne app eller fjerne den.</translation>
@@ -6650,7 +6649,7 @@
 <translation id="6840214587087739194">Adressen er slettet</translation>
 <translation id="6841143363521180029">Krypteret</translation>
 <translation id="6841186874966388268">Fejl</translation>
-<translation id="6842136130964845393">Bekræft din identitet for at sikre, at du altid har adgang til dine gemte adgangskoder</translation>
+<translation id="6842136130964845393">Verificer din identitet for at sikre, at du altid har adgang til dine gemte adgangskoder</translation>
 <translation id="6842749380892715807">XML-websitelister blev sidst downloadet <ph name="LAST_DATE_DOWNLOAD" />.</translation>
 <translation id="6842868554183332230">Websites registrerer som regel, hvornår du aktivt bruger din enhed, så de kan angive din tilgængelighed i chatapps</translation>
 <translation id="6843264316370513305">Fejlretning af netværk</translation>
@@ -7427,7 +7426,7 @@
 <translation id="7553242001898162573">Angiv din adgangskode</translation>
 <translation id="755472745191515939">Din administrator tillader ikke brug af dette sprog</translation>
 <translation id="7554791636758816595">Ny fane</translation>
-<translation id="7556033326131260574">Smart Lock kunne ikke bekræfte din konto. Angiv din adgangskode for at få adgang.</translation>
+<translation id="7556033326131260574">Smart Lock kunne ikke verificere din konto. Angiv din adgangskode for at få adgang.</translation>
 <translation id="7556242789364317684"><ph name="SHORT_PRODUCT_NAME" /> kan ikke gendanne dine indstillinger. Denne fejl kan korrigeres ved at lade <ph name="SHORT_PRODUCT_NAME" /> nulstille din enhed med Powerwash.</translation>
 <translation id="7557194624273628371">Omdirigering af port i Linux</translation>
 <translation id="7557411183415085169">Linux er ved at løbe tør for diskplads</translation>
@@ -8134,7 +8133,7 @@
 <translation id="8147346945017130012">Vær med til at forbedre funktionerne og ydeevnen i Chrome og ChromeOS ved automatisk at sende nedbrudsrapporter samt diagnostik- og brugsdata til Google.</translation>
 <translation id="8147900440966275470">Der blev fundet <ph name="NUM" /> fane</translation>
 <translation id="8148760431881541277">Begræns login</translation>
-<translation id="8149564499626272569">Bekræft via din telefon med et USB-kabel</translation>
+<translation id="8149564499626272569">Verificer via din telefon med et USB-kabel</translation>
 <translation id="815114315010033526">Brug QR-kode i stedet</translation>
 <translation id="8151638057146502721">Konfigurer</translation>
 <translation id="8154790740888707867">Ingen fil</translation>
@@ -8882,7 +8881,7 @@
 <translation id="881782782501875829">Tilføj portnummer</translation>
 <translation id="881799181680267069">Skjul andre</translation>
 <translation id="8818152010000655963">Baggrund</translation>
-<translation id="8818958672113348984">Bekræft via din telefon</translation>
+<translation id="8818958672113348984">Verificer via din telefon</translation>
 <translation id="8820817407110198400">Bogmærker</translation>
 <translation id="8821045908425223359">Konfigurer automatisk IP-adressen</translation>
 <translation id="8821268776955756404"><ph name="APP_NAME" /> er klar til brug.</translation>
diff --git a/chrome/app/resources/generated_resources_de.xtb b/chrome/app/resources/generated_resources_de.xtb
index 0d0a4c9..b99a414 100644
--- a/chrome/app/resources/generated_resources_de.xtb
+++ b/chrome/app/resources/generated_resources_de.xtb
@@ -388,7 +388,6 @@
 <translation id="1333965224356556482">Websites dürfen meinen Standort nicht sehen</translation>
 <translation id="1335282218035876586">Dein Chromebook erhält keine Sicherheits- und Softwareupdates mehr. Wir empfehlen, auf ein neues Chromebook umzusteigen.</translation>
 <translation id="133535873114485416">Bevorzugte Eingabe</translation>
-<translation id="1335437153193710305">Du kannst das Profil auswählen, für das du die Passwörter sehen möchtest</translation>
 <translation id="1335929031622236846">Gerät registrieren</translation>
 <translation id="1336902454946927954">Dein Sicherheitsschlüssel ist gesperrt, weil dein Fingerabdruck nicht erkannt werden konnte. Gib deine PIN ein, um ihn zu entsperren.</translation>
 <translation id="1338631221631423366">Wird gekoppelt…</translation>
@@ -3310,7 +3309,6 @@
 <translation id="383669374481694771">Dies sind allgemeine Informationen zu diesem Gerät und dessen Nutzung, zum Beispiel der Akkustand, System- und App-Aktivitäten und Fehler. Die Daten werden dazu verwendet, Android zu verbessern. Einige aggregierte Daten helfen auch Apps und Partnern von Google, beispielsweise Android-Entwicklern, ihre Apps und Produkte weiter zu verbessern.</translation>
 <translation id="3838085852053358637">Fehler beim Laden der Erweiterung</translation>
 <translation id="3838486795898716504">Weitere <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Gespeicherte Passwörter im Google Passwortmanager hinzufügen</translation>
 <translation id="383891835335927981">Keine Websites wurden vergrößert oder verkleinert</translation>
 <translation id="3839509547554145593">Scroll-Beschleunigung für Maus aktivieren</translation>
 <translation id="3839516600093027468">Immer verhindern, dass <ph name="HOST" /> die Zwischenablage abruft</translation>
diff --git a/chrome/app/resources/generated_resources_el.xtb b/chrome/app/resources/generated_resources_el.xtb
index 75ec8beb..8e1796d 100644
--- a/chrome/app/resources/generated_resources_el.xtb
+++ b/chrome/app/resources/generated_resources_el.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">Να μην επιτρέπεται στους ιστοτόπους να βλέπουν την τοποθεσία σας</translation>
 <translation id="1335282218035876586">Το Chromebook δεν λαμβάνει πλέον ενημερώσεις ασφάλειας και λογισμικού. Αναβαθμίστε το Chromebook για καλύτερη εμπειρία.</translation>
 <translation id="133535873114485416">Προτιμώμενη εισαγωγή</translation>
-<translation id="1335437153193710305">Μπορείτε να επιλέξετε το προφίλ του οποίου οι κωδικοί πρόσβασης θα εμφανίζονται</translation>
 <translation id="1335929031622236846">Εγγραφή της συσκευής σας</translation>
 <translation id="1336902454946927954">Το κλειδί ασφαλείας σας είναι κλειδωμένο επειδή δεν ήταν δυνατή η αναγνώριση του δακτυλικού σας αποτυπώματος. Για να το ξεκλειδώσετε, εισαγάγετε το PIN σας.</translation>
 <translation id="1338631221631423366">Σύζευξη…</translation>
@@ -3330,7 +3329,6 @@
 <translation id="383669374481694771">Αυτές είναι γενικές πληροφορίες σχετικά με αυτήν τη συσκευή και τον τρόπο με τον οποίο χρησιμοποιείται (όπως το επίπεδο της μπαταρίας, τη δραστηριότητα συστήματος και εφαρμογών και τα σφάλματα). Τα δεδομένα θα χρησιμοποιηθούν για τη βελτίωση του Android, ενώ ορισμένες συγκεντρωτικές πληροφορίες θα συμβάλλουν στη βελτίωση των εφαρμογών Google και θα χρησιμοποιηθούν από τους συνεργάτες της Google, όπως τους προγραμματιστές Android, προκειμένου να βελτιώσουν τις εφαρμογές και τα προϊόντα τους.</translation>
 <translation id="3838085852053358637">Η φόρτωση της επέκτασης απέτυχε</translation>
 <translation id="3838486795898716504">Περισσότερες σελίδες <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Προσθήκη αποθηκευμένων κωδικών πρόσβασης στον Διαχειριστή κωδικών πρόσβασης Google</translation>
 <translation id="383891835335927981">Δεν έχει γίνει μεγέθυνση ή σμίκρυνση κανενός ιστοτόπου</translation>
 <translation id="3839509547554145593">Ενεργοποίηση επιτάχυνσης κύλισης ποντικιού</translation>
 <translation id="3839516600093027468">Να γίνεται πάντα αποκλεισμός της προβολής του προχείρου από <ph name="HOST" /></translation>
diff --git a/chrome/app/resources/generated_resources_en-GB.xtb b/chrome/app/resources/generated_resources_en-GB.xtb
index 9ba0b68c..94903a8 100644
--- a/chrome/app/resources/generated_resources_en-GB.xtb
+++ b/chrome/app/resources/generated_resources_en-GB.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">At least <ph name="INSTALL_SIZE" /> of space is recommended for Linux. To increase free space, delete files from your device.</translation>
 <translation id="1038643060055067718">Lines:</translation>
 <translation id="1039337018183941703">Invalid or corrupt file</translation>
+<translation id="1040761927998636252">Unnamed bookmark for <ph name="URL" /></translation>
 <translation id="1041175011127912238">This page isn't responding</translation>
 <translation id="1041263367839475438">Available devices</translation>
 <translation id="1042174272890264476">Your computer also comes with <ph name="SHORT_PRODUCT_NAME" />'s RLZ library built in. RLZ assigns a non-unique, non-personally identifiable tag to measure the searches and <ph name="SHORT_PRODUCT_NAME" /> usage driven by a particular promotional campaign. These labels sometimes appear in Google Search queries in <ph name="PRODUCT_NAME" />.</translation>
@@ -390,7 +391,6 @@
 <translation id="1333965224356556482">Don't allow sites to see your location</translation>
 <translation id="1335282218035876586">Your Chromebook is no longer receiving security and software updates. Upgrade your Chromebook for the best experience.</translation>
 <translation id="133535873114485416">Preferred input</translation>
-<translation id="1335437153193710305">You can choose the profile that you want to see the passwords from.</translation>
 <translation id="1335929031622236846">Enrol your device</translation>
 <translation id="1336902454946927954">Your security key is locked because your fingerprint couldn't be recognised. To unlock it, enter your PIN.</translation>
 <translation id="1338631221631423366">Pairing…</translation>
@@ -3329,7 +3329,6 @@
 <translation id="383669374481694771">This is general information about this device and how it's used (such as battery level, system and app activity, and errors). The data will be used to improve Android, and some aggregated information will also help Google apps and partners, such as Android developers, make their apps and products better.</translation>
 <translation id="3838085852053358637">Failed to load extension</translation>
 <translation id="3838486795898716504">More <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Add saved passwords to Google Password Manager</translation>
 <translation id="383891835335927981">No sites have been zoomed in or out</translation>
 <translation id="3839509547554145593">Enable mouse scroll acceleration</translation>
 <translation id="3839516600093027468">Always block <ph name="HOST" /> from seeing the clipboard</translation>
diff --git a/chrome/app/resources/generated_resources_es-419.xtb b/chrome/app/resources/generated_resources_es-419.xtb
index 9630e5a7..2a90fd4 100644
--- a/chrome/app/resources/generated_resources_es-419.xtb
+++ b/chrome/app/resources/generated_resources_es-419.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Se recomienda tener al menos <ph name="INSTALL_SIZE" /> de espacio para Linux. Si necesitas liberar espacio, borra archivos del dispositivo.</translation>
 <translation id="1038643060055067718">Líneas:</translation>
 <translation id="1039337018183941703">Archivo no válido o dañado</translation>
+<translation id="1040761927998636252">Favorito sin nombre para <ph name="URL" /></translation>
 <translation id="1041175011127912238">Esta página no responde</translation>
 <translation id="1041263367839475438">Dispositivos disponibles</translation>
 <translation id="1042174272890264476">Tu computadora también tiene la biblioteca RLZ de <ph name="SHORT_PRODUCT_NAME" /> incorporada. RLZ asigna una etiqueta identificable, no exclusiva y no personal para medir las búsquedas y el uso de <ph name="SHORT_PRODUCT_NAME" /> impulsados por una determinada campaña de promoción. Estas etiquetas aparecen a veces en las consultas de la Búsqueda de Google en <ph name="PRODUCT_NAME" />.</translation>
@@ -387,7 +388,6 @@
 <translation id="1333965224356556482">No permitir que los sitios visualicen tu ubicación</translation>
 <translation id="1335282218035876586">Tu Chromebook ya no recibe actualizaciones de seguridad ni de software. Cambia tu Chromebook para obtener la mejor experiencia.</translation>
 <translation id="133535873114485416">Método de entrada preferido</translation>
-<translation id="1335437153193710305">Puedes elegir el perfil cuyas contraseñas deseas ver</translation>
 <translation id="1335929031622236846">Inscribe tu dispositivo</translation>
 <translation id="1336902454946927954">Se bloqueó la llave de seguridad porque no se reconoció tu huella dactilar. Para desbloquearla, ingresa el PIN.</translation>
 <translation id="1338631221631423366">Vinculando…</translation>
@@ -3309,7 +3309,6 @@
 <translation id="383669374481694771">Aquí se muestra información general sobre este dispositivo y cómo se usa (por ejemplo, el nivel de batería, la actividad de las apps y el sistema, y los errores). Los datos se usarán para mejorar Android, y la información agregada también permitirá que las apps y los socios de Google, como los desarrolladores de Android, mejoren sus apps y productos.</translation>
 <translation id="3838085852053358637">Se produjo un error al cargar la extensión</translation>
 <translation id="3838486795898716504">Más <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Agrega contraseñas guardadas al Administrador de contraseñas de Google</translation>
 <translation id="383891835335927981">No se configuró el zoom para ningún sitio</translation>
 <translation id="3839509547554145593">Habilitar la aceleración de desplazamiento del mouse</translation>
 <translation id="3839516600093027468">Nunca permitir que <ph name="HOST" /> vea el portapapeles</translation>
@@ -7114,7 +7113,7 @@
 <translation id="7295614427631867477">Ten en cuenta que Android, Play y las apps asociadas se rigen por sus propias políticas de uso y recopilación de datos.</translation>
 <translation id="729583233778673644">Permite la encriptación AES y RC4. Esta opción es riesgosa, ya que los cifrados RC4 son inseguros.</translation>
 <translation id="7297726121602187087">Verde oscuro</translation>
-<translation id="7298195798382681320">Recomendada</translation>
+<translation id="7298195798382681320">Recomendado</translation>
 <translation id="7299337219131431707">Habilitar navegación como invitado</translation>
 <translation id="7299515639584427954">¿Quieres cambiar la app predeterminada para los vínculos compatibles?</translation>
 <translation id="7299588179200441056"><ph name="URL" /> - <ph name="FOLDER" /></translation>
diff --git a/chrome/app/resources/generated_resources_es.xtb b/chrome/app/resources/generated_resources_es.xtb
index fd2f57a..6c75342 100644
--- a/chrome/app/resources/generated_resources_es.xtb
+++ b/chrome/app/resources/generated_resources_es.xtb
@@ -388,7 +388,6 @@
 <translation id="1333965224356556482">No permitir que los sitios vean tu ubicación</translation>
 <translation id="1335282218035876586">Tu Chromebook ya no recibe actualizaciones de seguridad ni de software. Cambia de Chromebook para disfrutar de la mejor experiencia.</translation>
 <translation id="133535873114485416">Método de introducción preferido</translation>
-<translation id="1335437153193710305">Puedes elegir el perfil cuyas contraseñas quieres ver</translation>
 <translation id="1335929031622236846">Registra el dispositivo</translation>
 <translation id="1336902454946927954">Tu llave de seguridad está bloqueada porque no se ha podido reconocer tu huella digital. Para desbloquearla, escribe tu PIN.</translation>
 <translation id="1338631221631423366">Emparejando...</translation>
@@ -3314,7 +3313,6 @@
 <translation id="383669374481694771">Esta página muestra información general sobre este dispositivo y su uso (como el nivel de batería, la actividad de las aplicaciones y del sistema, y los errores). Sirve para mejorar Android, y parte de los datos agregados también mejoran las aplicaciones y ayudan a los partners de Google, como los desarrolladores de Android, a mejorar sus productos y aplicaciones.</translation>
 <translation id="3838085852053358637">No se ha podido cargar la extensión</translation>
 <translation id="3838486795898716504">Más <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Añade contraseñas guardadas al Gestor de contraseñas de Google</translation>
 <translation id="383891835335927981">No se ha ampliado ni reducido ningún sitio web</translation>
 <translation id="3839509547554145593">Habilitar aceleración de desplazamiento del ratón</translation>
 <translation id="3839516600093027468">No permitir nunca que <ph name="HOST" /> vea el portapapeles</translation>
diff --git a/chrome/app/resources/generated_resources_et.xtb b/chrome/app/resources/generated_resources_et.xtb
index bbf7342..c26d481 100644
--- a/chrome/app/resources/generated_resources_et.xtb
+++ b/chrome/app/resources/generated_resources_et.xtb
@@ -390,7 +390,6 @@
 <translation id="1333965224356556482">Ära luba saitidel minu asukohta näha</translation>
 <translation id="1335282218035876586">Teie Chromebook ei saa enam turva- ja tarkvaravärskendusi. Parima kasutuskogemuse saamiseks värskendage oma Chromebooki.</translation>
 <translation id="133535873114485416">Eelistatud sisend</translation>
-<translation id="1335437153193710305">Saate valida profiili, mille paroole näha soovite</translation>
 <translation id="1335929031622236846">Seadme registreerimine</translation>
 <translation id="1336902454946927954">Teie turvavõti on lukustatud, kuna teie sõrmejälge ei õnnestunud tuvastada. Selle avamiseks sisestage oma PIN-kood.</translation>
 <translation id="1338631221631423366">Sidumine …</translation>
@@ -3319,7 +3318,6 @@
 <translation id="383669374481694771">See on üldteave seadme ja selle kasutamise kohta (nt aku laetuse tase, süsteemi ja rakenduste tegevused ning vead). Neid andmeid kasutatakse Androidi täiustamiseks ning teatud koondandmed on abiks ka Google'i rakendustele ja partneritele (nt Androidi arendajatele), aidates neil rakendusi ning teenuseid paremaks muuta.</translation>
 <translation id="3838085852053358637">Laienduse laadimine ebaõnnestus</translation>
 <translation id="3838486795898716504">Rohkem: <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Lisage salvestatud paroolid Google'i paroolihaldurisse</translation>
 <translation id="383891835335927981">Ühtegi saiti pole sisse ega välja suumitud</translation>
 <translation id="3839509547554145593">Luba hiire kerimise kiirendamine</translation>
 <translation id="3839516600093027468">Blokeeri hosti <ph name="HOST" /> jaoks alati lõikelaua nägemine</translation>
diff --git a/chrome/app/resources/generated_resources_eu.xtb b/chrome/app/resources/generated_resources_eu.xtb
index 9a8f4b0..f313b9b 100644
--- a/chrome/app/resources/generated_resources_eu.xtb
+++ b/chrome/app/resources/generated_resources_eu.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Linux instalatzeko, gutxienez <ph name="INSTALL_SIZE" /> eduki behar dira libre. Tokia egiteko, ezabatu gailuan dauden fitxategiak.</translation>
 <translation id="1038643060055067718">Lerroak:</translation>
 <translation id="1039337018183941703">Fitxategiak ez du balio edo hondatuta dago</translation>
+<translation id="1040761927998636252"><ph name="URL" /> webgunerako laster-marka izengabea</translation>
 <translation id="1041175011127912238">Orriak ez du erantzuten</translation>
 <translation id="1041263367839475438">Gailu erabilgarriak</translation>
 <translation id="1042174272890264476">Ordenagailuak <ph name="SHORT_PRODUCT_NAME" /> produktuaren RLZ liburutegia ere du integratuta. RLZ liburutegiak esklusiboa ez den eta pertsonalki identifikatu ezin zaitzakeen etiketa bat esleitzen du promozio-kanpaina jakin batek sortutako bilaketak eta <ph name="SHORT_PRODUCT_NAME" /> produktuaren erabilera neurtzeko. Etiketa horiek <ph name="PRODUCT_NAME" /> produktuko Google Bilaketa kontsultetan agertzen dira batzuetan.</translation>
@@ -387,7 +388,6 @@
 <translation id="1333965224356556482">Ez eman kokapena ikusteko baimena webguneei</translation>
 <translation id="1335282218035876586">Chromebook honek jadanik ez du jasotzen segurtasun- eta software-eguneratzerik. Zerbitzurik onena izateko, bertsio-berritu Chromebook-a.</translation>
 <translation id="133535873114485416">Sarrerako metodo hobetsia</translation>
-<translation id="1335437153193710305">Zein profiletako pasahitzak ikusi nahi dituzun aukera dezakezu</translation>
 <translation id="1335929031622236846">Erregistratu gailua</translation>
 <translation id="1336902454946927954">Segurtasun-giltza blokeatu egin da ez delako ezagutu hatz-marka. Desblokeatzeko, idatzi PINa.</translation>
 <translation id="1338631221631423366">Parekatzen…</translation>
@@ -3312,7 +3312,6 @@
 <translation id="383669374481694771">Gailu honi eta hura erabiltzeko moduari buruzko informazio orokorra da hau (adibidez, bateria-maila, sistemako eta aplikazioetako jarduerak, eta erroreak). Android hobetzeko erabiliko dira datuok. Gainera, multzokatutako datu batzuk oso baliagarriak dira Google-ren aplikazioak hobetzeko eta bazkideei (adibidez, Android-en garatzaileei) euren aplikazio eta produktuak hobetzen laguntzeko.</translation>
 <translation id="3838085852053358637">Ezin izan da kargatu luzapena</translation>
 <translation id="3838486795898716504"><ph name="PAGE_TITLE" /> orriaren jarraipena</translation>
-<translation id="3838487810283346084">Gehitu gordetako pasahitzak Google-ren Pasahitz-kudeatzailea zerbitzuan</translation>
 <translation id="383891835335927981">Ez da aplikatu zoomik inongo webgunetan</translation>
 <translation id="3839509547554145593">Gaitu saguarekin gora/behera bizkorrago egiteko aukera</translation>
 <translation id="3839516600093027468">Blokeatu beti <ph name="HOST" /> webguneari arbela ikusteko aukera</translation>
diff --git a/chrome/app/resources/generated_resources_fa.xtb b/chrome/app/resources/generated_resources_fa.xtb
index 9ad558a..d4ac7f25 100644
--- a/chrome/app/resources/generated_resources_fa.xtb
+++ b/chrome/app/resources/generated_resources_fa.xtb
@@ -118,6 +118,7 @@
 <translation id="1090541560108055381">پیش‌از مرتبط‌سازی، مطمئن شوید این کد در هر دو دستگاه یکی باشد</translation>
 <translation id="1091767800771861448">‏برای رد شدن، ESCAPE را فشار دهید (فقط ساخت‌های غیررسمی).</translation>
 <translation id="1093457606523402488">شبکه‌های قابل مشاهده:</translation>
+<translation id="1094219634413363886">اگر ضبط در این دستگاه تحت‌مدیریت شروع شود، اعلانی خواهید دید</translation>
 <translation id="1095761715416917775">مطمئن شوید همیشه می‌توانید به داده‌های همگام‌سازی دسترسی داشته باشید</translation>
 <translation id="1095879482467973146">‏«مدیر گذرواژه Google» در وب</translation>
 <translation id="109647177154844434">‏حذف نصب Parallels Desktop تصویر Windows شما را حذف خواهد کرد. برنامه‌ها، تنظیمات، و داده‌های آن هم حذف خواهد شد. مطمئنید که می‌خواهید ادامه دهید؟</translation>
@@ -391,7 +392,6 @@
 <translation id="1333965224356556482">به سایت‌ها اجازه داده نشود مکان شما را ببینند</translation>
 <translation id="1335282218035876586">‏Chromebook شما دیگر به‌روزرسانی‌های امنیتی و نرم‌افزاری را دریافت نمی‌کند. برای داشتن بهترین تجربه، Chromebook خود را ارتقا دهید.</translation>
 <translation id="133535873114485416">ورودی ترجیحی</translation>
-<translation id="1335437153193710305">می‌توانید نمایه مدنظرتان را برای دیدن گذرواژه‌های آن انتخاب کنید</translation>
 <translation id="1335929031622236846">دستگاهتان را ثبت‌نام کنید</translation>
 <translation id="1336902454946927954">کلید امنیتی شما قفل شده است زیرا اثر انگشتتان تشخیص داده نشد. برای باز کردن قفل آن، پین را وارد کنید.</translation>
 <translation id="1338631221631423366">درحال مرتبط‌سازی…</translation>
@@ -3325,7 +3325,6 @@
 <translation id="383669374481694771">‏این اطلاعاتی کلی درباره این دستگاه و نحوه استفاده از آن است (مانند سطح شارژ باتری، فعالیت سیستم و برنامه، و خطاها). از این داده‌ها برای بهبود Android استفاده خواهد شد و بعضی از اطلاعات انبوهشی نیز به برنامه‌های Google و شریکان، مانند برنامه‌نویسان Android کمک خواهد کرد برنامه‌ها و محصولاتشان را بهتر کنند.</translation>
 <translation id="3838085852053358637">افزونه بار نشد</translation>
 <translation id="3838486795898716504"><ph name="PAGE_TITLE" /> بیشتر</translation>
-<translation id="3838487810283346084">‏افزودن گذرواژه‌های ذخیره‌شده به «مدیر گذرواژه Google»</translation>
 <translation id="383891835335927981">هیچ سایتی بزرگ‌نمایی یا کوچک‌نمایی نشده است</translation>
 <translation id="3839509547554145593">فعال کردن شتاب پیمایش موشواره</translation>
 <translation id="3839516600093027468">دسترسی <ph name="HOST" /> به بریده‌‌دان همیشه مسدود باشد</translation>
@@ -3865,6 +3864,7 @@
 <translation id="4340125850502689798">نام کاربری نامعتبر است</translation>
 <translation id="4340515029017875942"><ph name="ORIGIN" /> می‌خواهد با برنامه «<ph name="EXTENSION_NAME" />» ارتباط برقرار کند</translation>
 <translation id="4340799661701629185">به سایت‌ها اجازه داده نشود اعلان ارسال کنند</translation>
+<translation id="4341280816303414009">ممکن است صفحه‌تان ضبط شود</translation>
 <translation id="4341577178275615435">‏برای روشن یا خاموش کردن مرور با نشانگر نوشتار، از میان‌بر F7 استفاده کنید</translation>
 <translation id="4341905082470253054">‏درحال بررسی وضعیت TPM…</translation>
 <translation id="434198521554309404">سریع. ایمن. بی‌دردسر.</translation>
@@ -5688,6 +5688,7 @@
 <translation id="5979421442488174909">&amp;ترجمه به <ph name="LANGUAGE" /></translation>
 <translation id="5979469435153841984">برای نشانک‌گذاری صفحه‌ها، روی ستاره در نوار نشانی کلیک کنید</translation>
 <translation id="5981362776161841923">برای مجاز کردن افزونه‌ها، تنظیم پیش‌فرض را در زیر تغییر دهید.</translation>
+<translation id="5982578203375898585">نمایش بارگیری‌ها پس‌از اتمام کار</translation>
 <translation id="5984222099446776634">به‌تازگی بازدیدشده</translation>
 <translation id="5985458664595100876">‏قالب نشانی وب نامعتبر است. قالب‌های پشتیبانی‌شده عبارتند از: \\server\share و smb://server/share.</translation>
 <translation id="598810097218913399">برداشتن تخصیص</translation>
diff --git a/chrome/app/resources/generated_resources_fi.xtb b/chrome/app/resources/generated_resources_fi.xtb
index e7ba0d2..d632f23 100644
--- a/chrome/app/resources/generated_resources_fi.xtb
+++ b/chrome/app/resources/generated_resources_fi.xtb
@@ -390,7 +390,6 @@
 <translation id="1333965224356556482">Älä salli sivustojen nähdä sijaintiasi</translation>
 <translation id="1335282218035876586">Chromebook ei enää saa tietoturva- ja ohjelmistopäivityksiä. Päivitä Chromebook, niin saat parhaan käyttökokemuksen.</translation>
 <translation id="133535873114485416">Syöttötapa</translation>
-<translation id="1335437153193710305">Voit valita profiilin, jonka salasanat haluat nähdä</translation>
 <translation id="1335929031622236846">Rekisteröi laite</translation>
 <translation id="1336902454946927954">Suojausavaimesi on lukittu, koska sormenjälkeäsi ei voitu tunnistaa. Avaa lukitus lisäämällä PIN-koodisi.</translation>
 <translation id="1338631221631423366">Laiteparia muodostetaan…</translation>
@@ -3327,7 +3326,6 @@
 <translation id="383669374481694771">Nämä ovat yleisiä tietoja tästä laitteesta ja sen käytöstä (esim. akun varaustasosta, järjestelmän ja sovellusten toiminnasta sekä virheistä). Datan avulla Androidia parannetaan, ja koottua dataa käytetään Google-sovellusten, Android-kehittäjien tai muiden kumppanien sovellusten ja tuotteiden parantamiseen.</translation>
 <translation id="3838085852053358637">Laajennuksen lataus epäonnistui</translation>
 <translation id="3838486795898716504">Lisää <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Lisää tallennetut salasanat Google Salasanoihin</translation>
 <translation id="383891835335927981">Zoomausta ei ole käytetty sivustoilla.</translation>
 <translation id="3839509547554145593">Ota käyttöön hiiren vierityksen kiihdytys</translation>
 <translation id="3839516600093027468"><ph name="HOST" /> ei saa koskaan nähdä leikepöydän sisältöä</translation>
diff --git a/chrome/app/resources/generated_resources_fil.xtb b/chrome/app/resources/generated_resources_fil.xtb
index 5f006fc..40331dc 100644
--- a/chrome/app/resources/generated_resources_fil.xtb
+++ b/chrome/app/resources/generated_resources_fil.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">Huwag payagan ang mga site na makita ang iyong lokasyon</translation>
 <translation id="1335282218035876586">Hindi na nakakatanggap ang iyong Chromebook ng mga update sa seguridad at software. I-upgrade ang iyong Chromebook para sa pinakamagandang experience.</translation>
 <translation id="133535873114485416">Gustong input</translation>
-<translation id="1335437153193710305">Puwede mong piliin ang profile kung saan mo gustong makita ang mga password</translation>
 <translation id="1335929031622236846">Ipa-enroll ang iyong device</translation>
 <translation id="1336902454946927954">Naka-lock ang iyong security key dahil hindi makilala ang fingerprint mo. Para i-unlock ito, ilagay ang iyong PIN.</translation>
 <translation id="1338631221631423366">Ipinapares...</translation>
@@ -3329,7 +3328,6 @@
 <translation id="383669374481694771">Ito ay pangkalahatang impormasyon tungkol sa device na ito at kung paano ito ginagamit (gaya ng antas ng baterya, aktibidad ng system at app, at mga error). Gagamitin ang data para pahusayin ang Android, at makakatulong din ang ilang pinagsama-samang impormasyon sa mga app at partner ng Google, gaya ng mga developer ng Android, na pahusayin ang kanilang mga app at produkto.</translation>
 <translation id="3838085852053358637">Hindi na-load ang extension</translation>
 <translation id="3838486795898716504">Higit pang <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Magdagdag ng mga naka-save na password sa Google Password Manager</translation>
 <translation id="383891835335927981">Walang site na na-zoom in o na-zoom out</translation>
 <translation id="3839509547554145593">I-enable ang pag-accelerate sa pag-scroll ng mouse</translation>
 <translation id="3839516600093027468">Palaging i-block ang <ph name="HOST" /> sa pagtingin sa clipboard</translation>
diff --git a/chrome/app/resources/generated_resources_fr-CA.xtb b/chrome/app/resources/generated_resources_fr-CA.xtb
index 25eb4c8..0b0b869 100644
--- a/chrome/app/resources/generated_resources_fr-CA.xtb
+++ b/chrome/app/resources/generated_resources_fr-CA.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Un minimum de <ph name="INSTALL_SIZE" /> d'espace est recommandé pour utiliser Linux. Pour libérer de l'espace, supprimez des fichiers sur votre appareil.</translation>
 <translation id="1038643060055067718">Lignes :</translation>
 <translation id="1039337018183941703">Fichier non valide ou corrompu</translation>
+<translation id="1040761927998636252">Favori sans nom pour <ph name="URL" /></translation>
 <translation id="1041175011127912238">Cette page ne répond pas</translation>
 <translation id="1041263367839475438">Appareils accessibles</translation>
 <translation id="1042174272890264476">Votre ordinateur est fourni avec la bibliothèque RLZ de <ph name="SHORT_PRODUCT_NAME" />. RLZ attribue une étiquette non unique et qui ne permet pas d'identifier des internautes afin de mesurer les recherches et l'utilisation de <ph name="SHORT_PRODUCT_NAME" /> générées par une campagne de promotion particulière. Ces étiquettes s'affichent parfois dans les requêtes de recherche Google dans <ph name="PRODUCT_NAME" />.</translation>
@@ -388,7 +389,6 @@
 <translation id="1333965224356556482">Ne pas autoriser les sites à accéder à votre position</translation>
 <translation id="1335282218035876586">Votre Chromebook ne reçoit plus les mises à jour de sécurité ni les mises à jour logicielles. Mettez à niveau votre Chromebook pour une expérience optimale.</translation>
 <translation id="133535873114485416">Entrée préférée</translation>
-<translation id="1335437153193710305">Vous pouvez choisir le profil dont vous souhaitez voir les mots de passe</translation>
 <translation id="1335929031622236846">Inscrivez votre appareil</translation>
 <translation id="1336902454946927954">Votre clé de sécurité est verrouillée parce que votre empreinte digitale n'a pas été reconnue. Pour la déverrouiller, entrez votre NIP.</translation>
 <translation id="1338631221631423366">Association en cours…</translation>
@@ -3314,7 +3314,6 @@
 <translation id="383669374481694771">Ces données d'ordre général concernent votre appareil et son utilisation (comme le niveau de la pile, les erreurs, ainsi que l'activité du système et des applications). Elles serviront à améliorer la plateforme Android. Certaines données collectées aideront également nos partenaires, tels que les développeurs Android, à améliorer leurs applications et leurs produits.</translation>
 <translation id="3838085852053358637">Échec du chargement de l'extension</translation>
 <translation id="3838486795898716504">Pages suivantes pour <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Ajoutez des mots de passe enregistrés au gestionnaire de mots de passe de Google</translation>
 <translation id="383891835335927981">Aucun site n'a fait l'objet d'un zoom avant ou arrière</translation>
 <translation id="3839509547554145593">Activer l'accélération du défilement pour la souris</translation>
 <translation id="3839516600093027468">Toujours empêcher <ph name="HOST" /> de voir le presse-papiers</translation>
diff --git a/chrome/app/resources/generated_resources_fr.xtb b/chrome/app/resources/generated_resources_fr.xtb
index 39197fd9..dc05e117 100644
--- a/chrome/app/resources/generated_resources_fr.xtb
+++ b/chrome/app/resources/generated_resources_fr.xtb
@@ -389,7 +389,6 @@
 <translation id="1333965224356556482">Ne pas autoriser les sites à accéder à votre position</translation>
 <translation id="1335282218035876586">Votre Chromebook ne reçoit plus de mises à jour logicielles ni de sécurité. Mettez-le à niveau pour une expérience optimale.</translation>
 <translation id="133535873114485416">Mode de saisie préféré</translation>
-<translation id="1335437153193710305">Vous pouvez choisir le profil dont vous souhaitez afficher les mots de passe</translation>
 <translation id="1335929031622236846">Enregistrer l'appareil</translation>
 <translation id="1336902454946927954">Empreinte digitale non reconnue. Votre clé de sécurité a été verrouillée. Pour la déverrouiller, saisissez votre code.</translation>
 <translation id="1338631221631423366">Association…</translation>
@@ -3314,7 +3313,6 @@
 <translation id="383669374481694771">Ces informations d'ordre général concernent votre appareil et son utilisation (comme le niveau de la batterie, les erreurs, ainsi que l'activité du système et des applications). Elles serviront à améliorer Android, et certaines données globales aideront également nos développeurs d'applications et nos partenaires tels que les développeurs Android, à perfectionner leurs applications et leurs produits.</translation>
 <translation id="3838085852053358637">Échec du chargement de l'extension</translation>
 <translation id="3838486795898716504">Plus de pages <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Ajouter des mots de passe enregistrés au Gestionnaire de mots de passe de Google</translation>
 <translation id="383891835335927981">Vous n'avez fait de zoom avant ou arrière sur aucun site</translation>
 <translation id="3839509547554145593">Activer l'accélération du défilement avec la souris</translation>
 <translation id="3839516600093027468">Toujours empêcher <ph name="HOST" /> de voir le contenu du presse-papiers</translation>
diff --git a/chrome/app/resources/generated_resources_gl.xtb b/chrome/app/resources/generated_resources_gl.xtb
index 9b4e357..f7788e0d 100644
--- a/chrome/app/resources/generated_resources_gl.xtb
+++ b/chrome/app/resources/generated_resources_gl.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">É recomendable dispoñer polo menos de <ph name="INSTALL_SIZE" /> de espazo para Linux. Se queres aumentar o espazo libre, elimina ficheiros do dispositivo.</translation>
 <translation id="1038643060055067718">Liñas:</translation>
 <translation id="1039337018183941703">O ficheiro non é válido ou está danado</translation>
+<translation id="1040761927998636252">Marcador sen nome para <ph name="URL" /></translation>
 <translation id="1041175011127912238">Esta páxina non responde</translation>
 <translation id="1041263367839475438">Dispositivos dispoñibles</translation>
 <translation id="1042174272890264476">O ordenador tamén inclúe a biblioteca de <ph name="SHORT_PRODUCT_NAME" />. RLZ asigna unha etiqueta que non é exclusiva e sen identificación persoal para medir as buscas e o uso de <ph name="SHORT_PRODUCT_NAME" /> derivados dunha determinada campaña promocional. En ocasións estas etiquetas aparecen nas consultas de Busca de Google en <ph name="PRODUCT_NAME" />.</translation>
@@ -387,7 +388,6 @@
 <translation id="1333965224356556482">Non permitir que os sitios vexan a túa localización</translation>
 <translation id="1335282218035876586">O teu Chromebook xa non vai recibir máis actualizacións de seguranza e software. Faite cun novo para desfrutar da mellor experiencia.</translation>
 <translation id="133535873114485416">Entrada de voz preferida</translation>
-<translation id="1335437153193710305">Podes seleccionar o perfil do que queiras ver os contrasinais</translation>
 <translation id="1335929031622236846">Inscribir o teu dispositivo</translation>
 <translation id="1336902454946927954">Bloqueouse a chave de seguranza porque non se puido recoñecer a túa impresión dixital. Para desbloqueala, escribe o PIN.</translation>
 <translation id="1338631221631423366">Vinculando...</translation>
@@ -3311,7 +3311,6 @@
 <translation id="383669374481694771">Trátase de información xeral acerca deste dispositivo e do seu uso, como o nivel de batería, a actividade das aplicacións e do sistema, e os erros. Os datos utilizaranse coa finalidade de mellorar Android, e algunha información agregada tamén axudará ás aplicacións de Google e aos socios, como os programadores de Android, a mellorar as súas aplicacións e produtos.</translation>
 <translation id="3838085852053358637">Produciuse un erro ao cargar a extensión</translation>
 <translation id="3838486795898716504">Máis <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Engade os contrasinais gardados ao xestor de contrasinais de Google</translation>
 <translation id="383891835335927981">Non se achegou nin se afastou o zoom en ningún sitio</translation>
 <translation id="3839509547554145593">Activar aceleración de desprazamento do rato</translation>
 <translation id="3839516600093027468">Impedir sempre que o host <ph name="HOST" /> vexa o contido do portapapeis</translation>
diff --git a/chrome/app/resources/generated_resources_gu.xtb b/chrome/app/resources/generated_resources_gu.xtb
index 18fff4c..478e20b 100644
--- a/chrome/app/resources/generated_resources_gu.xtb
+++ b/chrome/app/resources/generated_resources_gu.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Linux માટે ઓછામાં ઓછી <ph name="INSTALL_SIZE" /> સ્પેસનો સુઝાવ આપવામાં આવે છે. ખાલી સ્પેસ વધારવા માટે, તમારા ડિવાઇસમાંથી ફાઇલો ડિલીટ કરો.</translation>
 <translation id="1038643060055067718">લાઇનો:</translation>
 <translation id="1039337018183941703">અમાન્ય અથવા દૂષિત ફાઇલ</translation>
+<translation id="1040761927998636252"><ph name="URL" /> માટે અનામાંકિત બુકમાર્ક</translation>
 <translation id="1041175011127912238">આ પેજ પ્રતિભાવ આપી રહ્યું નથી</translation>
 <translation id="1041263367839475438">ઉપલબ્ધ ડિવાઇસ</translation>
 <translation id="1042174272890264476">તમારા કમ્પ્યુટરની સાથે <ph name="SHORT_PRODUCT_NAME" /> ની RLZ લાઇબ્રેરી બિલ્ટ ઇન પણ આવે છે. RLZ વિશેષ પ્રચારાત્મક ઝુંબેશ દ્વારા ચલાવવામાં આવતી શોધ અને <ph name="SHORT_PRODUCT_NAME" /> ઉપયોગને માપવા માટે બિન-અદ્વિતીય, બિન-વ્યક્તિગત રીતે ઓળખી શકાય તેવા ટૅગ સોંપે છે. આ લેબલ કેટલીકવાર <ph name="PRODUCT_NAME" />માં Google Search ક્વેરીમાં દેખાય છે.</translation>
@@ -388,7 +389,6 @@
 <translation id="1333965224356556482">સાઇટને તમારું સ્થાન જોવાની મંજૂરી આપશો નહીં</translation>
 <translation id="1335282218035876586">તમારી Chromebook હવે સુરક્ષા અને સૉફ્ટવેર અપડેટ મેળવતી નથી. શ્રેષ્ઠ અનુભવ માટે તમારી Chromebookને અપગ્રેડ કરો.</translation>
 <translation id="133535873114485416">પસંદગીનું ઇનપુટ</translation>
-<translation id="1335437153193710305">તમે એ પ્રોફાઇલ પસંદ કરી શકો છો જેમાંથી તમે પાસવર્ડ જોવા માગો છો</translation>
 <translation id="1335929031622236846">તમારા ડિવાઇસની નોંધણી કરાવો</translation>
 <translation id="1336902454946927954">તમારી સિક્યુરિટી કી લૉક કરેલી હોવાને કારણે તમારી ફિંગરપ્રિન્ટ ઓળખી શક્યાં નહીં. તેને અનલૉક કરવા માટે, તમારો પિન દાખલ કરો.</translation>
 <translation id="1338631221631423366">જોડાણ કરી રહ્યાં છીએ...</translation>
@@ -3310,7 +3310,6 @@
 <translation id="383669374481694771">આ ડિવાઇસ અને તે કેવી રીતે ઉપયોગમાં લેવાય છે તે (જેમ કે બૅટરીનું લેવલ, સિસ્ટમ અને ઍપ પ્રવૃત્તિ તેમજ ભૂલો) વિશેની આ સામાન્ય માહિતી છે. આ ડેટાનો ઉપયોગ Androidને બહેતર બનાવવા માટે કરવામાં આવશે અને અમુક એકીકૃત માહિતી, Google ઍપ અને ભાગીદારો, જેમ કે Android ડેવલપરને પણ તેઓની ઍપ અને પ્રોડક્ટને બહેતર બનાવવામાં સહાયરૂપ થશે.</translation>
 <translation id="3838085852053358637">એક્સ્ટેન્શન લોડ કરવામાં નિષ્ફળ થયાં</translation>
 <translation id="3838486795898716504">વધુ <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Google Password Managerમાં સાચવેલા પાસવર્ડ ઉમેરો</translation>
 <translation id="383891835335927981">કોઈ સાઇટનું ઝૂમ વધારેલું કે ઘટાડેલું નથી</translation>
 <translation id="3839509547554145593">માઉસ સ્ક્રોલ ઍક્સલરેશન સુવિધા ચાલુ કરો</translation>
 <translation id="3839516600093027468"><ph name="HOST" />ને હંમેશા ક્લિપબોર્ડ જોવાથી બ્લૉક કરો</translation>
diff --git a/chrome/app/resources/generated_resources_hi.xtb b/chrome/app/resources/generated_resources_hi.xtb
index 77847b8..5ad3de80 100644
--- a/chrome/app/resources/generated_resources_hi.xtb
+++ b/chrome/app/resources/generated_resources_hi.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Linux के लिए कम से कम <ph name="INSTALL_SIZE" /> खाली जगह का सुझाव दिया जाता है. खाली जगह बढ़ाने के लिए अपने डिवाइस से फ़ाइलें मिटाएं.</translation>
 <translation id="1038643060055067718">रेखाएं:</translation>
 <translation id="1039337018183941703">अमान्‍य या खराब फ़ाइल</translation>
+<translation id="1040761927998636252"><ph name="URL" /> के लिए बिना नाम वाला बुकमार्क</translation>
 <translation id="1041175011127912238">इस पेज से जवाब नहीं मिल रहा है</translation>
 <translation id="1041263367839475438">उपलब्ध डिवाइस</translation>
 <translation id="1042174272890264476">आपके कंप्यूटर में पहले से ही <ph name="SHORT_PRODUCT_NAME" /> की RLZ लाइब्रेरी होती है. किसी खास प्रचार कैंपेन में इस्तेमाल हुई खोजों और <ph name="SHORT_PRODUCT_NAME" /> के इस्तेमाल को मापने के लिए, RLZ एक बिना-विशिष्ट, बिना निजी तौर वाला टैग तय करता है. कभी-कभी ये लेबल <ph name="PRODUCT_NAME" /> में 'Google सर्च' क्वेरी में दिखाई देते हैं.</translation>
@@ -390,7 +391,6 @@
 <translation id="1333965224356556482">साइटों को आपकी जगह की जानकारी देखने की अनुमति न दें</translation>
 <translation id="1335282218035876586">अब से, आपके Chromebook को सुरक्षा और सॉफ़्टवेयर से जुड़े अपडेट नहीं मिलेंगे. बेहतर अनुभव पाने के लिए, अपना Chromebook अपग्रेड करें.</translation>
 <translation id="133535873114485416">पसंदीदा इनपुट</translation>
-<translation id="1335437153193710305">आपको जिस प्रोफ़ाइल का पासवर्ड देखना है उसे चुनने का विकल्प, आपके पास है</translation>
 <translation id="1335929031622236846">अपना डिवाइस रजिस्टर करें</translation>
 <translation id="1336902454946927954">फ़िंगरप्रिंट की पहचान न होने की वजह से आपकी सुरक्षा कुंजी लॉक कर दी गई है. इसे अनलॉक करने के लिए, अपना पिन डालें.</translation>
 <translation id="1338631221631423366">जोड़ा जा रहा है...</translation>
@@ -3328,7 +3328,6 @@
 <translation id="383669374481694771">यह इस डिवाइस और इसके इस्तेमाल से जुड़ी सामान्य जानकारी है, जैसे कि बैटरी कितनी चार्ज है, सिस्टम, और ऐप्लिकेशन की गतिविधि और गड़बड़ियां. डिवाइस से जुड़े इस डेटा का इस्तेमाल Android काे बेहतर बनाने के लिए किया जाएगा. साथ ही, इकट्ठा की गई कुछ जानकारी की मदद से Android डेवलपर जैसे पार्टनर और Google के ऐप्लिकेशन अपने प्रॉडक्ट को बेहतर बना पाएंगे.</translation>
 <translation id="3838085852053358637">एक्सटेंशन लोड नहीं हो सका</translation>
 <translation id="3838486795898716504">ज़्यादा <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Google Password Manager में सेव किए गए पासवर्ड जोड़ें</translation>
 <translation id="383891835335927981">कोई भी साइट ज़ूम इन या ज़ूम आउट नहीं की गई है</translation>
 <translation id="3839509547554145593">माउस से स्क्रोल करने की रफ़्तार बढ़ाने की सुविधा चालू करें</translation>
 <translation id="3839516600093027468"><ph name="HOST" /> को क्लिपबोर्ड देखने से हमेशा ब्लॉक करें</translation>
diff --git a/chrome/app/resources/generated_resources_hr.xtb b/chrome/app/resources/generated_resources_hr.xtb
index 2435600..fe56b05 100644
--- a/chrome/app/resources/generated_resources_hr.xtb
+++ b/chrome/app/resources/generated_resources_hr.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">Ne dopuštaj web-lokacijama prikazivanje vaše lokacije</translation>
 <translation id="1335282218035876586">Chromebook više ne prima sigurnosna i softverska ažuriranja. Nadogradite Chromebook za najbolji doživljaj.</translation>
 <translation id="133535873114485416">Preferirani unos</translation>
-<translation id="1335437153193710305">Možete odabrati profil s kojeg želite vidjeti zaporke</translation>
 <translation id="1335929031622236846">Registrirajte svoj uređaj</translation>
 <translation id="1336902454946927954">Sigurnosni je ključ zaključan jer vaš otisak prsta nije prepoznat. Da biste ga otključali, unesite PIN.</translation>
 <translation id="1338631221631423366">Uparivanje...</translation>
@@ -3318,7 +3317,6 @@
 <translation id="383669374481694771">To su općeniti podaci o ovom uređaju i načinu na koji se upotrebljava (kao što su razina baterije, aktivnosti sustava i aplikacija te pogreške). Ti podaci upotrijebit će se za poboljšanje Androida, a neki skupni podaci pomoći će i Googleovim aplikacijama i partnerima, na primjer razvojnim programerima za Android, da poboljšaju svoje aplikacije i proizvode.</translation>
 <translation id="3838085852053358637">Učitavanje proširenja nije uspjelo</translation>
 <translation id="3838486795898716504">Više za <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Dodavanje spremljenih zaporki u Google upravitelj zaporki</translation>
 <translation id="383891835335927981">Nijedna web-lokacija nije povećana ili smanjena</translation>
 <translation id="3839509547554145593">Omogući ubrzanje pomicanja mišem</translation>
 <translation id="3839516600093027468">Uvijek blokiraj web-lokaciji <ph name="HOST" /> uvid u međuspremnik</translation>
diff --git a/chrome/app/resources/generated_resources_hu.xtb b/chrome/app/resources/generated_resources_hu.xtb
index f92eb20c..91710c8 100644
--- a/chrome/app/resources/generated_resources_hu.xtb
+++ b/chrome/app/resources/generated_resources_hu.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Ajánlott legalább <ph name="INSTALL_SIZE" /> méretű területet szánni a Linuxra. Tárhely felszabadításához töröljön fájlokat az eszközről.</translation>
 <translation id="1038643060055067718">Sorok:</translation>
 <translation id="1039337018183941703">Érvénytelen vagy sérült fájl</translation>
+<translation id="1040761927998636252">Névtelen könyvjelző a következőhöz: <ph name="URL" /></translation>
 <translation id="1041175011127912238">Az oldal nem válaszol</translation>
 <translation id="1041263367839475438">Rendelkezésre álló eszközök</translation>
 <translation id="1042174272890264476">Számítógépe a <ph name="SHORT_PRODUCT_NAME" /> RLZ-könyvtárát is tartalmazza beépítve. Az RLZ egy nem egyedi, személy szerinti azonosításra nem alkalmas címkét rendel hozzá a keresések és a <ph name="SHORT_PRODUCT_NAME" /> használatának egy adott promóciós kampány keretein belüli felméréséhez. Ezek a címkék időnként a <ph name="PRODUCT_NAME" /> Google-keresési lekérdezéseiben is feltűnnek.</translation>
@@ -389,7 +390,6 @@
 <translation id="1333965224356556482">A webhelyek nem tekinthetik meg az Ön tartózkodási helyét</translation>
 <translation id="1335282218035876586">Chromebookja a továbbiakban nem kap biztonsági és szoftverfrissítéseket. A legjobb élmény érdekében váltson újabb Chromebookra.</translation>
 <translation id="133535873114485416">Elsődleges bevitel</translation>
-<translation id="1335437153193710305">Kiválaszthatja azt a profilt, amelynek jelszavait meg szeretné tekinteni.</translation>
 <translation id="1335929031622236846">Az eszköz regisztrálása</translation>
 <translation id="1336902454946927954">A biztonsági kulcsot zároltuk, mert nem tudtuk azonosítani az ujjlenyomatot. A feloldáshoz adja meg a PIN-kódot.</translation>
 <translation id="1338631221631423366">Párosítás…</translation>
@@ -3326,7 +3326,6 @@
 <translation id="383669374481694771">Ez általános információ erről az eszközről és a használati módjáról (például az akkumulátor töltöttségéről, a rendszer- és alkalmazástevékenységekről, valamint a hibákról). Az adatokat arra használjuk fel, hogy továbbfejlesszük az Androidot, bizonyos összesített adatok pedig a Google-alkalmazásoknak és -partnereknek, például az Android-fejlesztőknek segítenek alkalmazásaik és termékeik fejlesztésében.</translation>
 <translation id="3838085852053358637">Nem sikerült betölteni a bővítményt</translation>
 <translation id="3838486795898716504">Továbbiak: <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Mentett jelszavak hozzáadása a Google Jelszókezelőhöz</translation>
 <translation id="383891835335927981">Nincs nagyított vagy kicsinyített webhely</translation>
 <translation id="3839509547554145593">Az egérrel való görgetés gyorsításának engedélyezése</translation>
 <translation id="3839516600093027468">A vágólap megtekintésének állandó tiltása a(z) <ph name="HOST" /> számára</translation>
diff --git a/chrome/app/resources/generated_resources_hy.xtb b/chrome/app/resources/generated_resources_hy.xtb
index 6f33235..4b85fab 100644
--- a/chrome/app/resources/generated_resources_hy.xtb
+++ b/chrome/app/resources/generated_resources_hy.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Լինուքսը տեղադրելու համար խորհուրդ է տրվում ունենալ նվազագույնը <ph name="INSTALL_SIZE" /> ազատ տարածք։ Տարածք ազատելու համար սարքի հիշողությունից ֆայլեր ջնջեք։</translation>
 <translation id="1038643060055067718">Տողեր՝</translation>
 <translation id="1039337018183941703">Ֆայլն անվավեր է կամ վնասված</translation>
+<translation id="1040761927998636252">Անանուն էջանիշ <ph name="URL" /> կայքի համար</translation>
 <translation id="1041175011127912238">Էջը չի արձագանքում</translation>
 <translation id="1041263367839475438">Հասանելի սարքեր</translation>
 <translation id="1042174272890264476">Ձեր համակարգչում նաև առկա է <ph name="SHORT_PRODUCT_NAME" />-ի ներկառուցված RLZ գրադարանը: RLZ-ը նշանակում է ոչ եզակի, անձը չնույնացնող ներդիր` որոնումների և <ph name="SHORT_PRODUCT_NAME" />-ի օգտագործման չափումների համար՝ նախագծված հատուկ գովազդային արշավի կողմից: Այս պիտակները երբեմն ցուցադրվում են Google որոնման հարցումների մեջ <ph name="PRODUCT_NAME" />-ում:</translation>
@@ -389,7 +390,6 @@
 <translation id="1333965224356556482">Թույլ չտալ կայքերին տեսնել ձեր տեղադրությունը</translation>
 <translation id="1335282218035876586">Ձեր Chromebook-ն այլևս անվտանգության և ծրագրային թարմացումներ չի ստանում։ Որպեսզի աշխատելն ավելի հարմար լինի, ձեռք բերեք նոր Chromebook սարք։</translation>
 <translation id="133535873114485416">Ներածման նախընտրելի եղանակ</translation>
-<translation id="1335437153193710305">Դուք կարող եք ընտրել պրոֆիլը, որի գաղտնաբառերն ուզում եք տեսնել</translation>
 <translation id="1335929031622236846">Գրանցեք ձեր սարքը</translation>
 <translation id="1336902454946927954">Անվտանգության բանալին կողպված է, քանի որ չի հաջողվել ճանաչել ձեր մատնահետքը։ Ապակողպելու համար մուտքագրեք ձեր PIN կոդը։</translation>
 <translation id="1338631221631423366">Զուգակցում…</translation>
@@ -3314,7 +3314,6 @@
 <translation id="383669374481694771">Սրանք ընդհանուր տեղեկություններ են այս սարքի և դրա օգտագործման (օրինակ՝ մարտկոցի լիցքի, համակարգի ու հավելվածների օգտագործման և սխալների) մասին։ Տեղեկություններն օգտագործվելու են Android-ի ծառայությունների աշխատանքը բարելավելու համար։ Տվյալների մի մասը օգտակար կլինի մեր գործընկերների, օրինակ, Android ծրագրավորողների համար և կօգնի բարելավել նաև նրանց հավելվածներն ու արտադրանքները։</translation>
 <translation id="3838085852053358637">Չհաջողվեց բեռնել ընդլայնումը</translation>
 <translation id="3838486795898716504"><ph name="PAGE_TITLE" /> վերնագրով այլ էջեր</translation>
-<translation id="3838487810283346084">Ավելացրեք պահված գաղտնաբառերը Google գաղտնաբառերի կառավարիչում</translation>
 <translation id="383891835335927981">Ոչ մի կայք չի մասշտաբավորվել</translation>
 <translation id="3839509547554145593">Միացնել մկնիկով ոլորման արագացումը</translation>
 <translation id="3839516600093027468">Միշտ արգելափակել <ph name="HOST" /> կայքի մուտքը սեղմատախտակին</translation>
diff --git a/chrome/app/resources/generated_resources_id.xtb b/chrome/app/resources/generated_resources_id.xtb
index 4f49d85..9a5d919 100644
--- a/chrome/app/resources/generated_resources_id.xtb
+++ b/chrome/app/resources/generated_resources_id.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Sebaiknya sediakan ruang minimal <ph name="INSTALL_SIZE" /> untuk Linux. Untuk menambah ruang kosong, hapus file dari perangkat Anda.</translation>
 <translation id="1038643060055067718">Baris:</translation>
 <translation id="1039337018183941703">File tidak valid atau rusak</translation>
+<translation id="1040761927998636252">Bookmark tanpa nama untuk <ph name="URL" /></translation>
 <translation id="1041175011127912238">Halaman ini tidak merespons</translation>
 <translation id="1041263367839475438">Perangkat yang tersedia</translation>
 <translation id="1042174272890264476">Komputer Anda juga dilengkapi dengan perpustakaan RLZ <ph name="SHORT_PRODUCT_NAME" /> yang tertanam di dalamnya. RLZ menetapkan tag tak unik dan tidak dapat diidentifikasi secara pribadi untuk mengukur penelusuran dan penggunaan <ph name="SHORT_PRODUCT_NAME" /> yang didorong oleh kampanye promosi tertentu. Biasanya label ini muncul di kueri Google Penelusuran di <ph name="PRODUCT_NAME" />.</translation>
@@ -389,7 +390,6 @@
 <translation id="1333965224356556482">Jangan izinkan situs melihat lokasi Anda</translation>
 <translation id="1335282218035876586">Chromebook Anda tidak lagi menerima update keamanan dan software. Upgrade Chromebook Anda untuk mendapatkan pengalaman terbaik.</translation>
 <translation id="133535873114485416">Preferensi masukan</translation>
-<translation id="1335437153193710305">Anda dapat memilih profil yang ingin Anda lihat sandinya</translation>
 <translation id="1335929031622236846">Daftarkan perangkat Anda</translation>
 <translation id="1336902454946927954">Kunci keamanan Anda dikunci karena sidik jari Anda tidak dapat dikenali. Untuk membuka kuncinya, masukkan PIN.</translation>
 <translation id="1338631221631423366">Menyambungkan ...</translation>
@@ -3327,7 +3327,6 @@
 <translation id="383669374481694771">Ini adalah informasi umum tentang perangkat ini dan cara penggunaannya (seperti tingkat daya baterai, aktivitas sistem dan aplikasi, serta error). Data ini akan digunakan untuk menyempurnakan Android. Beberapa informasi gabungan juga akan membantu aplikasi dan partner Google, seperti developer Android, membuat aplikasi dan produk mereka menjadi lebih baik.</translation>
 <translation id="3838085852053358637">Gagal memuat ekstensi</translation>
 <translation id="3838486795898716504"><ph name="PAGE_TITLE" /> Lainnya</translation>
-<translation id="3838487810283346084">Tambahkan sandi tersimpan ke Pengelola Sandi Google</translation>
 <translation id="383891835335927981">Tidak ada situs yang telah diperbesar atau diperkecil</translation>
 <translation id="3839509547554145593">Aktifkan akselerasi scroll mouse</translation>
 <translation id="3839516600093027468">Selalu blokir <ph name="HOST" /> dari melihat papan klip</translation>
diff --git a/chrome/app/resources/generated_resources_is.xtb b/chrome/app/resources/generated_resources_is.xtb
index e682c7d..9ea879db 100644
--- a/chrome/app/resources/generated_resources_is.xtb
+++ b/chrome/app/resources/generated_resources_is.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Mælt er með að minnsta kosti <ph name="INSTALL_SIZE" /> af lausu plássi til að nota Linux. Eyddu skrám úr tækinu til að auka geymslurýmið.</translation>
 <translation id="1038643060055067718">Línur:</translation>
 <translation id="1039337018183941703">Ógild eða skemmd skrá</translation>
+<translation id="1040761927998636252">Bókamerki án heitis fyrir <ph name="URL" /></translation>
 <translation id="1041175011127912238">Þessi síða svarar ekki.</translation>
 <translation id="1041263367839475438">Tæki í boði</translation>
 <translation id="1042174272890264476">RLZ-safn <ph name="SHORT_PRODUCT_NAME" /> er einnig innbyggt í tölvuna. RLZ úthlutar merki sem er ekki einkvæmt og ekki persónugreinanlegt til að mæla leitarvirkni og notkun <ph name="SHORT_PRODUCT_NAME" /> hjá tiltekinni auglýsingaherferð. Þessi merki birtast stundum í leitarfyrirspurnum á Google í <ph name="PRODUCT_NAME" />.</translation>
@@ -390,7 +391,6 @@
 <translation id="1333965224356556482">Ekki leyfa vefsvæðum að sjá staðsetninguna þína</translation>
 <translation id="1335282218035876586">Chromebook-tölvan þín fær ekki öryggis- og hugbúnaðaruppfærslur lengur. Uppfærðu Chromebook-tölvuna til að upplifunin verði sem best.</translation>
 <translation id="133535873114485416">Inntak sem skal nota</translation>
-<translation id="1335437153193710305">Þú getur valið á hvaða prófíl þú sérð aðgangsorðin</translation>
 <translation id="1335929031622236846">Skráðu tækið þitt</translation>
 <translation id="1336902454946927954">Öryggislykillinn þinn er læstur vegna þess að fingrafarið þitt þekktist ekki. Sláðu inn PIN-númerið þitt til að opna hann.</translation>
 <translation id="1338631221631423366">Parar...</translation>
@@ -3328,7 +3328,6 @@
 <translation id="383669374481694771">Þetta eru almennar upplýsingar um þetta tæki og notkun þess (eins og stöðu rafhlöðunnar, kerfis- og forritavirkni og villur). Gögnin verða notuð til að bæta Android stýrikerfið og sumar uppsafnaðar upplýsingar geta gagnast forritum Google og samstarfsaðilum okkar, svo sem þróunaraðilum fyrir Android, við að bæta forrit og vörur.</translation>
 <translation id="3838085852053358637">Ekki tókst að hlaða viðbót</translation>
 <translation id="3838486795898716504">Fleiri <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Bættu vistuðum aðgangsorðum við Google aðgangsorðastjórnun</translation>
 <translation id="383891835335927981">Aðdráttur hefur ekki verið aukinn eða minnkaður á neinum vefsvæðum</translation>
 <translation id="3839509547554145593">Kveikja á flettihröðun músar</translation>
 <translation id="3839516600093027468">Koma alltaf í veg fyrir að <ph name="HOST" /> sjái klippiborðið</translation>
diff --git a/chrome/app/resources/generated_resources_it.xtb b/chrome/app/resources/generated_resources_it.xtb
index 728b4163..0705a07 100644
--- a/chrome/app/resources/generated_resources_it.xtb
+++ b/chrome/app/resources/generated_resources_it.xtb
@@ -389,7 +389,6 @@
 <translation id="1333965224356556482">Non consentire ai siti di vedere la tua posizione</translation>
 <translation id="1335282218035876586">Il tuo Chromebook non riceve più aggiornamenti della sicurezza e del software. Esegui l'upgrade di Chromebook per un'esperienza ottimale.</translation>
 <translation id="133535873114485416">Metodo di immissione preferito</translation>
-<translation id="1335437153193710305">Puoi scegliere il profilo da cui visualizzare le password</translation>
 <translation id="1335929031622236846">Registra il tuo dispositivo</translation>
 <translation id="1336902454946927954">Il token di sicurezza è bloccato perché non è stato possibile riconoscere la tua impronta. Per sbloccarlo, inserisci il PIN.</translation>
 <translation id="1338631221631423366">Accoppiamento in corso…</translation>
@@ -3315,7 +3314,6 @@
 <translation id="383669374481694771">Si tratta di informazioni generali su questo dispositivo e sulla relativa modalità di utilizzo, ad esempio il livello della batteria, l'attività nelle app e nel sistema e gli errori. I dati saranno utilizzati per migliorare Android e alcune informazioni aggregate saranno utili anche alle app e ai partner di Google, come ad esempio agli sviluppatori Android, che potranno migliorare i propri prodotti e le proprie app.</translation>
 <translation id="3838085852053358637">Caricamento estensione non riuscito</translation>
 <translation id="3838486795898716504">Altre <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Aggiungi le password salvate a Gestore delle password di Google</translation>
 <translation id="383891835335927981">Non è stato aumentato o diminuito lo zoom di alcun sito</translation>
 <translation id="3839509547554145593">Attiva l'accelerazione di scorrimento del mouse</translation>
 <translation id="3839516600093027468">Impedisci sempre a <ph name="HOST" /> di leggere gli appunti</translation>
diff --git a/chrome/app/resources/generated_resources_iw.xtb b/chrome/app/resources/generated_resources_iw.xtb
index 33f24c4..b09d9e0 100644
--- a/chrome/app/resources/generated_resources_iw.xtb
+++ b/chrome/app/resources/generated_resources_iw.xtb
@@ -392,7 +392,6 @@
 <translation id="1333965224356556482">לא לאפשר לאתרים לראות את המיקום שלך</translation>
 <translation id="1335282218035876586">‏לא יתקבלו יותר עדכוני אבטחה ותוכנה במכשיר Chromebook שלך. מומלץ לשדרג את מכשיר Chromebook כדי ליהנות מהחוויה הטובה ביותר.</translation>
 <translation id="133535873114485416">קלט מועדף</translation>
-<translation id="1335437153193710305">אפשר לבחור את הפרופיל שממנו יוצגו הסיסמאות</translation>
 <translation id="1335929031622236846">רישום המכשיר שלך</translation>
 <translation id="1336902454946927954">מפתח האבטחה נעול מאחר שאי אפשר לזהות את טביעת האצבע שלך. כדי לבטל את הנעילה, יש להזין את קוד האימות.</translation>
 <translation id="1338631221631423366">מתבצעת התאמה…</translation>
@@ -3328,7 +3327,6 @@
 <translation id="383669374481694771">‏זהו מידע כללי על המכשיר הזה ואופן השימוש בו (למשל רמת הסוללה, פעילות המערכת, הפעילות באפליקציות ושגיאות). הנתונים האלה ישמשו כדי לשפר את Android. חלק מהמידע הנצבר יעזור גם לשפר את האפליקציות של Google, וכן יעזור לשותפים של Google (למשל למפתחים של Android) לשפר את האפליקציות והמוצרים שלהם.</translation>
 <translation id="3838085852053358637">טעינת התוסף נכשלה</translation>
 <translation id="3838486795898716504"><ph name="PAGE_TITLE" /> נוספים</translation>
-<translation id="3838487810283346084">‏אפשר להוסיף סיסמאות שמורות למנהל הסיסמאות של Google</translation>
 <translation id="383891835335927981">באף אתר לא השתנה המרחק מהתצוגה</translation>
 <translation id="3839509547554145593">הפעלה של האצת גלילה בעכבר</translation>
 <translation id="3839516600093027468">יש למנוע תמיד מ-<ph name="HOST" /> לגשת אל הלוח</translation>
diff --git a/chrome/app/resources/generated_resources_ja.xtb b/chrome/app/resources/generated_resources_ja.xtb
index 923eac61..867aaf2 100644
--- a/chrome/app/resources/generated_resources_ja.xtb
+++ b/chrome/app/resources/generated_resources_ja.xtb
@@ -388,7 +388,6 @@
 <translation id="1333965224356556482">サイトに位置情報へのアクセスを許可しない</translation>
 <translation id="1335282218035876586">この Chromebook は、セキュリティ アップデートとソフトウェア アップデートの提供が終了しました。快適にご利用いただくには、Chromebook をアップグレードしてください。</translation>
 <translation id="133535873114485416">優先する入力</translation>
-<translation id="1335437153193710305">パスワードを表示するプロフィールを選択できます</translation>
 <translation id="1335929031622236846">デバイスを登録する</translation>
 <translation id="1336902454946927954">指紋を認識できなかったため、セキュリティ キーがロックされています。ロックを解除するには PIN を入力してください。</translation>
 <translation id="1338631221631423366">ペア設定中...</translation>
@@ -3306,7 +3305,6 @@
 <translation id="383669374481694771">このデバイスと使用状況に関する一般的な情報(電池残量、システムやアプリのアクティビティ、エラーなど)です。このデータは、Android の機能向上に使用されます。また、統計情報の一部は、Google のアプリのほか、Android デベロッパーなどのパートナーが開発するアプリやサービスの品質改善にも役立てられます。</translation>
 <translation id="3838085852053358637">拡張機能を読み込めませんでした</translation>
 <translation id="3838486795898716504"><ph name="PAGE_TITLE" /> をもっと見る</translation>
-<translation id="3838487810283346084">保存したパスワードを Google パスワード マネージャーに追加する</translation>
 <translation id="383891835335927981">拡大縮小値を設定したサイトはありません</translation>
 <translation id="3839509547554145593">マウスのスクロール アクセラレーションを有効にする</translation>
 <translation id="3839516600093027468"><ph name="HOST" /> によるクリップボードへのアクセスを常にブロックする</translation>
diff --git a/chrome/app/resources/generated_resources_ka.xtb b/chrome/app/resources/generated_resources_ka.xtb
index 49fb27b..9764bf5c 100644
--- a/chrome/app/resources/generated_resources_ka.xtb
+++ b/chrome/app/resources/generated_resources_ka.xtb
@@ -389,7 +389,6 @@
 <translation id="1333965224356556482">საიტებისთვის თქვენი მდებარეობის ნახვის აკრძალვა</translation>
 <translation id="1335282218035876586">თქვენი Chromebook აღარ იღებს უსაფრთხოებისა და პროგრამული უზრუნველყოფის განახლებებს. საუკეთესო ფუნქციებით რომ ისარგებლოთ, გამოცვალეთ თქვენი Chromebook.</translation>
 <translation id="133535873114485416">შეყვანის სასურველი მეთოდი</translation>
-<translation id="1335437153193710305">შეგიძლიათ აირჩიოთ პროფილი, რომლიდანაც გსურთ პაროლების ნახვა</translation>
 <translation id="1335929031622236846">თქვენი მოწყობილობის რეგისტრაცია</translation>
 <translation id="1336902454946927954">თქვენი უსაფრთხოების გასაღები ჩაკეტილია, რადგან თითის ანაბეჭდის ამოცნობა ვერ მოხერხდა. განსაბლოკად შეიყვანეთ PIN-კოდი.</translation>
 <translation id="1338631221631423366">მიმდინარეობს დაწყვილება...</translation>
@@ -3315,7 +3314,6 @@
 <translation id="383669374481694771">ეს არის ზოგადი ინფორმაცია ამ მოწყობილობისა და მისი გამოყენების შესახებ (მაგ. ბატარეის დონე, სისტემისა და აპების აქტივობა თუ შეცდომები). აღნიშნული მონაცემები ხელს შეუწყობს Android-ის გაუმჯობესებას, ხოლო შეჯამებული ინფორმაციის ნაწილი ასევე სასარგებლო იქნება Google-ის აპებისა და პარტნიორებისთვის, მაგალითად, Android-ის დეველოპერებისთვის, რომლებიც შეძლებენ საკუთარი აპებისა და პროდუქტების დახვეწას.</translation>
 <translation id="3838085852053358637">გაფართოება ვერ ჩაიტვირთა</translation>
 <translation id="3838486795898716504">მეტი <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">დაამატეთ შენახული პაროლები Google პაროლების მმართველს</translation>
 <translation id="383891835335927981">მასშტაბის გადიდება ან შემცირება არცერთ საიტზე არ მოხდარა</translation>
 <translation id="3839509547554145593">მაუსით გადაადგილების დაჩქარების ჩართვა</translation>
 <translation id="3839516600093027468">ყოველთვის აეკრძალოს <ph name="HOST" />-ს გაცვლის ბუფერის ნახვა</translation>
diff --git a/chrome/app/resources/generated_resources_kk.xtb b/chrome/app/resources/generated_resources_kk.xtb
index 71a52d7c..65673fd 100644
--- a/chrome/app/resources/generated_resources_kk.xtb
+++ b/chrome/app/resources/generated_resources_kk.xtb
@@ -388,7 +388,6 @@
 <translation id="1333965224356556482">Сайттардың геодерегіңізді көруіне рұқсат бермеу</translation>
 <translation id="1335282218035876586">Chromebook жүйеңіз енді қауіпсіздік және бағдарламалық құрал жаңартуларын алмайды. Барынша жақсы жұмыс үшін жаңа Chromebook сатып алыңыз.</translation>
 <translation id="133535873114485416">Қалаған енгізу әдісі</translation>
-<translation id="1335437153193710305">Құпия сөздерді көргіңіз келетін профильді таңдауға болады.</translation>
 <translation id="1335929031622236846">Құрылғыны тіркеу</translation>
 <translation id="1336902454946927954">Саусағыңыздың ізі танылмағандықтан, қауіпсіздік кілті құлыптаулы тұр. Оның құлпын ашу үшін PIN кодыңызды енгізіңіз.</translation>
 <translation id="1338631221631423366">Жұпталуда…</translation>
@@ -3310,7 +3309,6 @@
 <translation id="383669374481694771">Бұл – осы құрылғы мен оны пайдалану (мысалы, батарея зарядының деңгейі, жүйе мен қолданбаларды пайдалану тарихы, қателер) туралы жалпы ақпарат. Мәлімет Android жүйесін жақсарту үшін пайдаланылады, ал кейбір ақпарат Google қолданбаларына және Android әзірлеушілері сияқты серіктестерге көмектеседі әрі олардың қолданбалары мен өнімдерін жақсарта түседі.</translation>
 <translation id="3838085852053358637">Кеңейтім жүктелмеді</translation>
 <translation id="3838486795898716504"><ph name="PAGE_TITLE" /> атауы қойылған басқа беттер</translation>
-<translation id="3838487810283346084">Сақталған құпия сөздерді Google Құпия сөз менеджеріне қосу</translation>
 <translation id="383891835335927981">Ешқандай сайт ұлғайтылмады не кішірейтілмеді</translation>
 <translation id="3839509547554145593">Тінтуірді айналдыру жылдамдығын арттыруды қосу</translation>
 <translation id="3839516600093027468"><ph name="HOST" /> хостының буферді көруіне әрқашан тыйым салу</translation>
diff --git a/chrome/app/resources/generated_resources_km.xtb b/chrome/app/resources/generated_resources_km.xtb
index dec4a29b7..7313e03 100644
--- a/chrome/app/resources/generated_resources_km.xtb
+++ b/chrome/app/resources/generated_resources_km.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">មិនអនុញ្ញាតឱ្យ​គេហទំព័រ​មើលឃើញ​ទីតាំងរបស់អ្នកទេ</translation>
 <translation id="1335282218035876586">Chromebook របស់អ្នកលែងទទួលបានការធ្វើបច្ចុប្បន្នភាព​ផ្នែក​សុវត្ថិភាព និងកំណែកម្មវិធីថ្មីៗទៀតហើយ។ សូមប្ដូរ Chromebook របស់អ្នក ដើម្បីទទួលបានបទពិសោធន៍ល្អបំផុត។</translation>
 <translation id="133535873114485416">ការ​បញ្ចូលតាម​ចំណូលចិត្ត</translation>
-<translation id="1335437153193710305">អ្នកអាចជ្រើសរើសកម្រងព័ត៌មានដែលអ្នកចង់ឃើញពាក្យសម្ងាត់</translation>
 <translation id="1335929031622236846">ចុះឈ្មោះ​ឧបករណ៍​របស់អ្នក</translation>
 <translation id="1336902454946927954">សោសុវត្ថិភាព​របស់អ្នក​ត្រូវបានចាក់សោ ដោយសារ​មិនអាចសម្គាល់​ស្នាមម្រាមដៃរបស់អ្នក។ ដើម្បីដោះសោសុវត្ថិភាពនេះ សូមបញ្ចូលកូដ PIN របស់អ្នក។</translation>
 <translation id="1338631221631423366">កំពុងផ្គូផ្គង...</translation>
@@ -3330,7 +3329,6 @@
 <translation id="383669374481694771">នេះគឺជា​ព័ត៌មាន​ទូទៅអំពី​ឧបករណ៍​នេះ និង​របៀបប្រើប្រាស់​ (ដូចជា​កម្រិតថ្ម សកម្មភាព​កម្មវិធី និងប្រព័ន្ធ ព្រមទាំង​បញ្ហានានា)។ ទិន្នន័យនេះ​នឹងត្រូវ​បានប្រើប្រាស់ ដើម្បី​កែលម្អ Android ហើយព័ត៌មាន​ដែលបាន​ប្រមូល​មួយចំនួនក៏​នឹងជួយ​ឱ្យកម្មវិធី និងដៃគូ Google ដូចជា​អ្នកអភិវឌ្ឍន៍ Android ធ្វើឱ្យ​កម្មវិធី និង​ផលិតផល​របស់​ពួកគេ​ប្រសើរ​ជាងមុន​ផងដែរ។</translation>
 <translation id="3838085852053358637">មិនអាច​ផ្ទុក​កម្មវិធីបន្ថែម​បាន​ទេ</translation>
 <translation id="3838486795898716504">ច្រើនទៀត <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">បញ្ចូល​ពាក្យសម្ងាត់​ដែល​បាន​រក្សាទុក​ទៅ​ក្នុង​កម្មវិធីគ្រប់គ្រងពាក្យសម្ងាត់</translation>
 <translation id="383891835335927981">គ្មាន​ទំព័រ​ដែល​បាន​ពង្រីក ឬ​បង្រួម​ទេ</translation>
 <translation id="3839509547554145593">បើកការ​បង្កើន​ល្បឿនរំកិល​កណ្ដុរ</translation>
 <translation id="3839516600093027468">ទប់ស្កាត់មិន​ឱ្យ <ph name="HOST" /> មើល​​អង្គចងចាំ​ជានិច្ច</translation>
diff --git a/chrome/app/resources/generated_resources_kn.xtb b/chrome/app/resources/generated_resources_kn.xtb
index b43cd37..41b3e5d 100644
--- a/chrome/app/resources/generated_resources_kn.xtb
+++ b/chrome/app/resources/generated_resources_kn.xtb
@@ -118,6 +118,7 @@
 <translation id="1090541560108055381">ಜೋಡಿಸುವ ಮೊದಲು, ಎರಡೂ ಸಾಧನಗಳಲ್ಲಿ ಈ ಕೋಡ್ ಒಂದೇ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ</translation>
 <translation id="1091767800771861448">ಸ್ಕಿಪ್‌ ಮಾಡಲು ESCAPE ಅನ್ನು ಒತ್ತಿರಿ (ಅಧಿಕೃತವಲ್ಲದ ಬಿಲ್ಡ್‌ಗಳಿಗೆ ಮಾತ್ರ).</translation>
 <translation id="1093457606523402488">ಗೋಚರಿಸುವ ನೆಟ್‌ವರ್ಕ್‌ಗಳು:</translation>
+<translation id="1094219634413363886">ಈ ನಿರ್ವಹಿಸಲ್ಪಟ್ಟ ಸಾಧನದಲ್ಲಿ ರೆಕಾರ್ಡಿಂಗ್ ಪ್ರಾರಂಭವಾದರೆ ನೀವು ಅಧಿಸೂಚನೆಯೊಂದನ್ನು ಕಾಣುತ್ತೀರಿ</translation>
 <translation id="1095761715416917775">ನಿಮ್ಮ ಸಿಂಕ್ ಡೇಟಾಕ್ಕೆ ನೀವು ಯಾವಾಗಲೂ ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಾಗುವ ಹಾಗೆ ನೋಡಿಕೊಳ್ಳಿ</translation>
 <translation id="1095879482467973146">ವೆಬ್‌ನಲ್ಲಿನ Google Password Manager</translation>
 <translation id="109647177154844434">Parallels Desktop ಅನ್ನು ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡುವುದರಿಂದ ನಿಮ್ಮ Windows ಚಿತ್ರವನ್ನು ಅಳಿಸುತ್ತದೆ. ಅದರ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಇದು ಒಳಗೊಂಡಿರುತ್ತದೆ. ನೀವು ಮುಂದುವರಿಸಲು ಬಯಸುವಿರಾ?</translation>
@@ -391,7 +392,6 @@
 <translation id="1333965224356556482">ನಿಮ್ಮ ಸ್ಥಳವನ್ನು ನೋಡಲು ಸೈಟ್‌ಗಳಿಗೆ ಅನುಮತಿಸಬೇಡಿ</translation>
 <translation id="1335282218035876586">ನಿಮ್ಮ Chromebook ಇನ್ನು ಮುಂದೆ ಭದ್ರತೆ ಮತ್ತು ಸಾಫ್ಟ್‌ವೇರ್ ಅಪ್‌ಡೇಟ್‌ಗಳನ್ನು ಸ್ವೀಕರಿಸುವುದಿಲ್ಲ. ಅತ್ಯುತ್ತಮ ಅನುಭವಕ್ಕಾಗಿ ನಿಮ್ಮ Chromebook ಅನ್ನು ಅಪ್‌ಗ್ರೇಡ್ ಮಾಡಿ.</translation>
 <translation id="133535873114485416">ಆದ್ಯತೆಯ ಇನ್‌ಪುಟ್</translation>
-<translation id="1335437153193710305">ನೀವು ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ನೋಡಲು ಬಯಸುವ ಪ್ರೊಫೈಲ್ ಅನ್ನು ನೀವು ಆಯ್ಕೆಮಾಡಬಹುದು</translation>
 <translation id="1335929031622236846">ನಿಮ್ಮ ಸಾಧನವನ್ನು ನೋಂದಾಯಿಸಿಕೊಳ್ಳಿ</translation>
 <translation id="1336902454946927954">ನಿಮ್ಮ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್ನು ಗುರುತಿಸಲು ಸಾಧ್ಯವಾಗದ ಕಾರಣ, ನಿಮ್ಮ ಸುರಕ್ಷತಾ ಕೀ ಲಾಕ್ ಆಗಿದೆ. ಇದನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು, ನಿಮ್ಮ ಪಿನ್ ಅನ್ನು ನಮೂದಿಸಿ.</translation>
 <translation id="1338631221631423366">ಜೋಡಿಸಲಾಗುತ್ತಿದೆ...</translation>
@@ -3134,6 +3134,7 @@
 <translation id="369489984217678710">ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಮತ್ತು ಇತರ ಸೈನ್-ಇನ್ ಡೇಟಾ</translation>
 <translation id="369522892592566391">{NUM_FILES,plural, =0{ಭದ್ರತೆ ಪರಿಶೀಲನೆಗಳನ್ನು ಮಾಡಲಾಗಿದೆ. ನಿಮ್ಮ ಡೇಟಾವನ್ನು ಅಪ್‌ಲೋಡ್ ಮಾಡಲಾಗುತ್ತದೆ.}=1{ಭದ್ರತೆ ಪರಿಶೀಲನೆಗಳನ್ನು ಮಾಡಲಾಗಿದೆ. ನಿಮ್ಮ ಫೈಲ್ ಅನ್ನು ಅಪ್‌ಲೋಡ್ ಮಾಡಲಾಗುತ್ತದೆ.}one{ಭದ್ರತೆ ಪರಿಶೀಲನೆಗಳನ್ನು ಮಾಡಲಾಗಿದೆ. ನಿಮ್ಮ ಫೈಲ್‌ಗಳನ್ನು ಅಪ್‌ಲೋಡ್ ಮಾಡಲಾಗುತ್ತದೆ.}other{ಭದ್ರತೆ ಪರಿಶೀಲನೆಗಳನ್ನು ಮಾಡಲಾಗಿದೆ. ನಿಮ್ಮ ಫೈಲ್‌ಗಳನ್ನು ಅಪ್‌ಲೋಡ್ ಮಾಡಲಾಗುತ್ತದೆ.}}</translation>
 <translation id="3696817060563289264">ಪಠ್ಯ ಗುರುತಿಸುವಿಕೆ ಫೈಲ್‌ಗಳನ್ನು ಡೌನ್‌ಲೋಡ್ ಮಾಡಲಾಗಿದೆ</translation>
+<translation id="3697716475445175867">ಕೊನೆಯದಾಗಿ ತೆರೆದಿರುವುದು</translation>
 <translation id="3698471669415859717">ಪರಿಶೀಲನೆ ಪೂರ್ಣಗೊಂಡಿದೆ</translation>
 <translation id="3698825735945432002">ಫಿಲ್ಟರ್ ಪ್ರಕಾರ</translation>
 <translation id="3699624789011381381">ಇಮೇಲ್ ವಿಳಾಸ</translation>
@@ -3322,7 +3323,6 @@
 <translation id="383669374481694771">ಇದು, ಈ ಸಾಧನದ ಕುರಿತು ಮತ್ತು ಅದನ್ನು ಹೇಗೆ ಬಳಸಲಾಗುತ್ತದೆ ಎಂಬ ಕುರಿತು ಸಾಮಾನ್ಯ ಮಾಹಿತಿಯಾಗಿದೆ (ಉದಾಹರಣೆಗೆ, ಬ್ಯಾಟರಿಯ ಮಟ್ಟ, ಸಿಸ್ಟಂ ಹಾಗೂ ಆ್ಯಪ್ ಚಟುವಟಿಕೆ, ಮತ್ತು ದೋಷಗಳು). Android ಅನ್ನು ಸುಧಾರಿಸಲು ಈ ಡೇಟಾವನ್ನು ಬಳಸಲಾಗುತ್ತದೆ ಮತ್ತು ಒಟ್ಟುಗೂಡಿಸಲಾದ ಕೆಲವೊಂದು ಮಾಹಿತಿಯು, Google ಆ್ಯಪ್‌ಗಳಿಗೆ ಮತ್ತು Android ಡೆವಲಪರ್‌ಗಳಂತಹ ಪಾಲುದಾರರಿಗೆ, ತಮ್ಮ ಆ್ಯಪ್‌ಗಳು ಹಾಗೂ ಉತ್ಪನ್ನಗಳನ್ನು ಉತ್ತಮಗೊಳಿಸಲು ಸಹಾಯ ಮಾಡುತ್ತದೆ.</translation>
 <translation id="3838085852053358637">ವಿಸ್ತರಣೆಯನ್ನು ಲೋಡ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ</translation>
 <translation id="3838486795898716504">ಇನ್ನಷ್ಟು <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">ಉಳಿಸಿದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು Google ಪಾಸ್‌ವರ್ಡ್ ನಿರ್ವಾಹಕದಲ್ಲಿ ಸೇರಿಸಿ</translation>
 <translation id="383891835335927981">ಯಾವುದೇ ಸೈಟ್‌ಗಳನ್ನು ಝೂಮ್ ಇನ್ ಅಥವಾ ಝೂಮ್ ಔಟ್ ಮಾಡಲಾಗಿಲ್ಲ</translation>
 <translation id="3839509547554145593">ಮೌಸ್ ಸ್ಕ್ರಾಲ್ ವೇಗವರ್ಧಕವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ</translation>
 <translation id="3839516600093027468"><ph name="HOST" /> ಕ್ಲಿಪ್‌ಬೋರ್ಡ್ ನೋಡುವುದನ್ನು ಯಾವಾಗಲೂ ನಿರ್ಬಂಧಿಸಿ</translation>
@@ -3862,6 +3862,7 @@
 <translation id="4340125850502689798">ಮಾನ್ಯವಲ್ಲದ ಬಳಕೆದಾರರ ಹೆಸರು</translation>
 <translation id="4340515029017875942">"<ph name="EXTENSION_NAME" />" ಅಪ್ಲಿಕೇಶನ್ ನೊಂದಿಗೆ <ph name="ORIGIN" /> ಸಂಪರ್ಕಿಸಲು ಬಯಸುತ್ತದೆ</translation>
 <translation id="4340799661701629185">ಅಧಿಸೂಚನೆಗಳನ್ನು ಕಳುಹಿಸಲು ಸೈಟ್‌ಗಳಿಗೆ ಅನುಮತಿಸಬೇಡಿ</translation>
+<translation id="4341280816303414009">ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಅನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು</translation>
 <translation id="4341577178275615435">ಕೆರೆಟ್ ಬ್ರೌಸಿಂಗ್ ಆನ್ ಅಥವಾ ಆಫ್ ಮಾಡಲು, F7 ಶಾರ್ಟ್‌ಕಟ್ ಬಳಸಿ</translation>
 <translation id="4341905082470253054">TPM ಸ್ಥಿತಿಯನ್ನು ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ...</translation>
 <translation id="434198521554309404">ವೇಗ. ಸುರಕ್ಷಿತ. ಶ್ರಮರಹಿತ.</translation>
@@ -5686,6 +5687,7 @@
 <translation id="5979421442488174909"><ph name="LANGUAGE" /> ಗೆ &amp;ಭಾಷಾಂತರಿಸಿ</translation>
 <translation id="5979469435153841984">ಪುಟಗಳನ್ನು ಬುಕ್‌ಮಾರ್ಕ್‌ ಮಾಡಲು, ವಿಳಾಸಪಟ್ಟಿಯಲ್ಲಿರುವ ನಕ್ಷತ್ರವನ್ನು ಕ್ಲಿಕ್ ಮಾಡಿ</translation>
 <translation id="5981362776161841923">ವಿಸ್ತರಣೆಯನ್ನು ಅನುಮತಿಸಲು, ನಿಮ್ಮ ಡೀಫಾಲ್ಟ್ ಸೆಟ್ಟಿಂಗ್ ಅನ್ನು ಕೆಳಗೆ ಬದಲಾಯಿಸಿ.</translation>
+<translation id="5982578203375898585">ಡೌನ್‌ಲೋಡ್‌ಗಳು ಪೂರ್ಣಗೊಂಡಾಗ ಅವುಗಳನ್ನು ತೋರಿಸಿ</translation>
 <translation id="5984222099446776634">ಇತ್ತೀಚೆಗೆ ಭೇಟಿ ನೀಡಿದವು</translation>
 <translation id="5985458664595100876">ಅಮಾನ್ಯ URL ಫಾರ್ಮ್ಯಾಟ್. \\server\share ಮತ್ತು smb://server/share ಫಾರ್ಮ್ಯಾಟ್‍ಗಳಿಗೆ ಬೆಂಬಲವಿದೆ.</translation>
 <translation id="598810097218913399">ಕಾರ್ಯನಿಯೋಜನೆಯನ್ನು ತೆಗೆದುಹಾಕಿ</translation>
@@ -6364,6 +6366,7 @@
 <translation id="6596816719288285829">IP ವಿಳಾಸ</translation>
 <translation id="6597017209724497268">ಮಾದರಿಗಳು</translation>
 <translation id="6597331566371766302">ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಕೆಳಗಿನ ವಿಸ್ತರಣೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿದ್ದಾರೆ:</translation>
+<translation id="659894938503552850">ಹೊಚ್ಚ ಹೊಸತು</translation>
 <translation id="6601262427770154296">ಬಳಕೆದಾರ ನಿಘಂಟುಗಳನ್ನು ನಿರ್ವಹಿಸಿ</translation>
 <translation id="6601612474695404578">ಕೆಲವು ಸೈಟ್‌ಗಳು ತಮ್ಮ ಪುಟಗಳನ್ನು ಲೋಡ್ ಮಾಡಲು ಥರ್ಡ್ ಪಾರ್ಟಿ ಕುಕೀಗಳನ್ನು ಬಳಸುತ್ತವೆ. ಸೈಟ್ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತಿಲ್ಲದಿದ್ದರೆ, ಕುಕೀಗಳನ್ನು ಅನುಮತಿಸುವ ಮೂಲಕ ನೀವು ಪ್ರಯತ್ನಿಸಬಹುದು.</translation>
 <translation id="6602937173026466876">ನಿಮ್ಮ ಪ್ರಿಂಟರ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಿ</translation>
@@ -8143,6 +8146,7 @@
 <translation id="8161293209665121583">ವೆಬ್ ಪುಟಗಳಿಗಾಗಿ ರೀಡರ್‌ ಮೋಡ್‌</translation>
 <translation id="8161604891089629425">ಔಟ್‌ಲೈನ್ ಫಾಂಟ್</translation>
 <translation id="8162984717805647492">{NUM_TABS,plural, =1{ಟ್ಯಾಬ್ ಅನ್ನು ಹೊಸ ವಿಂಡೋಗೆ ಸರಿಸಿ}one{ಟ್ಯಾಬ್‌ಗಳನ್ನು ಹೊಸ ವಿಂಡೋಗೆ ಸರಿಸಿ}other{ಟ್ಯಾಬ್‌ಗಳನ್ನು ಹೊಸ ವಿಂಡೋಗೆ ಸರಿಸಿ}}</translation>
+<translation id="8163708146810922598">ತುಂಬಾ ಹಳೆಯದು</translation>
 <translation id="8165997195302308593">Crostini ಪೋರ್ಟ್ ಫಾರ್ವರ್ಡ್ ಮಾಡುವಿಕೆ</translation>
 <translation id="816704878106051517">{COUNT,plural, =1{ಒಂದು ಫೋನ್ ಸಂಖ್ಯೆ}one{# ಫೋನ್ ಸಂಖ್ಯೆಗಳು}other{# ಫೋನ್ ಸಂಖ್ಯೆಗಳು}}</translation>
 <translation id="8168071266284693455">ನಿಮ್ಮ ಎಲ್ಲಾ ಸಾಧನಗಳಲ್ಲಿ ನಿಮ್ಮ ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳು, ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, ಇತಿಹಾಸ ಹಾಗೂ ಇತ್ಯಾದಿಗಳನ್ನು ಸಿಂಕ್ ಮಾಡಲಾಗುತ್ತದೆ</translation>
@@ -8657,6 +8661,7 @@
 <translation id="8637688295594795546">ಸಿಸ್ಟಂ ಅಪ್‌ಡೇಟ್‌‌ ಲಭ್ಯವಿದೆ. ಡೌನ್‌ಲೋಡ್ ಮಾಡಲು ಸಿದ್ಧಗೊಳ್ಳುತ್ತಿದೆ...</translation>
 <translation id="8639047128869322042">ಹಾನಿಕಾರಕ ಸಾಫ್ಟ್‌ವೇರ್‌ಗಾಗಿ ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ...</translation>
 <translation id="8639635302972078117">ಬಳಕೆ ಮತ್ತು ಡಯಾಗ್ನಾಸ್ಟಿಕ್ ಡೇಟಾವನ್ನು ಕಳುಹಿಸಿ. ಪ್ರಸ್ತುತ, ಈ ಸಾಧನವು ಡಯಾಗ್ನಾಸ್ಟಿಕ್, ಸಾಧನ ಹಾಗೂ ಆ್ಯಪ್ ಬಳಕೆಯ ಡೇಟಾವನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ Google ಗೆ ಕಳುಹಿಸುತ್ತಿದೆ. ನಿಮ್ಮ ಮಗುವನ್ನು ಗುರುತಿಸಲು ಈ ಡೇಟಾವನ್ನು ಬಳಸಲಾಗುವುದಿಲ್ಲ, ಹಾಗೂ ಇದು ಸಿಸ್ಟಂ ಮತ್ತು ಆ್ಯಪ್‌ನ ಸ್ಥಿರತೆ, ಹಾಗೂ ಇತರ ಸುಧಾರಣೆಗಳಿಗೆ ಸಹಾಯ ಮಾಡುತ್ತದೆ. ಒಟ್ಟುಗೂಡಿಸಲಾದ ಕೆಲವೊಂದು ಡೇಟಾ, Google ಆ್ಯಪ್‌ಗಳಿಗೆ ಮತ್ತು Android ಡೆವಲಪರ್‌ಗಳಂತಹ ಪಾಲುದಾರರಿಗೂ ಸಹಾಯ ಮಾಡುತ್ತದೆ. ನಿಮ್ಮ ಮಗುವಿಗಾಗಿ, ಹೆಚ್ಚುವರಿ ವೆಬ್ ಮತ್ತು ಆ್ಯಪ್‌ ಚಟುವಟಿಕೆಯನ್ನು ಆನ್ ಮಾಡಿದ್ದರೆ, ಈ ಡೇಟಾವನ್ನು ಅವರ Google ಖಾತೆಯಲ್ಲಿ ಉಳಿಸಬಹುದು.</translation>
+<translation id="8640575194957831802">ಕೊನೆಯದಾಗಿ ತೆರೆದಿರುವುದು</translation>
 <translation id="8642900771896232685">2 ಸೆಕೆಂಡುಗಳು</translation>
 <translation id="8642947597466641025">ಪಠ್ಯವನ್ನು ದೊಡ್ಡದಾಗಿಸಿ</translation>
 <translation id="8643403533759285912">ಗುಂಪನ್ನು ಅಳಿಸಿ</translation>
diff --git a/chrome/app/resources/generated_resources_ko.xtb b/chrome/app/resources/generated_resources_ko.xtb
index 38dacf6..f9f8937 100644
--- a/chrome/app/resources/generated_resources_ko.xtb
+++ b/chrome/app/resources/generated_resources_ko.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Linux를 사용하려면 최소 <ph name="INSTALL_SIZE" />의 여유 공간이 권장됩니다. 여유 공간을 늘리려면 기기에서 파일을 삭제하세요.</translation>
 <translation id="1038643060055067718">행 수:</translation>
 <translation id="1039337018183941703">잘못되었거나 손상된 파일입니다.</translation>
+<translation id="1040761927998636252"><ph name="URL" />에 관한 이름 없는 북마크</translation>
 <translation id="1041175011127912238">페이지가 응답하지 않음</translation>
 <translation id="1041263367839475438">사용 가능한 기기</translation>
 <translation id="1042174272890264476">또한 컴퓨터에는 <ph name="SHORT_PRODUCT_NAME" /> RLZ 라이브러리가 내장되어 있습니다. RLZ는 고유하지 않고 개인 식별이 불가능한 태그를 할당하여 특정 홍보 캠페인을 통한 검색 및 <ph name="SHORT_PRODUCT_NAME" /> 사용 실태를 측정합니다. 이러한 라벨은 <ph name="PRODUCT_NAME" />의 Google 검색어에 표시되기도 합니다.</translation>
@@ -389,7 +390,6 @@
 <translation id="1333965224356556482">사이트에서 내 위치를 확인하도록 허용하지 않음</translation>
 <translation id="1335282218035876586">Chromebook에 더 이상 보안 및 소프트웨어 업데이트가 적용되지 않습니다. 최적의 환경에서 사용하려면 Chromebook을 업그레이드하세요.</translation>
 <translation id="133535873114485416">선호하는 입력 방식</translation>
-<translation id="1335437153193710305">비밀번호를 확인할 프로필을 선택할 수 있습니다</translation>
 <translation id="1335929031622236846">기기 등록</translation>
 <translation id="1336902454946927954">지문을 인식할 수 없어 보안 키가 잠겼습니다. 보안 키를 잠금 해제하려면 PIN을 입력하세요.</translation>
 <translation id="1338631221631423366">페어링 중...</translation>
@@ -2041,7 +2041,7 @@
 <translation id="2709516037105925701">자동 완성</translation>
 <translation id="2710101514844343743">사용 및 진단 데이터</translation>
 <translation id="271033894570825754">New</translation>
-<translation id="2711073837061989559">무료 체험</translation>
+<translation id="2711073837061989559">체험판</translation>
 <translation id="2713106313042589954">카메라 끄기</translation>
 <translation id="2713444072780614174">흰색</translation>
 <translation id="2714180132046334502">어두운 배경</translation>
@@ -2685,7 +2685,7 @@
 <translation id="3289856944988573801">업데이트를 확인하려면 이더넷 또는 Wi-Fi를 사용하세요.</translation>
 <translation id="3289886661311231677">사이트와 공유하고 싶지 않은 주제를 차단할 수 있습니다. 또한 Chrome에서는 4주 이상된 주제를 자동으로 삭제합니다.</translation>
 <translation id="3290249595466894471">또한 페이지, 다운로드 항목, 확장 프로그램 활동, 시스템 정보의 표본을 일부 전송하여 새로운 위협을 발견하는 데 도움을 줍니다.</translation>
-<translation id="3293181007446299124">방문 기록은 기기에서 비공개로 유지되며 신고는 사용자의 신원을 보호하기 위해 보고서 전송이 지연됩니다.</translation>
+<translation id="3293181007446299124">방문 기록은 기기에서 비공개로 유지되며 사용자의 신원을 보호하기 위해 보고서 전송이 지연됩니다.</translation>
 <translation id="3293644607209440645">이 페이지 전송</translation>
 <translation id="32939749466444286">Linux 컨테이너가 시작되지 않았습니다. 다시 시도해 주세요.</translation>
 <translation id="3294437725009624529">게스트</translation>
@@ -3329,7 +3329,6 @@
 <translation id="383669374481694771">기기 및 기기 사용 방식에 관한 일반적인 정보(배터리 수준, 시스템 및 앱 활동, 오류 등)입니다. 데이터는 Android를 개선하는 데 사용되며 일부 수집 정보는 Google 앱과 파트너(Android 개발자 등)가 앱 및 제품을 개선하는 데도 도움이 됩니다.</translation>
 <translation id="3838085852053358637">확장 프로그램을 로드하지 못함</translation>
 <translation id="3838486795898716504"><ph name="PAGE_TITLE" /> 더보기</translation>
-<translation id="3838487810283346084">저장된 비밀번호를 Google 비밀번호 관리자에 추가합니다.</translation>
 <translation id="383891835335927981">확대 또는 축소된 사이트가 없음</translation>
 <translation id="3839509547554145593">마우스 스크롤 가속 사용</translation>
 <translation id="3839516600093027468"><ph name="HOST" />에서 클립보드를 볼 수 없도록 항상 차단</translation>
@@ -6968,7 +6967,7 @@
 <translation id="7123302939607518173">특정 항목과 관련된 광고가 유용하다고 생각한다면 관심분야나 사이트를 추가하세요.</translation>
 <translation id="7124013154139278147">'이전'에 스위치 할당</translation>
 <translation id="7124712201233930202">조직의 정책을 준수하지 않습니다.</translation>
-<translation id="7125029162161377569">개인 정보 보호 샌드박스 무료 체험 기간에는 사이트에서 내 정보를 더 적게 사용하면서도 동일한 인터넷 사용 환경을 제공할 수 있습니다. 즉, 개인 정보 보호는 강화되고 크로스 사이트 추적은 줄어듭니다. 테스트 준비가 완료되는 대로 새로운 무료 체험 프로그램이 추가될 예정입니다.</translation>
+<translation id="7125029162161377569">개인 정보 보호 샌드박스 체험판을 사용하면 사이트에서 내 정보를 더 적게 사용하면서도 동일한 인터넷 사용 환경을 제공할 수 있습니다. 즉, 개인 정보 보호는 강화되고 크로스 사이트 추적은 줄어듭니다. 테스트 준비가 완료되는 대로 새로운 체험 프로그램이 추가될 예정입니다.</translation>
 <translation id="7125148293026877011">Crostini 삭제</translation>
 <translation id="7127980134843952133">다운로드 기록</translation>
 <translation id="7128151990937044829">알림이 차단되면 주소 표시줄에 표시 아이콘 나타내기</translation>
diff --git a/chrome/app/resources/generated_resources_ky.xtb b/chrome/app/resources/generated_resources_ky.xtb
index 779eb70..6a2974bdd 100644
--- a/chrome/app/resources/generated_resources_ky.xtb
+++ b/chrome/app/resources/generated_resources_ky.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Linux үчүн кеминде <ph name="INSTALL_SIZE" /> орун сунушталат. Орун бошотуу үчүн түзмөгүңүздөн файлдарды жок кылыңыз.</translation>
 <translation id="1038643060055067718">Саптар:</translation>
 <translation id="1039337018183941703">Жараксыз же бузук файл</translation>
+<translation id="1040761927998636252"><ph name="URL" /> үчүн аталышы жок кыстарма</translation>
 <translation id="1041175011127912238">Барак жооп бербей жатат</translation>
 <translation id="1041263367839475438">Жеткиликтүү түзмөктөр</translation>
 <translation id="1042174272890264476">Компьютериңизде <ph name="SHORT_PRODUCT_NAME" /> өнүмүнүн RLZ китепканасы камтылган. Белгилүү бир жарнамалык иш-чара башкарган издөө аракеттерин жана <ph name="SHORT_PRODUCT_NAME" /> колдонулушун талдап туруу үчүн RLZ кеңири кездешкен жалпы таанылуучу тегди дайындайт. Бул белгилер айрым учурларда Google Издөө сурамдарындагы <ph name="PRODUCT_NAME" /> өнүмүндө көрүнөт.</translation>
@@ -389,7 +390,6 @@
 <translation id="1333965224356556482">Сайттар жайгашкан жеримди көрө албасын</translation>
 <translation id="1335282218035876586">Chromebook түзмөгүңүз коопсуздук тутумун жана программаларды жаңыртууларды албай калган. Туура иштеши үчүн Chromebook түзмөгүңүздү жаңыртыңыз.</translation>
 <translation id="133535873114485416">Тандалган киргизүү</translation>
-<translation id="1335437153193710305">Сырсөздөрүн көргүңүз келген профилди тандай аласыз</translation>
 <translation id="1335929031622236846">Түзмөгүңүздү каттаңыз</translation>
 <translation id="1336902454946927954">Коопсуздук ачкычыңыз кулпуланды, анткени манжа изиңиз таанылган жок. Анын кулпусун ачуу үчүн PIN кодуңузду киргизиңиз.</translation>
 <translation id="1338631221631423366">Туташууда...</translation>
@@ -3327,7 +3327,6 @@
 <translation id="383669374481694771">Бул жерде түзмөгүңүз жана анын колдонулушу (мисалы, батареянын деңгээли, тутум жана колдонмонун иштетилиши жана каталар) тууралуу жалпы маалымат берилген. Маалымат Android кызматтарын жакшыртууга жана айрым маалыматтар тобу Google колдонмолоруна жана Android'дин иштеп чыгуучулары сыяктуу өнөктөштөрүнө да колдонмолорун жана кызматтарын жакшыртууга жардам берет.</translation>
 <translation id="3838085852053358637">Кеңейтүү жүктөлбөй калды</translation>
 <translation id="3838486795898716504">Дагы <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Сакталган сырсөздөрдү Сырсөздөрдү башкаргычка кошуу</translation>
 <translation id="383891835335927981">Эч кандай сайттар чоңойтуп/кичирейтилген жок</translation>
 <translation id="3839509547554145593">Чычканды ылдамдаткычты иштетүү</translation>
 <translation id="3839516600093027468"><ph name="HOST" /> башкы түйүнүнө алмашуу буфери эч качан көрүнбөсүн</translation>
diff --git a/chrome/app/resources/generated_resources_lo.xtb b/chrome/app/resources/generated_resources_lo.xtb
index 2e9529d5..2a8e6717 100644
--- a/chrome/app/resources/generated_resources_lo.xtb
+++ b/chrome/app/resources/generated_resources_lo.xtb
@@ -390,7 +390,6 @@
 <translation id="1333965224356556482">ບໍ່ອະນຸຍາດໃຫ້ເວັບໄຊເຫັນສະຖານທີ່ຂອງທ່ານ</translation>
 <translation id="1335282218035876586">Chromebook ຂອງທ່ານບໍ່ໄດ້ຮັບການອັບເດດຄວາມປອດໄພ ແລະ ຊອບແວອີກຕໍ່ໄປ. ອັບເກຣດ Chromebook ຂອງທ່ານເພື່ອປະສົບການໃນການໃຊ້ທີ່ດີທີ່ສຸດ.</translation>
 <translation id="133535873114485416">ການປ້ອນຂໍ້ມູນທີ່ຕ້ອງການ</translation>
-<translation id="1335437153193710305">ທ່ານສາມາດເລືອກໂປຣໄຟລ໌ທີ່ທ່ານຕ້ອງການເບິ່ງລະຫັດຜ່ານໄດ້</translation>
 <translation id="1335929031622236846">ລົງທະບຽນອຸປະກອນຂອງທ່ານ</translation>
 <translation id="1336902454946927954">ກະແຈຄວາມປອດໄພຂອງທ່ານຖືກລັອກ ເພາະວ່າບໍ່ສາມາດຮັບຮູ້ລາຍນິ້ວມືຂອງທ່ານໄດ້. ເພື່ອປົດລັອກມັນ, ກະລຸນາປ້ອນ PIN ຂອງທ່ານ.</translation>
 <translation id="1338631221631423366">ກຳລັງຈັບຄູ່...</translation>
@@ -3327,7 +3326,6 @@
 <translation id="383669374481694771">ນີ້ແມ່ນຂໍ້ມູນທົ່ວໄປກ່ຽວກັບອຸປະກອນນີ້ ແລະ ມັນຖືກໃຊ້ແນວໃດ (ເຊັ່ນ: ລະດັບແບັດເຕີຣີ, ການເຄື່ອນໄຫວລະບົບ ແລະ ແອັບ, ຂໍ້ຜິດພາດຕ່າງໆ). ຂໍ້ມູນດັ່ງກ່າວຈະຖືກໃຊ້ເພື່ອປັບປຸງ Android ແລະ ບາງຂໍ້ມູນແບບຮວມກັນຈະຊ່ວຍໃຫ້ແອັບ ແລະ ຮຸ້ນສ່ວນຂອງ Google ເຊັ່ນ: ນັກພັດທະນາແອັບ Android ປັບປຸງແອັບ ແລະ ຜະລິດຕະພັນຂອງເຂົາເຈົ້າໃຫ້ດີຂຶ້ນໄດ້ນຳ.</translation>
 <translation id="3838085852053358637">ໂຫຼດສ່ວນຂະຫຍາຍບໍ່ສຳເລັດ</translation>
 <translation id="3838486795898716504"><ph name="PAGE_TITLE" /> ເພີ່ມເຕີມ</translation>
-<translation id="3838487810283346084">ເພີ່ມລະຫັດຜ່ານທີ່ໄດ້ບັນທຶກໄວ້ໃສ່ຕົວຈັດການລະຫັດຜ່ານ Google Password</translation>
 <translation id="383891835335927981">ບໍ່ມີການຕັ້ງຄ່າຊູມເຂົ້າ ຫຼື ຊູມອອກສຳລັບເວັບໄຊໃດ</translation>
 <translation id="3839509547554145593">ເປີດການນຳໃຊ້ການເລັ່ງຄວາມໄວການເລື່ອນເມົ້າ</translation>
 <translation id="3839516600093027468">ບລັອກບໍ່ໃຫ້ <ph name="HOST" /> ເຫັນຄລິບບອດທຸກເທື່ອ</translation>
diff --git a/chrome/app/resources/generated_resources_lt.xtb b/chrome/app/resources/generated_resources_lt.xtb
index ae6c063..0ff65bc 100644
--- a/chrome/app/resources/generated_resources_lt.xtb
+++ b/chrome/app/resources/generated_resources_lt.xtb
@@ -118,6 +118,7 @@
 <translation id="1090541560108055381">Prieš susiedami įsitikinkite, kad šis kodas sutampa abiejuose įrenginiuose</translation>
 <translation id="1091767800771861448">Jei norite praleisti, paspauskite ESCAPE (galioja tik neoficialioms versijoms).</translation>
 <translation id="1093457606523402488">Matomi tinklai:</translation>
+<translation id="1094219634413363886">Jei šiame valdomame įrenginyje bus pradėtas įrašymas, matysite pranešimą</translation>
 <translation id="1095761715416917775">Galimybė visada pasiekti sinchronizuotus duomenis</translation>
 <translation id="1095879482467973146">„Google“ slaptažodžių tvarkyklė žiniatinklyje</translation>
 <translation id="109647177154844434">Pašalinus „Parallels Desktop“ bus ištrintas „Windows“ vaizdas. Tai apima jo programas, nustatymus ir duomenis. Ar tikrai norite tęsti?</translation>
@@ -393,7 +394,6 @@
 <translation id="1333965224356556482">Neleisti svetainėms peržiūrėti vietovės informacijos</translation>
 <translation id="1335282218035876586">„Chromebook“ nebegauna saugos ir programinės įrangos naujinių. Naujovinkite „Chromebook“, kad galėtumėte pasinaudoti geriausiomis funkcijomis.</translation>
 <translation id="133535873114485416">Pageidaujama įvestis</translation>
-<translation id="1335437153193710305">Galite pasirinkti profilį, kurio slaptažodžius norite peržiūrėti</translation>
 <translation id="1335929031622236846">Įrenginio registracija</translation>
 <translation id="1336902454946927954">Jūsų saugos raktas užrakintas, nes nepavyko atpažinti kontrolinio kodo. Kad jį atrakintumėte, įveskite PIN kodą.</translation>
 <translation id="1338631221631423366">Susiejama...</translation>
@@ -3331,7 +3331,6 @@
 <translation id="383669374481694771">Tai yra bendra informacija apie šį įrenginį ir jo naudojimą (pvz., akumuliatoriaus įkrovos lygį, sistemos ir programų veiklą bei klaidas). Duomenys bus naudojami siekiant patobulinti „Android“, o tam tikra sukaupta informacija taip pat padės „Google“ programoms ir partneriams, pvz., „Android“ kūrėjams, pagerinti savo programas ir produktus.</translation>
 <translation id="3838085852053358637">Nepavyko įkelti plėtinio</translation>
 <translation id="3838486795898716504">Daugiau <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Pridėkite išsaugotų slaptažodžių prie „Google“ slaptažodžių tvarkyklės</translation>
 <translation id="383891835335927981">Nėra svetainių, kurių turinys priartintas arba atitolintas</translation>
 <translation id="3839509547554145593">Įgalinti slinkimo pele paspartinimą</translation>
 <translation id="3839516600093027468">Niekada neleisti <ph name="HOST" /> peržiūrėti iškarpinės</translation>
@@ -3871,6 +3870,7 @@
 <translation id="4340125850502689798">Neteisingas naudotojo vardas</translation>
 <translation id="4340515029017875942"><ph name="ORIGIN" /> nori užmegzti ryšį su programa „<ph name="EXTENSION_NAME" />“</translation>
 <translation id="4340799661701629185">Neleisti svetainėms siųsti pranešimų</translation>
+<translation id="4341280816303414009">Ekranas gali būti įrašomas</translation>
 <translation id="4341577178275615435">Jei norite įjungti arba išjungti „Caret Browsing“, naudokite spartųjį klavišą F7</translation>
 <translation id="4341905082470253054">Tikrinama TPM būsena...</translation>
 <translation id="434198521554309404">Spartu. Saugu. Paprasta.</translation>
@@ -5695,6 +5695,7 @@
 <translation id="5979421442488174909">Versti į <ph name="LANGUAGE" /></translation>
 <translation id="5979469435153841984">Kad pažymėtumėte puslapius, spustelėkite žvaigždutę adreso juostoje</translation>
 <translation id="5981362776161841923">Kad būtų leidžiamas plėtinys, toliau pakeiskite numatytuosius nustatymus.</translation>
+<translation id="5982578203375898585">Rodyti atsisiuntimus, kai jie bus baigti</translation>
 <translation id="5984222099446776634">Neseniai lankyta</translation>
 <translation id="5985458664595100876">Netinkamas URL formatas. Palaikomi formatai yra „\\server\share“ ir „smb://server/share“.</translation>
 <translation id="598810097218913399">Pašalinti priskyrimą</translation>
diff --git a/chrome/app/resources/generated_resources_lv.xtb b/chrome/app/resources/generated_resources_lv.xtb
index 0762bd1..04b55c72 100644
--- a/chrome/app/resources/generated_resources_lv.xtb
+++ b/chrome/app/resources/generated_resources_lv.xtb
@@ -118,6 +118,7 @@
 <translation id="1090541560108055381">Pirms izveidojat savienojumu pārī, pārliecinieties, ka šis kods abās ierīcēs ir vienāds.</translation>
 <translation id="1091767800771861448">Nospiediet ESCAPE, lai izlaistu (tikai neoficiāli būvējumi).</translation>
 <translation id="1093457606523402488">Redzamie tīkli:</translation>
+<translation id="1094219634413363886">Ja šajā pārvaldītajā ierīcē tiks sākta ierakstīšana, jums tiks parādīts paziņojums.</translation>
 <translation id="1095761715416917775">Parūpējieties, lai vienmēr varētu piekļūt sinhronizētajiem datiem</translation>
 <translation id="1095879482467973146">Google paroļu pārvaldnieks tīmeklī</translation>
 <translation id="109647177154844434">Atinstalējot Parallels Desktop, tiks izdzēsts jūsu Windows sistēmas attēls. Tostarp tiks izdzēstas tajā iekļautās lietojumprogrammas, iestatījumi un dati. Vai tiešām vēlaties turpināt?</translation>
@@ -390,7 +391,6 @@
 <translation id="1333965224356556482">Neļaut vietnēm piekļūt jūsu atrašanās vietas informācijai</translation>
 <translation id="1335282218035876586">Jūsu Chromebook datorā vairs netiek saņemti drošības un programmatūras atjauninājumi. Izmantojiet jaunu Chromebook datoru, lai pilnvērtīgi izmantotu visas iespējas.</translation>
 <translation id="133535873114485416">Vēlamā ievade</translation>
-<translation id="1335437153193710305">Varat izvēlēties profilu, no kura vēlaties skatīt paroles.</translation>
 <translation id="1335929031622236846">Ierīces reģistrēšana</translation>
 <translation id="1336902454946927954">Jūsu drošības atslēga ir bloķēta, jo nevarēja atpazīt jūsu pirksta nospiedumu. Lai atbloķētu drošības atslēgu, ievadiet PIN.</translation>
 <translation id="1338631221631423366">Notiek savienošana pārī...</translation>
@@ -3315,7 +3315,6 @@
 <translation id="383669374481694771">Šī ir vispārīga informācija par šo ierīci un tās lietojumu (piemēram, par akumulatora uzlādes līmeni, sistēmas darbībām, lietotņu izmantojumu un kļūdām). Dati tiks izmantoti, lai uzlabotu Android darbību. Noteiktu apkopotu informāciju izmantos arī Google lietotņu izstrādātāji un partneri, piemēram, Android izstrādātāji, lai uzlabotu lietotnes un produktus.</translation>
 <translation id="3838085852053358637">Neizdevās ielādēt paplašinājumu</translation>
 <translation id="3838486795898716504">Citas lapas ar nosaukumu <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Pievienojiet saglabātās paroles Google paroļu pārvaldniekam.</translation>
 <translation id="383891835335927981">Nevienā vietnē nav veikta tālummaiņa.</translation>
 <translation id="3839509547554145593">Iespējot peles ritināšanas paātrinātāju</translation>
 <translation id="3839516600093027468">Vienmēr bloķēt starpliktuves satura rādīšanu vietnei <ph name="HOST" /></translation>
@@ -3855,6 +3854,7 @@
 <translation id="4340125850502689798">Lietotājvārds nav derīgs</translation>
 <translation id="4340515029017875942"><ph name="ORIGIN" /> vēlas sazināties ar lietotni “<ph name="EXTENSION_NAME" />”</translation>
 <translation id="4340799661701629185">Neļaut vietnēm sūtīt paziņojumus</translation>
+<translation id="4341280816303414009">Jūsu ekrāns var tikt ierakstīts</translation>
 <translation id="4341577178275615435">Lai ieslēgtu vai izslēgtu taustiņpārlūkošanu, izmantojiet īsinājumtaustiņu F7.</translation>
 <translation id="4341905082470253054">Notiek TPM statusa pārbaude...</translation>
 <translation id="434198521554309404">Ātra. Droša. Ērta.</translation>
@@ -5674,6 +5674,7 @@
 <translation id="5979421442488174909">&amp;Tulkot <ph name="LANGUAGE" /> valodā</translation>
 <translation id="5979469435153841984">Lai saglabātu lapu kā grāmatzīmi, noklikšķiniet uz zvaigznītes adreses joslā.</translation>
 <translation id="5981362776161841923">Lai atļautu paplašinājumu, tālāk mainiet noklusējuma iestatījumu.</translation>
+<translation id="5982578203375898585">Rādīt lejupielādes, kad tās ir pabeigtas</translation>
 <translation id="5984222099446776634">Nesen apmeklētie</translation>
 <translation id="5985458664595100876">Nederīgs vietrāža URL formāts. Atbalstītie formāti ir \\server\share un smb://server/share.</translation>
 <translation id="598810097218913399">Atcelt piešķiršanu</translation>
diff --git a/chrome/app/resources/generated_resources_mk.xtb b/chrome/app/resources/generated_resources_mk.xtb
index 70004e6a..562de158 100644
--- a/chrome/app/resources/generated_resources_mk.xtb
+++ b/chrome/app/resources/generated_resources_mk.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">За Linux, се препорачува најмалку <ph name="INSTALL_SIZE" /> слободен простор. За да го зголемите слободниот простор, избришете датотеки од уредот.</translation>
 <translation id="1038643060055067718">Редови:</translation>
 <translation id="1039337018183941703">Невалидна или оштетена датотека</translation>
+<translation id="1040761927998636252">Неименуван обележувач за <ph name="URL" /></translation>
 <translation id="1041175011127912238">Страницава не реагира</translation>
 <translation id="1041263367839475438">Достапни уреди</translation>
 <translation id="1042174272890264476">Вашиот компјутер е со вградена <ph name="SHORT_PRODUCT_NAME" /> RLZ библиотека. RLZ доделува неуникатна, не-лична идентификувачка картичка за мерење на пребарувањата и користење на <ph name="SHORT_PRODUCT_NAME" /> поттикнато од одредена промотивна кампања. Овие ознаки понекогаш се појавуваат во прашалници за пребарување на Google во <ph name="PRODUCT_NAME" />.</translation>
@@ -390,7 +391,6 @@
 <translation id="1333965224356556482">Не им дозволувај на сајтовите да ја гледаат локацијата</translation>
 <translation id="1335282218035876586">Вашиот Chromebook веќе не прима безбедносни и софтверски ажурирања. Надградете го вашиот Chromebook за најдобро доживување.</translation>
 <translation id="133535873114485416">Претпочитан влез</translation>
-<translation id="1335437153193710305">Може да го изберете профилот од којшто сакате да ги гледате лозинките</translation>
 <translation id="1335929031622236846">Регистрирајте го уредот</translation>
 <translation id="1336902454946927954">Вашиот безбедносен клуч е заклучен бидејќи вашиот отпечаток не може да се препознае. За да го отклучите, внесете го вашиот PIN.</translation>
 <translation id="1338631221631423366">Се спарува…</translation>
@@ -3328,7 +3328,6 @@
 <translation id="383669374481694771">Ова се општи податоци за уредов и неговото користење (како нивото на батеријата, активноста на системот и апликациите и грешките). Податоците ќе се користат за подобрување на Android, а некои збирни податоци ќе им помогнат на апликациите и партнерите на Google, како што се програмерите на Android, да ги подобрат нивните апликации и производи.</translation>
 <translation id="3838085852053358637">Не може да се вчита екстензијата</translation>
 <translation id="3838486795898716504">Повеќе <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Додајте ги зачуваните лозинки во Google Password Manager</translation>
 <translation id="383891835335927981">Ниеден сајт не е зумиран ниту одзумиран</translation>
 <translation id="3839509547554145593">Овозможи забрзување на лизгањето на глувчето</translation>
 <translation id="3839516600093027468">Секогаш блокирај го пристапот на <ph name="HOST" /> за гледање на привремената меморија</translation>
diff --git a/chrome/app/resources/generated_resources_ml.xtb b/chrome/app/resources/generated_resources_ml.xtb
index 397b3c8..7328b0a 100644
--- a/chrome/app/resources/generated_resources_ml.xtb
+++ b/chrome/app/resources/generated_resources_ml.xtb
@@ -118,6 +118,7 @@
 <translation id="1090541560108055381">ജോടിയാക്കുന്നതിന് മുമ്പ്, ഈ കോഡ് രണ്ട് ഉപകരണങ്ങളിലും ഒന്ന് തന്നെയാണെന്ന് ഉറപ്പാക്കുക</translation>
 <translation id="1091767800771861448">ഒഴിവാക്കുന്നതിനായി ESCAPE അമർത്തുക (അനൗദ്യോഗിക നിർമ്മിതകൾക്ക് മാത്രം).</translation>
 <translation id="1093457606523402488">ദൃശ്യമാകുന്ന നെറ്റ്‌വർക്കുകൾ:</translation>
+<translation id="1094219634413363886">മാനേജ് ചെയ്യപ്പെടുന്ന ഈ ഉപകരണത്തിൽ റെക്കോർഡിംഗ് ആരംഭിച്ചാൽ ഒരു അറിയിപ്പ് നിങ്ങൾക്ക് കാണാം</translation>
 <translation id="1095761715416917775">സമന്വയിപ്പിക്കുന്ന ഡാറ്റ നിങ്ങൾക്ക് എല്ലായ്‌പ്പോഴും ആക്‌സസ് ചെയ്യാനാകുമെന്ന് ഉറപ്പാക്കുക</translation>
 <translation id="1095879482467973146">വെബിലെ Google Password Manager</translation>
 <translation id="109647177154844434">Parallels Desktop അൺഇൻസ്‌റ്റാൾ ചെയ്യുന്നത്, നിങ്ങളുടെ Windows ചിത്രം ഇല്ലാതാക്കും. ഇതിന്റെ ആപ്പുകളും ക്രമീകരണവും ഡാറ്റയും ഇതിൽ ഉൾപ്പെടുന്നു. തുടരണമെന്ന് തീർച്ചയാണോ?</translation>
@@ -390,7 +391,6 @@
 <translation id="1333965224356556482">നിങ്ങളുടെ ലൊക്കേഷൻ കാണാൻ സൈറ്റുകളെ അനുവദിക്കരുത്</translation>
 <translation id="1335282218035876586">നിങ്ങളുടെ Chromebook-ന് ഇനി സുരക്ഷാ, സോഫ്‌റ്റ്‌വെയർ അപ്‌ഡേറ്റുകൾ ലഭിക്കില്ല. മികച്ച അനുഭവത്തിനായി നിങ്ങളുടെ Chromebook അപ്‌ഗ്രേഡ് ചെയ്യുക.</translation>
 <translation id="133535873114485416">തിരഞ്ഞെടുത്ത ഇൻപുട്ട്</translation>
-<translation id="1335437153193710305">നിങ്ങൾക്ക് പാസ്‌വേഡുകൾ കാണാൻ താൽപ്പര്യമുള്ള പ്രൊഫൈൽ തിരഞ്ഞെടുക്കാം</translation>
 <translation id="1335929031622236846">നിങ്ങളുടെ ഉപകരണം എൻറോൾ ചെയ്യുക</translation>
 <translation id="1336902454946927954">ഫിംഗർപ്രിന്റ് തിരിച്ചറിയാനാകാത്തതിനാൽ നിങ്ങളുടെ സുരക്ഷാ കീ ലോക്ക് ചെയ്‌തിരിക്കുന്നു. ഇത് അൺലോക്ക് ചെയ്യാൻ, പിൻ നൽകുക.</translation>
 <translation id="1338631221631423366">ജോടിയാക്കുന്നു...</translation>
@@ -3124,6 +3124,7 @@
 <translation id="369489984217678710">പാസ്‍വേഡുകളും മറ്റ് സൈൻ ഇൻ ഡാറ്റയും</translation>
 <translation id="369522892592566391">{NUM_FILES,plural, =0{സുരക്ഷാപരിശോധനകൾ പൂർത്തിയാക്കി. നിങ്ങളുടെ ഡാറ്റ അപ്‌ലോഡ് ചെയ്യപ്പെടും.}=1{സുരക്ഷാപരിശോധനകൾ പൂർത്തിയാക്കി. നിങ്ങളുടെ ഫയൽ അപ്‌ലോഡ് ചെയ്യപ്പെടും.}other{സുരക്ഷാപരിശോധനകൾ പൂർത്തിയാക്കി. നിങ്ങളുടെ ഫയലുകൾ അപ്‌ലോഡ് ചെയ്യപ്പെടും.}}</translation>
 <translation id="3696817060563289264">ടെക്‌സ്റ്റ് തിരിച്ചറിയൽ ഫയലുകൾ ഡൗൺലോഡ് ചെയ്തു</translation>
+<translation id="3697716475445175867">അവസാനം തുറന്നത്</translation>
 <translation id="3698471669415859717">അവലോകനം പൂർത്തിയായി</translation>
 <translation id="3698825735945432002">ഫിൽട്ടർ തരം</translation>
 <translation id="3699624789011381381">ഇമെയില്‍ വിലാസങ്ങള്‍</translation>
@@ -3312,7 +3313,6 @@
 <translation id="383669374481694771">നിങ്ങളുടെ ഉപകരണത്തെ കുറിച്ചും നിങ്ങൾ എങ്ങനെയത് ഉപയോഗിച്ചു എന്നതിനെ കുറിച്ചുമുള്ള പൊതുവായ വിവരങ്ങൾ (ബാറ്ററി നില, സിസ്റ്റം ആക്‌റ്റിവിറ്റി, ആപ്പ് ആക്‌റ്റിവിറ്റി, പിശകുകൾ എന്നിവ പോലെ) ആണിത്. Android മെച്ചപ്പെടുത്താൻ ഈ ഡാറ്റ ഉപയോഗിക്കപ്പെടും, സംഗ്രഹിച്ച ചില വിവരങ്ങൾ, Google ആപ്പുകളെയും Android ഡെവലപ്പർമാർ പോലുള്ള പങ്കാളികളെയും അവരുടെ ആപ്പുകളും ഉൽപ്പന്നങ്ങളും മെച്ചപ്പെടുത്താനും സഹായിക്കും.</translation>
 <translation id="3838085852053358637">വിപുലീകരണം ലോഡ് ചെയ്യാനായില്ല</translation>
 <translation id="3838486795898716504">കൂടുതൽ <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">സംരക്ഷിച്ച പാസ്‌വേഡുകൾ Google Password Manager-ൽ ചേർക്കുക</translation>
 <translation id="383891835335927981">സൈറ്റുകളൊന്നും സൂം ഇൻ അല്ലെങ്കിൽ സൂം ഔട്ട് ചെയ്‌തിട്ടില്ല</translation>
 <translation id="3839509547554145593">മൗസ് സ്‍ക്രോള്‍ ആക്‌സിലറേഷൻ പ്രവർത്തനക്ഷമമാക്കുക</translation>
 <translation id="3839516600093027468">ക്ലിപ്പ്‌ബോർഡ് കാണുന്നതിൽ നിന്ന് എല്ലായ്പ്പോഴും <ph name="HOST" /> എന്നതിനെ ബ്ലോക്ക് ചെയ്യുക</translation>
@@ -3851,6 +3851,7 @@
 <translation id="4340125850502689798">ഉപയോക്തൃനാമം അസാധുവാണ്</translation>
 <translation id="4340515029017875942">"<ph name="EXTENSION_NAME" />" ആപ്പ് ഉപയോഗിച്ച് <ph name="ORIGIN" /> എന്നത് ആശയവിനിമയം നടത്താൻ താൽപ്പര്യപ്പെടുന്നു</translation>
 <translation id="4340799661701629185">അറിയിപ്പുകൾ അയയ്ക്കാൻ സൈറ്റുകളെ അനുവദിക്കരുത്</translation>
+<translation id="4341280816303414009">നിങ്ങളുടെ സ്ക്രീൻ റെക്കോർഡ് ചെയ്‌തേക്കാം</translation>
 <translation id="4341577178275615435">കാരറ്റ് ബ്രൗസ് ചെയ്യൽ ഓണാക്കാനോ ഓഫാക്കാനോ, F7 എന്ന കുറുക്കുവഴി ഉപയോഗിക്കുക</translation>
 <translation id="4341905082470253054">TPM നില പരിശോധിക്കുന്നു...</translation>
 <translation id="434198521554309404">വേഗമേറിയത്. സുരക്ഷിതം. ആയാസരഹിതം.</translation>
@@ -5674,6 +5675,7 @@
 <translation id="5979421442488174909">&amp; <ph name="LANGUAGE" /> ലേക്ക് വിവർത്തനം ചെയ്യുക</translation>
 <translation id="5979469435153841984">പേജുകൾ ബുക്ക്‌മാർക്ക് ചെയ്യുന്നതിന്, വിലാസ ബാറിലെ നക്ഷത്ര ചിഹ്നത്തിൽ ക്ലിക്ക് ചെയ്യുക</translation>
 <translation id="5981362776161841923">ഒരു വിപുലീകരണം അനുവദിക്കാൻ, ചുവടെയുള്ള നിങ്ങളുടെ ഡിഫോൾട്ട് ക്രമീകരണം മാറ്റുക.</translation>
+<translation id="5982578203375898585">ഡൗൺലോഡ് ചെയ്യുന്നത് പൂർത്തിയായാൽ അവ കാണിക്കുക</translation>
 <translation id="5984222099446776634">സമീപകാലത്ത് സന്ദർശിച്ചത്</translation>
 <translation id="5985458664595100876">അസാധുവായ URL ഫോര്‍മാറ്റ്. \\server\share, smb://server/share എന്നിവയാണ്‌ പിന്തുണയ്‌ക്കുന്ന ഫോര്‍മാറ്റുകള്‍.</translation>
 <translation id="598810097218913399">അസൈൻമെന്റ് നീക്കം ചെയ്യുക</translation>
@@ -6351,6 +6353,7 @@
 <translation id="6596816719288285829">IP വിലാസം</translation>
 <translation id="6597017209724497268">സാമ്പിളുകൾ</translation>
 <translation id="6597331566371766302">നിങ്ങളുടെ അഡ്‌മിൻ ഇനിപ്പറയുന്ന വിപുലീകരണങ്ങൾ ബ്ലോക്ക് ചെയ്‌തു:</translation>
+<translation id="659894938503552850">ഏറ്റവും പുതിയത്</translation>
 <translation id="6601262427770154296">ഉപയോക്തൃ നിഘണ്ടുക്കൾ മാനേജ് ചെയ്യുക</translation>
 <translation id="6601612474695404578">ചില സൈറ്റുകൾ അവരുടെ പേജുകൾ ലോഡ് ചെയ്യാൻ മൂന്നാം കക്ഷി കുക്കികൾ ഉപയോഗിക്കുന്നു. സൈറ്റ് പ്രവർത്തിക്കുന്നില്ലെങ്കിൽ നിങ്ങൾക്ക് കുക്കികൾ അനുവദിച്ച് നോക്കാവുന്നതാണ്.</translation>
 <translation id="6602937173026466876">നിങ്ങളുടെ പ്രിന്ററുകൾ ആക്‌സസ് ചെയ്യുക</translation>
@@ -8133,6 +8136,7 @@
 <translation id="8161293209665121583">വെബ് പേജുകൾക്കുള്ള വായനാ മോഡ്</translation>
 <translation id="8161604891089629425">ഔട്ട്‌ലൈൻ ഫോണ്ട്</translation>
 <translation id="8162984717805647492">{NUM_TABS,plural, =1{ടാബ് പുതിയ വിൻഡോയിലേക്ക് നീക്കുക}other{ടാബുകൾ പുതിയ വിൻഡോയിലേക്ക് നീക്കുക}}</translation>
+<translation id="8163708146810922598">ഏറ്റവും പഴയത്</translation>
 <translation id="8165997195302308593">Crostini പോർട്ട് ഫോർവേഡിംഗ്</translation>
 <translation id="816704878106051517">{COUNT,plural, =1{ഒരു ഫോൺ നമ്പർ}other{# ഫോൺ നമ്പറുകൾ}}</translation>
 <translation id="8168071266284693455">നിങ്ങളുടെ എല്ലാ ഉപകരണങ്ങളിലും ബുക്ക്‌മാർക്കുകളും പാസ്‌വേഡുകളും ചരിത്രവും മറ്റും സമന്വയിപ്പിക്കും</translation>
@@ -8647,6 +8651,7 @@
 <translation id="8637688295594795546">സിസ്റ്റം അപ്ഡേറ്റ് ലഭ്യമാണ്. ഡൗണ്‍ലോഡ് ചെയ്യുന്നതിന് തയ്യാറെടുക്കുന്നു...</translation>
 <translation id="8639047128869322042">ദോഷകരമായ സോഫ്‌റ്റ്‌വെയർ ഉണ്ടോയെന്ന് പരിശോധിക്കുന്നു...</translation>
 <translation id="8639635302972078117">ഉപയോഗവും പ്രശ്‌നനിർണ്ണയവുമായി ബന്ധപ്പെട്ട ഡാറ്റ അയയ്ക്കുക. പ്രശ്‌നനിർണ്ണയം, ഉപകരണം, ആപ്പ് ഉപയോഗം എന്നിവയുമായി ബന്ധപ്പെട്ട ഡാറ്റ, ഈ ഉപകരണം നിലവിൽ സ്വയമേവ Google-ന് അയയ്ക്കുന്നുണ്ട്. നിങ്ങളുടെ കുട്ടിയെ തിരിച്ചറിയാൻ ഇത് ഉപയോഗിക്കില്ല, സിസ്‌റ്റം, ആപ്പ് സ്ഥിരത, മറ്റ് മെച്ചപ്പെടുത്തലുകൾ എന്നിവയ്ക്ക് സഹായിക്കുകയും ചെയ്യും. ചില സംഗ്രഹ ഡാറ്റ, Google ആപ്പുകളെയും Android ഡെവലപ്പർമാരെപ്പോലുള്ള പങ്കാളികളെയും സഹായിക്കുകയും ചെയ്യും. നിങ്ങളുടെ കുട്ടിയുടെ അധിക വെബ്, ആപ്പ് ആക്റ്റിവിറ്റി ക്രമീകരണം ഓണാക്കിയിട്ടുണ്ടെങ്കിൽ, ഈ ഡാറ്റ അവരുടെ Google അക്കൗണ്ടിൽ സംരക്ഷിക്കപ്പെട്ടേക്കാം.</translation>
+<translation id="8640575194957831802">അവസാനം തുറന്നത്</translation>
 <translation id="8642900771896232685">2 സെക്കൻഡ്</translation>
 <translation id="8642947597466641025">പാഠത്തെ വലുതാക്കുക</translation>
 <translation id="8643403533759285912">ഗ്രൂപ്പ് ഇല്ലാതാക്കുക</translation>
diff --git a/chrome/app/resources/generated_resources_mn.xtb b/chrome/app/resources/generated_resources_mn.xtb
index 43bb5577..f3e91e6 100644
--- a/chrome/app/resources/generated_resources_mn.xtb
+++ b/chrome/app/resources/generated_resources_mn.xtb
@@ -390,7 +390,6 @@
 <translation id="1333965224356556482">Сайтуудад таны байршлыг харахыг бүү зөвшөөр</translation>
 <translation id="1335282218035876586">Таны Chromebook цаашид аюулгүй байдлын болон программ хангамжийн шинэчлэлтүүд хүлээн авахаа больсон. Хамгийн сайн хэрэглээг авах бол Chromebook-ээ сайжруулна уу.</translation>
 <translation id="133535873114485416">Давуу эрхтэй оролт</translation>
-<translation id="1335437153193710305">Та нууц үгнүүдийг нь харахыг хүсэж буй профайлаа сонгож болно</translation>
 <translation id="1335929031622236846">Төхөөрөмжөө бүртгүүлнэ үү</translation>
 <translation id="1336902454946927954">Таны хурууны хээг таньж чадаагүй тул таны аюулгүй байдлын түлхүүрийг түгжсэн. Түгжээг нь тайлахын тулд ПИН-ээ оруулна уу.</translation>
 <translation id="1338631221631423366">Хослуулж байна...</translation>
@@ -3324,7 +3323,6 @@
 <translation id="383669374481694771">Энэ нь уг төхөөрөмжийн болон түүнийг хэрхэн ашигладаг тухай (батарейн түвшин, систем болон аппын үйл ажиллагаа, алдаа зэрэг) ерөнхий мэдээлэл юм. Өгөгдлийг Android-г сайжруулах зорилгоор ашиглах бөгөөд хуримтлуулсан зарим мэдээлэл нь Google-н аппууд болон Android хөгжүүлэгч зэрэг түншүүдэд апп болон бүтээгдэхүүнээ сайжруулахад нь мөн тусална.</translation>
 <translation id="3838085852053358637">Өргөтгөлийг ачаалж чадсангүй</translation>
 <translation id="3838486795898716504">Илүү их <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Хадгалсан нууц үгнүүдийг Google Password Manager-т нэмэх</translation>
 <translation id="383891835335927981">Томруулж, жижигрүүлсэн сайт алга</translation>
 <translation id="3839509547554145593">Хулганын гүйлгэлтийн хурдасгуурыг идэвхжүүлэх</translation>
 <translation id="3839516600093027468"><ph name="HOST" />-г түр санах ой харахыг тогтмол хориглох</translation>
diff --git a/chrome/app/resources/generated_resources_mr.xtb b/chrome/app/resources/generated_resources_mr.xtb
index d91f8a4e..ae38c94 100644
--- a/chrome/app/resources/generated_resources_mr.xtb
+++ b/chrome/app/resources/generated_resources_mr.xtb
@@ -390,7 +390,6 @@
 <translation id="1333965224356556482">साइटना तुमचे स्थान पाहाण्याची अनुमती देऊ नका</translation>
 <translation id="1335282218035876586">तुमच्या Chromebook ला आता सुरक्षा आणि सॉफ्टवेअर अपडेट मिळत नाहीत. सर्वोत्तम अनुभवासाठी तुमचे Chromebook अपग्रेड करा.</translation>
 <translation id="133535873114485416">प्राधान्य असलेले इनपुट</translation>
-<translation id="1335437153193710305">तुम्हाला ज्यामधून पासवर्ड पाहायचे आहेत ती प्रोफाइल तुम्ही निवडू शकता</translation>
 <translation id="1335929031622236846">तुमच्या डिव्हाइसची नोंदणी करा</translation>
 <translation id="1336902454946927954">तुमची फिंगरप्रिंट ओळखता न आल्यामुळे तुमची सिक्युरिटी की लॉक केली गेली आहे. ती अनलॉक करण्यासाठी, तुमचा पिन एंटर करा.</translation>
 <translation id="1338631221631423366">पेअर करत आहे...</translation>
@@ -3327,7 +3326,6 @@
 <translation id="383669374481694771">हे डिव्हाइस आणि ते कसे वापरले जाते याबद्दल ही सर्वसाधारण माहिती आहे (जसे की, बॅटरी पातळी, सिस्टम आणि ॲप ॲक्टिव्हिटी व एरर). डेटा Android मध्ये सुधारणा करण्यासाठी वापरला जाईल आणि काही एकत्रित केलेली माहिती Google ॲप्स आणि Android डेव्हलपरसारख्या भागीदारांनादेखील त्यांची ॲप्स आणि उत्पादने आणखी चांगली बनवण्यात मदत करेल.</translation>
 <translation id="3838085852053358637">एक्स्टेंशन लोड करण्‍यात अयशस्वी झाले</translation>
 <translation id="3838486795898716504">अधिक <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">सेव्ह केलेले पासवर्ड Google Password Manager मध्ये जोडा</translation>
 <translation id="383891835335927981">कोणत्याही साइटसाठी झूम वाढविले किंवा कमी केलेले नाही</translation>
 <translation id="3839509547554145593">माउस स्क्रोल अ‍ॅक्सिलरेशन सुरू करा</translation>
 <translation id="3839516600093027468"><ph name="HOST" /> ला क्लिपबोर्ड पाहण्यापासून नेहमी ब्लॉक करा</translation>
diff --git a/chrome/app/resources/generated_resources_ms.xtb b/chrome/app/resources/generated_resources_ms.xtb
index b147ef0..96993986 100644
--- a/chrome/app/resources/generated_resources_ms.xtb
+++ b/chrome/app/resources/generated_resources_ms.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">Jangan benarkan laman melihat lokasi anda</translation>
 <translation id="1335282218035876586">Chromebook anda tidak menerima kemaskinian keselamatan dan perisian lagi. Tingkatkan Chromebook anda untuk mendapatkan pengalaman terbaik.</translation>
 <translation id="133535873114485416">Input pilihan</translation>
-<translation id="1335437153193710305">Anda boleh memilih profil yang anda mahukan untuk melihat kata laluan tersebut</translation>
 <translation id="1335929031622236846">Daftarkan peranti anda</translation>
 <translation id="1336902454946927954">Kunci keselamatan anda dikunci kerana cap jari anda tidak dapat dikenal pasti. Untuk membuka kunci keselamatan itu, masukkan PIN anda.</translation>
 <translation id="1338631221631423366">Menggandingkan...</translation>
@@ -3330,7 +3329,6 @@
 <translation id="383669374481694771">Ini merupakan maklumat umum tentang peranti ini dan cara anda menggunakan peranti ini (seperti aras bateri, aktiviti sistem dan apl serta ralat). Data ini akan digunakan untuk menambah baik Android dan sesetengah maklumat teragregat juga dapat membantu apl Google dan rakan kongsi, seperti pembangun Android, memperbaik apl dan produk mereka.</translation>
 <translation id="3838085852053358637">Gagal memuatkan sambungan</translation>
 <translation id="3838486795898716504">Lagi <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Tambahkan kata laluan yang disimpan pada Google Password Manager</translation>
 <translation id="383891835335927981">Tiada tapak yang telah dizum masuk atau keluar</translation>
 <translation id="3839509547554145593">Dayakan pemecutan penatalan tetikus</translation>
 <translation id="3839516600093027468">Sentiasa sekat <ph name="HOST" /> daripada melihat papan keratan</translation>
diff --git a/chrome/app/resources/generated_resources_my.xtb b/chrome/app/resources/generated_resources_my.xtb
index 26dc01d..0caabf6 100644
--- a/chrome/app/resources/generated_resources_my.xtb
+++ b/chrome/app/resources/generated_resources_my.xtb
@@ -390,7 +390,6 @@
 <translation id="1333965224356556482">သင့်တည်နေရာကိုကြည့်ရန် ဝဘ်ဆိုက်များကို ခွင့်မပြုပါနှင့်</translation>
 <translation id="1335282218035876586">သင့် Chromebook သည် လုံခြုံရေးနှင့် ဆော့ဖ်ဝဲအပ်ဒိတ်များ မရရှိတော့ပါ။ အကောင်းဆုံးအသုံးပြုမှုအတွက် သင့် Chromebook ကို အဆင့်မြှင့်ပါ။</translation>
 <translation id="133535873114485416">ဦးစားပေး စာရိုက်စနစ်</translation>
-<translation id="1335437153193710305">စကားဝှက်များကြည့်လိုသော ပရိုဖိုင်ကို ရွေးနိုင်သည်</translation>
 <translation id="1335929031622236846">သင့်စက်ကို စာရင်းသွင်းခြင်း</translation>
 <translation id="1336902454946927954">သင့်လက်ဗွေကို မသိသောကြောင့် သင်၏လုံခြုံရေးကီးကို လော့ခ်ချလိုက်သည်။ ၎င်းကိုဖွင့်ရန် သင့်ပင်နံပါတ် ထည့်ပါ။</translation>
 <translation id="1338631221631423366">တွဲချိတ်နေသည်...</translation>
@@ -3327,7 +3326,6 @@
 <translation id="383669374481694771">ဤသည်မှာ ဤစက်၏ ယေဘုယျအချက်အလက်နှင့် ၎င်းကို မည်သို့အသုံးပြုကြောင်း အချက်အလက်များဖြစ်သည် (ဥပမာ ဘက်ထရီပမာဏ၊ စနစ်နှင့် အက်ပ်လုပ်ဆောင်ချက်နှင့် အမှားအယွင်းများ)။ ဤဒေတာများကို Android ပိုမိုကောင်းမွန်လာစေရန်အတွက် အသုံးပြုသွားမည်ဖြစ်ပြီး အချို့သော စုစည်းထားသည့်အချက်အလက်များသည်လည်း Android ဆော့ဖ်ဝဲအင်ဂျင်နီယာကဲ့သို့သော Google အက်ပ်နှင့် ပါတနာများအား ၎င်းတို့၏ အက်ပ်နှင့် ထုတ်ကုန်များ ပိုမိုကောင်းမွန်လာစေရန် အတွက်လည်း အထောက်အကူဖြစ်စေပါသည်။</translation>
 <translation id="3838085852053358637">နောက်ဆက်တွဲကို ဖွင့်ရာတွင် မအောင်မြင်ပါ</translation>
 <translation id="3838486795898716504">နောက်ထပ် <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">‘Google စကားဝှက်မန်နေဂျာ’ တွင် သိမ်းထားသည့် စကားဝှက်များကို ထည့်သည်</translation>
 <translation id="383891835335927981">မည်သည့်ဝဘ်ဆိုက်ကိုမျှ ဇူးမ် ချဲ့ခြင်း သို့မဟုတ် ချုံ့ခြင်း ပြုလုပ်မထားပါ</translation>
 <translation id="3839509547554145593">မောက်စ်လှိမ့်သည့် အရှိန်မြှင့်စနစ် ဖွင့်ရန်</translation>
 <translation id="3839516600093027468">ကလစ်ဘုတ်အား ကြည့်ရှုခွင့်ကို <ph name="HOST" /> အတွက် အမြဲပိတ်ရန်</translation>
diff --git a/chrome/app/resources/generated_resources_ne.xtb b/chrome/app/resources/generated_resources_ne.xtb
index 68f12d6..b556909 100644
--- a/chrome/app/resources/generated_resources_ne.xtb
+++ b/chrome/app/resources/generated_resources_ne.xtb
@@ -116,6 +116,7 @@
 <translation id="1090541560108055381">कुनै डिभाइसमा कनेक्ट गर्नुअघि उक्त डिभाइसमा र यो डिभाइसमा उही कोड देखाइएको छ भन्ने कुरा सुनिश्चित गर्नुहोस्</translation>
 <translation id="1091767800771861448">(गैर-आधिकारिक बिल्डहरू मात्र) छोड्न ESCAPE थिच्नुहोस्।</translation>
 <translation id="1093457606523402488">दर्शनीय नेटवर्कहरू:</translation>
+<translation id="1094219634413363886">व्यवस्थापन गरिएको यो डिभाइसमा रेकर्ड गर्न थालिएको खण्डमा तपाईंलाई एउटा सूचना देखाइने छ</translation>
 <translation id="1095761715416917775">तपाईं आफूले सिंक गरेको डेटा जुनसुकै बेला प्रयोग गर्न तथा हेर्न सक्नुहुन्छ भन्ने कुरा सुनिश्चित गर्नुहोस्</translation>
 <translation id="1095879482467973146">वेबमा भएको Google पासवर्ड म्यानेजर</translation>
 <translation id="109647177154844434">Parallels Desktop अनइन्स्टल गर्नुले तपाईंको Windows इमेज मेटाउने छ। यसमा Windows का एप, सेटिङ र डेटा समावेश हुन्छन्। तपाईंले Parallels Desktop अनइन्स्टल गर्न खोज्नुभएकै हो?</translation>
@@ -386,7 +387,6 @@
 <translation id="1333965224356556482">साइटहरूलाई मेरो स्थानसम्बन्धी जानकारी हेर्ने अनुमति नदिइयोस्</translation>
 <translation id="1335282218035876586">तपाईंको Chromebook मा सुरक्षा तथा सफ्टवेयरसम्बन्धी अपडेटहरू प्राप्त हुन छाडेको छ। उत्कृष्ट सुविधा प्राप्त गर्न आफ्नो Chromebook अपग्रेड गर्नुहोस्।</translation>
 <translation id="133535873114485416">रुचाइएको इनपुट</translation>
-<translation id="1335437153193710305">तपाईं जुन प्रोफाइलका पासवर्ड हेर्न चाहनुहुन्छ उक्त प्रोफाइल छनौट गर्नुहोस्</translation>
 <translation id="1335929031622236846">आफ्नो यन्त्र दर्ता गर्नुहोस्</translation>
 <translation id="1336902454946927954">तपाईंको फिंगरप्रिन्ट पहिचान गर्न नसकिएकाले तपाईंको सुरक्षा साँचो लक गरिएको छ। यसलाई अनलक गर्न आफ्नो PIN प्रविष्टि गर्नुहोस्।</translation>
 <translation id="1338631221631423366">कनेक्ट गरिँदै छ...</translation>
@@ -3311,7 +3311,6 @@
 <translation id="383669374481694771">यो जानकारी यो डिभाइस र यसलाई प्रयोग गरिने तरिकासम्बन्धी सामान्य जानकारी (जस्तै ब्याट्रीको स्तर, प्रणाली तथा एपका गतिविधि र त्रुटिहरू) हो। यो डेटा Android डिभाइसमामा सुधार ल्याउनका लागि प्रयोग गरिने छ र केही समग्र जानकारीले Google का एप र Android का विकासकर्ताहरूलगायत यसका साझेदारहरूलाई आफ्ना एप र उत्पादनहरू अझ राम्रो बनाउन पनि मद्दत गर्ने छ।</translation>
 <translation id="3838085852053358637">विस्तार लोड गर्न सकिएन</translation>
 <translation id="3838486795898716504">थप <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">सेभ गरिएका पासवर्डहरू Google पासवर्ड म्यानेजरमा हाल्नुहोस्</translation>
 <translation id="383891835335927981">कुनै पनि साइटलाई जुम इन वा जुम आउट गरिएको छैन</translation>
 <translation id="3839509547554145593">माउस स्क्रोल हुने गति बढाउने सुविधा सक्षम पार्नुहोस्</translation>
 <translation id="3839516600093027468"><ph name="HOST" /> लाई क्लिपबोर्ड हेर्न सधैँ रोक लगाउनुहोस्</translation>
@@ -3850,6 +3849,7 @@
 <translation id="4340125850502689798">युजरनेम अवैध छ</translation>
 <translation id="4340515029017875942"><ph name="ORIGIN" /> एपलाई "<ph name="EXTENSION_NAME" />" सँग सञ्चार गर्न चाहन्छ</translation>
 <translation id="4340799661701629185">साइटहरूलाई सूचना देखाउने अनुमति नदिइयोस्</translation>
+<translation id="4341280816303414009">तपाईंको स्क्रिन रेकर्ड गरिन सक्छ</translation>
 <translation id="4341577178275615435">सर्टकट तरिकाले क्यारेट ब्राउजिङ अन वा अफ गर्न F7 थिच्नुहोस्</translation>
 <translation id="4341905082470253054">TPM को स्थिति जाँचिदै छ...</translation>
 <translation id="434198521554309404">छिटो। सुरक्षित। सजिलो।</translation>
@@ -5671,6 +5671,7 @@
 <translation id="5979421442488174909"><ph name="LANGUAGE" /> मा &amp;अनुवाद गर्नुहोस्</translation>
 <translation id="5979469435153841984">पृष्ठहरूलाई पुस्तक चिन्ह लगाउन ठेगाना पट्टीमा अवस्थित तारा आइकनमा क्लिक गर्नुहोस्</translation>
 <translation id="5981362776161841923">कुनै एक्स्टेन्सनलाई अनुमति दिन तल आफ्नो डिफल्ट सेटिङ बदल्नुहोस्।</translation>
+<translation id="5982578203375898585">डाउनलोड गर्ने कार्य पूरा भएपछि डाउनलोड गरिएका सामग्री देखाइऊन्</translation>
 <translation id="5984222099446776634">भर्खरै भ्रमण गरिएको</translation>
 <translation id="5985458664595100876">URL ढाँचा अमान्य छ। समर्थन गरिएका ढाँचाहरू \\server\share र smb://server/share हुन्।</translation>
 <translation id="598810097218913399">तोकिएको काम हटाउनुहोस्</translation>
diff --git a/chrome/app/resources/generated_resources_nl.xtb b/chrome/app/resources/generated_resources_nl.xtb
index 9c4a9635..5eead6b 100644
--- a/chrome/app/resources/generated_resources_nl.xtb
+++ b/chrome/app/resources/generated_resources_nl.xtb
@@ -118,6 +118,7 @@
 <translation id="1090541560108055381">Voordat je de apparaten koppelt, check je of deze code gelijk is op beide apparaten</translation>
 <translation id="1091767800771861448">Druk op ESCAPE om over te slaan (alleen voor niet-officiële builds).</translation>
 <translation id="1093457606523402488">Zichtbare netwerken:</translation>
+<translation id="1094219634413363886">Je ziet een melding als de opname start op dit beheerde apparaat</translation>
 <translation id="1095761715416917775">Zorg dat je altijd toegang hebt tot je gesynchroniseerde gegevens</translation>
 <translation id="1095879482467973146">Google Wachtwoordmanager op internet</translation>
 <translation id="109647177154844434">Als je Parallels Desktop verwijdert, wordt je Windows-image verwijderd. Bijbehorende apps, instellingen en gegevens worden ook verwijderd. Weet je zeker dat je wilt doorgaan?</translation>
@@ -388,7 +389,6 @@
 <translation id="1333965224356556482">Niet toestaan dat sites je locatie zien</translation>
 <translation id="1335282218035876586">Je Chromebook krijgt geen beveiligings- en software-updates meer. Upgrade je Chromebook voor de beste functionaliteit.</translation>
 <translation id="133535873114485416">Voorkeursinvoer</translation>
-<translation id="1335437153193710305">Je kunt kiezen voor welk profiel je de wachtwoorden wilt zien</translation>
 <translation id="1335929031622236846">Je apparaat inschrijven</translation>
 <translation id="1336902454946927954">Je beveiligingssleutel is vergrendeld omdat je vingerafdruk niet kan worden herkend. Geef je pincode op om de sleutel te ontgrendelen.</translation>
 <translation id="1338631221631423366">Koppelen...</translation>
@@ -3313,7 +3313,6 @@
 <translation id="383669374481694771">Dit is algemene informatie over dit apparaat en hoe je het gebruikt (zoals batterijniveau, systeem- en app-activiteit en fouten). De gegevens worden gebruikt om Android te verbeteren voor iedereen. Daarnaast helpen bepaalde verzamelde gegevens Google-apps en -partners, zoals Android-ontwikkelaars, bij de verbetering van hun apps en producten.</translation>
 <translation id="3838085852053358637">Kan extensie niet laden</translation>
 <translation id="3838486795898716504">Meer <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Opgeslagen wachtwoorden toevoegen aan Google Wachtwoordmanager</translation>
 <translation id="383891835335927981">Er zijn geen sites in- of uitgezoomd</translation>
 <translation id="3839509547554145593">Scrollversnelling voor muis aanzetten</translation>
 <translation id="3839516600093027468"><ph name="HOST" /> altijd blokkeren voor het klembord</translation>
@@ -3852,6 +3851,7 @@
 <translation id="4340125850502689798">Ongeldige gebruikersnaam</translation>
 <translation id="4340515029017875942"><ph name="ORIGIN" /> wil communiceren met de app '<ph name="EXTENSION_NAME" />'</translation>
 <translation id="4340799661701629185">Niet toestaan dat sites meldingen sturen</translation>
+<translation id="4341280816303414009">Je scherm wordt misschien opgenomen</translation>
 <translation id="4341577178275615435">Gebruik de sneltoets F7 om browsen met navigatietoetsen aan of uit te zetten</translation>
 <translation id="4341905082470253054">TPM-status checken...</translation>
 <translation id="434198521554309404">Snel, beveiligd, makkelijk.</translation>
@@ -5670,6 +5670,7 @@
 <translation id="5979421442488174909">&amp;Vertalen naar het <ph name="LANGUAGE" /></translation>
 <translation id="5979469435153841984">Als je een bookmark wilt instellen voor een pagina, klik je op de ster in de adresbalk</translation>
 <translation id="5981362776161841923">Als je een extensie wilt toestaan, wijzig je hieronder je standaardinstelling.</translation>
+<translation id="5982578203375898585">Downloads tonen als ze klaar zijn</translation>
 <translation id="5984222099446776634">Recent bezocht</translation>
 <translation id="5985458664595100876">Ongeldige URL-indeling. Ondersteunde formaten zijn \\server\share en smb://server/share.</translation>
 <translation id="598810097218913399">Toewijzing verwijderen</translation>
diff --git a/chrome/app/resources/generated_resources_no.xtb b/chrome/app/resources/generated_resources_no.xtb
index 023ec67..9fa1b7f 100644
--- a/chrome/app/resources/generated_resources_no.xtb
+++ b/chrome/app/resources/generated_resources_no.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">Ikke la nettsteder se posisjonen din</translation>
 <translation id="1335282218035876586">Chromebooken din får ikke sikkerhets- eller programvareoppdateringer lenger. Oppgrader Chromebooken for å få den beste opplevelsen.</translation>
 <translation id="133535873114485416">Foretrukket inndatametode</translation>
-<translation id="1335437153193710305">Du kan velge profilen du vil se passordene fra</translation>
 <translation id="1335929031622236846">Registrer enheten din</translation>
 <translation id="1336902454946927954">Sikkerhetsnøkkelen er låst fordi fingeravtrykket ikke ble gjenkjent. For å låse den opp, skriv inn PIN-koden.</translation>
 <translation id="1338631221631423366">Kobler sammen …</translation>
@@ -3325,7 +3324,6 @@
 <translation id="383669374481694771">Dette er generell informasjon om denne enheten og hvordan den brukes (for eksempel batterinivå, system- og appaktivitet og feil). Dataene brukes til å gjøre Android bedre, og noen aggregerte data hjelper også Google-apper og -partnere, for eksempel Android-utviklere, med å gjøre apper og produkter bedre.</translation>
 <translation id="3838085852053358637">Kunne ikke laste inn utvidelsen</translation>
 <translation id="3838486795898716504">Mer av <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Legg til lagrede passord i Google Passordlagring</translation>
 <translation id="383891835335927981">Det er ikke zoomet inn eller ut på noen nettsteder</translation>
 <translation id="3839509547554145593">Slå på rulleakselerering for musen</translation>
 <translation id="3839516600093027468">Blokkér alltid <ph name="HOST" /> fra å se utklippstavlen</translation>
diff --git a/chrome/app/resources/generated_resources_or.xtb b/chrome/app/resources/generated_resources_or.xtb
index c900acd0..be6cc9dc 100644
--- a/chrome/app/resources/generated_resources_or.xtb
+++ b/chrome/app/resources/generated_resources_or.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Linux ପାଇଁ ଅତିକମରେ <ph name="INSTALL_SIZE" />ର ସ୍ଥାନ ସୁପାରିଶ କରାଯାଇଛି। ଖାଲି ସ୍ଥାନ ବଢ଼ାଇବାକୁ, ଆପଣଙ୍କ ଡିଭାଇସରୁ ଫାଇଲଗୁଡ଼ିକ ଡିଲିଟ୍ କରନ୍ତୁ।</translation>
 <translation id="1038643060055067718">ଧାଡ଼ି:</translation>
 <translation id="1039337018183941703">ଅବୈଧ କିମ୍ବା ଖରାପ ଫାଇଲ୍</translation>
+<translation id="1040761927998636252"><ph name="URL" /> ପାଇଁ ବେନାମୀ ବୁକମାର୍କ</translation>
 <translation id="1041175011127912238">ଏହି ପୃଷ୍ଠାଟି କାମ କରୁନାହିଁ</translation>
 <translation id="1041263367839475438">ଉପଲବ୍ଧ ଥିବା ଡିଭାଇସ୍‍ଗୁଡ଼ିକ</translation>
 <translation id="1042174272890264476">ଆପଣଙ୍କ କମ୍ପ୍ୟୁଟର୍‌ରେ ମଧ୍ୟ ପୂର୍ବରୁ<ph name="SHORT_PRODUCT_NAME" />ର RLZ ଲାଇବ୍ରେରୀ ଥାଏ। ଏକ ନିର୍ଦ୍ଧିଷ୍ଟ ପ୍ରଚାର ଅଭିଯାନରେ ବ୍ୟବହାର ହୋ‍ଇଥିବା ସନ୍ଧାନ ଏବଂ <ph name="SHORT_PRODUCT_NAME" />ର ବ୍ୟବହାର ମାପିବାକୁ RLZ ଏକ ସାଧାରଣ, ସାର୍ବଜନିକ ଚିହ୍ନିପାରିବା ପରି ଟାଗ୍‌ ନିରୂପଣ କରେ। Google ସର୍ଚ୍ଚ କ୍ୱେରୀର <ph name="PRODUCT_NAME" />ରେ ଏହି ଲେବଲ୍‌ଗୁଡ଼ିକ ବେଳେବେଳେ ଦେଖାଯାଏ।</translation>
@@ -388,7 +389,6 @@
 <translation id="1333965224356556482">ଆପଣଙ୍କ ଲୋକେସନ୍ ଦେଖିବାକୁ ସାଇଟଗୁଡ଼ିକୁ ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ</translation>
 <translation id="1335282218035876586">ଆପଣଙ୍କ Chromebook ଆଉ ସୁରକ୍ଷା ଏବଂ ସଫ୍ଟୱେର ଅପଡେଟଗୁଡ଼ିକୁ ପାଉନାହିଁ। ସର୍ବୋତ୍ତମ ଅନୁଭୂତି ପାଇଁ ଆପଣଙ୍କ Chromebookକୁ ଅପଗ୍ରେଡ କରନ୍ତୁ।</translation>
 <translation id="133535873114485416">ପସନ୍ଦ କରାଯାଇଥିବା ଇନ୍‌ପୁଟ୍</translation>
-<translation id="1335437153193710305">ଆପଣ ଯେଉଁ ପ୍ରୋଫାଇଲରୁ ପାସୱାର୍ଡ ଦେଖିବାକୁ ଚାହାଁନ୍ତି ତାହା ବାଛିପାରିବେ</translation>
 <translation id="1335929031622236846">ଆପଣଙ୍କ ଡିଭାଇସ୍ ପଞ୍ଜିକରଣ କରନ୍ତୁ</translation>
 <translation id="1336902454946927954">ଆପଣଙ୍କର ଟିପଚିହ୍ନ ଚିହ୍ନଟ କରାଯାଇ ପାରିନଥିବାରୁ ଆପଣଙ୍କର ସୁରକ୍ଷା କୀ'କୁ ଲକ୍ କରାଯାଇଛି। ଏହାକୁ ଅନଲକ୍ କରିବା ପାଇଁ ଆପଣଙ୍କର PIN ଲେଖନ୍ତୁ।</translation>
 <translation id="1338631221631423366">ପେୟାର କରାଯାଉଛି...</translation>
@@ -3310,7 +3310,6 @@
 <translation id="383669374481694771">ଏହି ଡିଭାଇସ୍ ଓ ଏହାକୁ କିପରି ବ୍ୟବହାର କରାଯାଇଛି (ଯେପରି ବ୍ୟାଟେରୀ ସ୍ତର, ସିଷ୍ଟମ୍ ଓ ଆପ୍ କାର୍ଯ୍ୟକଳାପ ଏବଂ ତ୍ରୁଟିଗୁଡ଼ିକ) ସେ ବିଷୟରେ ଏହା ସାଧାରଣ ସୂଚନା ଅଟେ। Androidକୁ ଉନ୍ନତ କରିବା ପାଇଁ ଏହି ଡାଟାକୁ ବ୍ୟବହାର କରାଯିବ ଏବଂ କିଛି ଏକତ୍ରିତ ସୂଚନା Google ଆପ୍ ଏବଂ Android ଡେଭଲପର୍ ପରି ଏହାର ପାର୍ଟନରଗୁଡ଼ିକୁ ମଧ୍ୟ ସେଗୁଡ଼ିକର ଆପ୍ ଓ ପ୍ରଡକ୍ଟଗୁଡ଼ିକ ଉନ୍ନତ କରିବାରେ ସାହାଯ୍ୟ କରିବ।</translation>
 <translation id="3838085852053358637">ଏକ୍ସଟେନ୍‍ସନ୍ ଲୋଡ୍ କରିହେଲା ନାହିଁ</translation>
 <translation id="3838486795898716504">ଅଧିକ <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Google Password Managerରେ ସେଭ କରାଯାଇଥିବା ପାସୱାର୍ଡଗୁଡ଼ିକୁ ଯୋଗ କରନ୍ତୁ</translation>
 <translation id="383891835335927981">କୌଣସି ସାଇଟ୍‌କୁ ଜୁମ୍ ଇନ୍ ବା ଆଉଟ୍ କରାଯାଇନାହିଁ</translation>
 <translation id="3839509547554145593">ମାଉସ୍ ସ୍କ୍ରଲ୍ ଆକ୍ସିଲିରେସନ୍ ସକ୍ଷମ କରନ୍ତୁ</translation>
 <translation id="3839516600093027468">କ୍ଲିପ୍‌ବୋର୍ଡ ଦେଖିବାରୁ ସର୍ବଦା <ph name="HOST" />କୁ ବ୍ଲକ୍ କରନ୍ତୁ</translation>
diff --git a/chrome/app/resources/generated_resources_pa.xtb b/chrome/app/resources/generated_resources_pa.xtb
index 70e49adb..31d96abe 100644
--- a/chrome/app/resources/generated_resources_pa.xtb
+++ b/chrome/app/resources/generated_resources_pa.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">ਸਾਈਟਾਂ ਨੂੰ ਤੁਹਾਡਾ ਟਿਕਾਣਾ ਦੇਖਣ ਦੀ ਇਜਾਜ਼ਤ ਨਾ ਦਿਓ</translation>
 <translation id="1335282218035876586">ਤੁਹਾਡੀ Chromebook ਹੁਣ ਸੁਰੱਖਿਆ ਅਤੇ ਸਾਫ਼ਟਵੇਅਰ ਅੱਪਡੇਟ ਪ੍ਰਾਪਤ ਨਹੀਂ ਕਰ ਰਹੀ ਹੈ। ਬਿਹਤਰੀਨ ਅਨੁਭਵ ਲਈ ਆਪਣੀ Chromebook ਨੂੰ ਅੱਪਗ੍ਰੇਡ ਕਰੋ।</translation>
 <translation id="133535873114485416">ਤਰਜੀਹੀ ਇਨਪੁੱਟ</translation>
-<translation id="1335437153193710305">ਤੁਸੀਂ ਉਹ ਪ੍ਰੋਫਾਈਲ ਚੁਣ ਸਕਦੇ ਹੋ, ਜਿਸ ਤੋਂ ਤੁਸੀਂ ਪਾਸਵਰਡ ਦੇਖਣਾ ਚਾਹੁੰਦੇ ਹੋ</translation>
 <translation id="1335929031622236846">ਆਪਣੇ ਡੀਵਾਈਸ ਨੂੰ ਦਰਜ ਕਰੋ</translation>
 <translation id="1336902454946927954">ਤੁਹਾਡੀ ਸੁਰੱਖਿਆ ਕੁੰਜੀ ਲਾਕ ਹੋ ਗਈ ਹੈ ਕਿਉਂਕਿ ਤੁਹਾਡੇ ਫਿੰਗਰਪ੍ਰਿੰਟ ਨੂੰ ਪਛਾਣਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ। ਇਸਨੂੰ ਅਣਲਾਕ ਕਰਨ ਲਈ, ਆਪਣਾ ਪਿੰਨ ਦਾਖਲ ਕਰੋ।</translation>
 <translation id="1338631221631423366">ਜੋੜਾਬੱਧ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ...</translation>
@@ -3328,7 +3327,6 @@
 <translation id="383669374481694771">ਇਹ ਇਸ ਡੀਵਾਈਸ ਅਤੇ ਇਸਦੀ ਵਰਤੋਂ ਬਾਰੇ ਆਮ ਜਾਣਕਾਰੀ ਹੈ (ਜਿਵੇਂ ਕਿ ਬੈਟਰੀ ਪੱਧਰ, ਸਿਸਟਮ ਅਤੇ ਐਪ ਸਰਗਰਮੀ, ਅਤੇ ਗੜਬੜੀਆਂ)। ਡਾਟਾ Android ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ ਵਰਤਿਆ ਜਾਵੇਗਾ ਅਤੇ ਕੁਝ ਏਕੀਕ੍ਰਿਤ ਜਾਣਕਾਰੀ Google ਐਪਾਂ ਅਤੇ ਪਾਰਟਨਰਾਂ, ਜਿਵੇਂ ਕਿ Android ਵਿਕਾਸਕਾਰਾਂ ਦੀਆਂ ਐਪਾਂ ਅਤੇ ਉਤਪਾਦਾਂ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਵਿੱਚ ਵੀ ਉਹਨਾਂ ਦੀ ਮਦਦ ਕਰੇਗੀ।</translation>
 <translation id="3838085852053358637">ਐਕਸਟੈਂਸ਼ਨ ਨੂੰ ਲੋਡ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ</translation>
 <translation id="3838486795898716504">ਹੋਰ <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Google Password Manager ਵਿੱਚ ਰੱਖਿਅਤ ਕੀਤੇ ਪਾਸਵਰਡ ਸ਼ਾਮਲ ਕਰੋ</translation>
 <translation id="383891835335927981">ਕੋਈ ਵੀ ਸਾਈਟਾਂ ਜ਼ੂਮ ਇਨ ਜਾਂ ਆਊਟ ਨਹੀਂ ਕੀਤੀਆਂ ਗਈਆਂ ਹਨ</translation>
 <translation id="3839509547554145593">ਮਾਊਸ ਸਕ੍ਰੋਲ ਐਕਸੈੱਲਰੇਸ਼ਨ ਚਾਲੂ ਕਰੋ</translation>
 <translation id="3839516600093027468"><ph name="HOST" /> ਨੂੰ ਕਲਿੱਪਬੋਰਡ ਦੇਖਣ ਤੋਂ ਹਮੇਸ਼ਾਂ ਬਲਾਕ ਕਰੋ</translation>
diff --git a/chrome/app/resources/generated_resources_pl.xtb b/chrome/app/resources/generated_resources_pl.xtb
index d3199c5..3ea77a58 100644
--- a/chrome/app/resources/generated_resources_pl.xtb
+++ b/chrome/app/resources/generated_resources_pl.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">Nie zezwalaj witrynom na wyświetlanie lokalizacji</translation>
 <translation id="1335282218035876586">Twój Chromebook nie otrzymuje już aktualizacji zabezpieczeń ani oprogramowania. Aby korzystać ze wszystkich funkcji, uaktualnij Chromebooka.</translation>
 <translation id="133535873114485416">Preferowane urządzenie wejściowe</translation>
-<translation id="1335437153193710305">Możesz wybrać profil, z którego chcesz wyświetlić hasła</translation>
 <translation id="1335929031622236846">Zarejestruj swoje urządzenie</translation>
 <translation id="1336902454946927954">Klucz bezpieczeństwa jest zablokowany, bo nie udało się rozpoznać Twojego odcisku palca. Aby odblokować klucz bezpieczeństwa, wpisz kod PIN.</translation>
 <translation id="1338631221631423366">Paruję…</translation>
@@ -3302,7 +3301,6 @@
 <translation id="383669374481694771">Są to ogólne informacje o tym urządzeniu i o jego używaniu (takie jak poziom naładowania baterii, aktywność w systemie i aplikacjach oraz błędy). Wykorzystamy je do ulepszania Androida. Niektóre informacje zbiorcze pomogą nam też udoskonalić aplikacje Google lub zostaną wykorzystane przez naszych partnerów, na przykład deweloperów aplikacji na Androida, do tworzenia lepszych aplikacji i produktów.</translation>
 <translation id="3838085852053358637">Nie udało się wczytać rozszerzenia</translation>
 <translation id="3838486795898716504">Więcej o <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Dodawaj zapisane hasła do Menedżera haseł Google</translation>
 <translation id="383891835335927981">Żadna strona nie jest powiększana ani pomniejszana</translation>
 <translation id="3839509547554145593">Włącz szybkie przewijanie kółkiem myszy</translation>
 <translation id="3839516600093027468">Zawsze blokuj stronie <ph name="HOST" /> dostęp do schowka</translation>
@@ -7078,7 +7076,7 @@
 <translation id="7258192266780953209">Transformacje</translation>
 <translation id="7258225044283673131">Aplikacja nie odpowiada. Aby ją zamknąć, wybierz „Wymuś zamknięcie”.</translation>
 <translation id="7260186537988033909">Rejestrowanie urządzenia w trybie kiosku i tablicy informacyjnej zostało zakończone</translation>
-<translation id="7260367682327802201">Twoje urządzenie z Androidem może mieć podobne ustawienie. Jeśli w Chrome i na Twoim urządzeniu z Androidem jest włączony pomiar skuteczności reklam, firma może mierzyć skuteczność reklam w odwiedzanych przez Ciebie witrynach i w aplikacjach, z których korzystasz.</translation>
+<translation id="7260367682327802201">Twoje urządzenie z Androidem może mieć podobne ustawienie. Jeśli w Chrome i na Twoim urządzeniu z Androidem jest włączony pomiar skuteczności reklam, firma może mierzyć skuteczność reklam w odwiedzanych przez Ciebie witrynach i w aplikacjach, z których korzystasz</translation>
 <translation id="7261612856573623172">Systemowy głos zamiany tekstu na mowę</translation>
 <translation id="7262004276116528033">Ta usługa logowania pochodzi z domeny <ph name="SAML_DOMAIN" /></translation>
 <translation id="7263162347647986485">{NUM_SITES,plural, =1{Usunięto uprawnienia 1 witryny}few{Usunięto uprawnienia {NUM_SITES} witryn}many{Usunięto uprawnienia {NUM_SITES} witryn}other{Usunięto uprawnienia {NUM_SITES} witryny}}</translation>
diff --git a/chrome/app/resources/generated_resources_pt-BR.xtb b/chrome/app/resources/generated_resources_pt-BR.xtb
index e3be854..011503b 100644
--- a/chrome/app/resources/generated_resources_pt-BR.xtb
+++ b/chrome/app/resources/generated_resources_pt-BR.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">Não permitir que os sites acessem seu local</translation>
 <translation id="1335282218035876586">Seu Chromebook deixou de receber atualizações de segurança e de software. Faça upgrade para ter a melhor experiência possível.</translation>
 <translation id="133535873114485416">Entrada preferencial</translation>
-<translation id="1335437153193710305">Você pode escolher um perfil para acessar as senhas</translation>
 <translation id="1335929031622236846">Inscrever seu dispositivo</translation>
 <translation id="1336902454946927954">A chave de segurança está bloqueada porque sua impressão digital não foi reconhecida. Para desbloquear, digite seu PIN.</translation>
 <translation id="1338631221631423366">Pareando…</translation>
@@ -3331,7 +3330,6 @@
 <translation id="383669374481694771">Estas são informações gerais sobre este dispositivo e a forma como ele é usado, como nível da bateria, atividade de apps e do sistema e erros. Os dados serão usados para melhorar o Android, e algumas informações agregadas também ajudarão apps e parceiros do Google, como os desenvolvedores Android, a melhorar os apps e produtos deles.</translation>
 <translation id="3838085852053358637">Falha ao carregar extensão</translation>
 <translation id="3838486795898716504">Mais <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Adicione senhas salvas ao Gerenciador de senhas do Google</translation>
 <translation id="383891835335927981">Nenhum site teve o zoom aumentado ou diminuído</translation>
 <translation id="3839509547554145593">Ativar aceleração de rolagem do mouse</translation>
 <translation id="3839516600093027468">Sempre impedir que <ph name="HOST" /> veja a área de transferência</translation>
diff --git a/chrome/app/resources/generated_resources_pt-PT.xtb b/chrome/app/resources/generated_resources_pt-PT.xtb
index 50a0ef3..e7791c52 100644
--- a/chrome/app/resources/generated_resources_pt-PT.xtb
+++ b/chrome/app/resources/generated_resources_pt-PT.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Recomenda-se, pelo menos, <ph name="INSTALL_SIZE" /> de espaço para o Linux. Para aumentar o espaço livre, elimine ficheiros do dispositivo.</translation>
 <translation id="1038643060055067718">Linhas:</translation>
 <translation id="1039337018183941703">Ficheiro inválido ou danificado</translation>
+<translation id="1040761927998636252">Marcador sem nome para <ph name="URL" /></translation>
 <translation id="1041175011127912238">Esta página não está a responder.</translation>
 <translation id="1041263367839475438">Dispositivos disponíveis</translation>
 <translation id="1042174272890264476">O seu computador também tem a biblioteca RLZ de <ph name="SHORT_PRODUCT_NAME" /> incorporada. A RLZ atribui uma etiqueta não exclusiva e não identificável a nível pessoal para medir as pesquisas e a utilização de <ph name="SHORT_PRODUCT_NAME" /> impulsionada por uma campanha promocional específica. Estas etiquetas por vezes aparecem em consultas da Pesquisa Google em <ph name="PRODUCT_NAME" />.</translation>
@@ -387,7 +388,6 @@
 <translation id="1333965224356556482">Não permitir que os sites vejam a sua localização</translation>
 <translation id="1335282218035876586">O seu Chromebook já não está a receber atualizações de segurança e software. Atualize o Chromebook para obter a melhor experiência.</translation>
 <translation id="133535873114485416">Introdução preferida</translation>
-<translation id="1335437153193710305">Pode escolher o perfil a partir do qual quer ver as palavras-passe</translation>
 <translation id="1335929031622236846">Inscreva o seu dispositivo</translation>
 <translation id="1336902454946927954">A sua chave de segurança está bloqueada porque não foi possível reconhecer a sua impressão digital. Para a desbloquear, introduza o seu PIN.</translation>
 <translation id="1338631221631423366">A sincronizar…</translation>
@@ -3314,7 +3314,6 @@
 <translation id="383669374481694771">Estas são informações gerais acerca deste dispositivo e da forma como o utiliza (como o nível da bateria, a atividade do sistema e de apps e erros). Os dados são utilizados para melhorar o Android e algumas informações agregadas também ajudarão as apps e os parceiros Google, como os programadores Android, a melhorar os respetivos produtos e apps.</translation>
 <translation id="3838085852053358637">Falha ao carregar a extensão</translation>
 <translation id="3838486795898716504">Mais <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Adicione palavras-passe guardadas ao Gestor de Palavras-passe da Google</translation>
 <translation id="383891835335927981">O zoom dos sites não foi aumentado nem diminuído</translation>
 <translation id="3839509547554145593">Ativar aceleração da deslocação do rato</translation>
 <translation id="3839516600093027468">Impedir sempre <ph name="HOST" /> de ver a área de transferência</translation>
diff --git a/chrome/app/resources/generated_resources_ro.xtb b/chrome/app/resources/generated_resources_ro.xtb
index a98b3f2..7f8c3fa6 100644
--- a/chrome/app/resources/generated_resources_ro.xtb
+++ b/chrome/app/resources/generated_resources_ro.xtb
@@ -390,7 +390,6 @@
 <translation id="1333965224356556482">Nu permite site-urilor să-ți vadă locația</translation>
 <translation id="1335282218035876586">Chromebookul nu mai primește actualizări de securitate și de software. Fă upgrade Chromebookului pentru o experiență optimă.</translation>
 <translation id="133535873114485416">Metoda preferată de introducere</translation>
-<translation id="1335437153193710305">Poți alege profilul din care vrei să vezi parolele</translation>
 <translation id="1335929031622236846">Înregistrează dispozitivul</translation>
 <translation id="1336902454946927954">Cheia de securitate este blocată, deoarece amprenta nu a fost recunoscută. Introdu codul PIN ca să o deblochezi.</translation>
 <translation id="1338631221631423366">Se asociază…</translation>
@@ -3316,7 +3315,6 @@
 <translation id="383669374481694771">Acestea sunt informații generale despre dispozitiv și despre modul în care îl folosești (de exemplu, nivelul bateriei, activitatea pe sistem și în aplicații și erorile). Datele vor fi folosite pentru îmbunătățirea Android și unele informații cumulate vor ajuta aplicațiile și partenerii Google, cum ar fi dezvoltatorii Android, să își îmbunătățească aplicațiile și produsele.</translation>
 <translation id="3838085852053358637">Extensia nu s-a încărcat</translation>
 <translation id="3838486795898716504">Mai multe <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Adaugă parolele salvate în Managerul de parole Google</translation>
 <translation id="383891835335927981">Nu s-a mărit sau micșorat niciun site</translation>
 <translation id="3839509547554145593">Activează accelerarea derulării mouse-ului</translation>
 <translation id="3839516600093027468">Blochează întotdeauna accesul <ph name="HOST" /> la clipboard</translation>
diff --git a/chrome/app/resources/generated_resources_ru.xtb b/chrome/app/resources/generated_resources_ru.xtb
index 36874fb..1ba7324 100644
--- a/chrome/app/resources/generated_resources_ru.xtb
+++ b/chrome/app/resources/generated_resources_ru.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Для Linux рекомендуется как минимум <ph name="INSTALL_SIZE" /> свободного пространства. Удалите с устройства файлы, которые больше не нужны.</translation>
 <translation id="1038643060055067718">Строк:</translation>
 <translation id="1039337018183941703">Файл поврежден или недействителен</translation>
+<translation id="1040761927998636252">Закладка без названия: <ph name="URL" /></translation>
 <translation id="1041175011127912238">Страница не отвечает</translation>
 <translation id="1041263367839475438">Доступные устройства</translation>
 <translation id="1042174272890264476">В ваш компьютер встроена библиотека RLZ <ph name="SHORT_PRODUCT_NAME" />. RLZ присваивает компьютеру неуникальную и не позволяющую идентифицировать пользователя метку, с помощью которой мы можем оценить количество запросов и статистику использования этого продукта (<ph name="SHORT_PRODUCT_NAME" />) по результатам рекламных кампаний. Иногда метки могут включаться в поисковые запросы, сделанные в этом продукте (<ph name="PRODUCT_NAME" />).</translation>
@@ -390,7 +391,6 @@
 <translation id="1333965224356556482">Запретить сайтам доступ к местоположению</translation>
 <translation id="1335282218035876586">Устройство Chromebook больше не получает обновления системы безопасности и программного обеспечения. Чтобы работать было удобнее, перейдите на новое устройство Chromebook.</translation>
 <translation id="133535873114485416">Предпочитаемый способ ввода</translation>
-<translation id="1335437153193710305">Можно выбрать профиль, пароль от которого вы хотите посмотреть.</translation>
 <translation id="1335929031622236846">Зарегистрируйте устройство</translation>
 <translation id="1336902454946927954">Не удалось распознать отпечаток пальца. Электронный ключ заблокирован. Чтобы разблокировать его, введите PIN-код.</translation>
 <translation id="1338631221631423366">Подключение…</translation>
@@ -3314,7 +3314,6 @@
 <translation id="383669374481694771">Мы будем получать общие сведения о работе устройства, например об уровне заряда батареи, ошибках и действиях в системе и приложениях. Они помогут нам усовершенствовать Android, а наши партнеры смогут использовать некоторые агрегированные данные, чтобы улучшать свои приложения и другие продукты.</translation>
 <translation id="3838085852053358637">Ошибка загрузки</translation>
 <translation id="3838486795898716504">Другие страницы с заголовком <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Добавляйте сохраненные пароли в Google Менеджер паролей.</translation>
 <translation id="383891835335927981">Нет сайтов с измененным масштабом</translation>
 <translation id="3839509547554145593">Включить ускорение прокрутки мыши</translation>
 <translation id="3839516600093027468">Никогда не открывать сайту <ph name="HOST" /> доступ к буферу обмена</translation>
@@ -3699,7 +3698,7 @@
 <translation id="4186749321808907788"><ph name="QUERY_NAME" /> – <ph name="DEFAULT_SEARCH_ENGINE_NAME" /> Поиск</translation>
 <translation id="4187424053537113647">Настройка <ph name="APP_NAME" />…</translation>
 <translation id="4190828427319282529">Выделение объектов, выбранных с помощью клавиатуры</translation>
-<translation id="4193575319002689239">Показать подсказки</translation>
+<translation id="4193575319002689239">Показывать карточки</translation>
 <translation id="4193836101014293726">Невозможно удалить профиль</translation>
 <translation id="419427585139779713">Вводить по слогам</translation>
 <translation id="4194570336751258953">Включить нажатие от прикосновения</translation>
diff --git a/chrome/app/resources/generated_resources_si.xtb b/chrome/app/resources/generated_resources_si.xtb
index 0d94c37d..900bdd5 100644
--- a/chrome/app/resources/generated_resources_si.xtb
+++ b/chrome/app/resources/generated_resources_si.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">ලිනක්ස් සඳහා අවම වශයෙන් <ph name="INSTALL_SIZE" /> ක ඉඩ නිර්දේශ කෙරේ. නිදහස් ඉඩ වැඩි කිරීමට, ඔබේ උපාංගයෙන් ගොනු මකන්න.</translation>
 <translation id="1038643060055067718">රේඛා:</translation>
 <translation id="1039337018183941703">වලංගු නොවන හෝ දූෂිත ගොනුවකි</translation>
+<translation id="1040761927998636252"><ph name="URL" /> සඳහා නම් නොකළ පිටුසන</translation>
 <translation id="1041175011127912238">මෙම පිටුව ප්‍රතිචාර නොදක්වයි</translation>
 <translation id="1041263367839475438">තිබෙන උපාංග</translation>
 <translation id="1042174272890264476">ඔබේ පරිගණකය අැතුළතින් සවි කළ <ph name="SHORT_PRODUCT_NAME" />හි RLZ පුස්තකාලයද සමඟ පැමිණේ. RLZ විසින් විශේෂ ප්‍රවර්ධනාත්මක ව්‍යාපාරයක් මඟින් ධාවනය වන සෙවීම් සහ <ph name="SHORT_PRODUCT_NAME" /> භාවිතය මැනීම සදහා අසමසම නොවන, පුද්ගලික නොවන ලෙස හදුනාගත හැකි ටැග් ඒකක් පවරයි. මෙම ලේබල සමහර විට Google සෙවීම් විමසුම්වල දිස් වේ <ph name="PRODUCT_NAME" />.</translation>
@@ -390,7 +391,6 @@
 <translation id="1333965224356556482">ඔබගේ ස්ථානය බැලීමට අඩවිවලට ඉඩ නොදෙන්න</translation>
 <translation id="1335282218035876586">ඔබේ Chromebook හට තවදුරටත් ආරක්ෂක සහ මෘදුකාංග යාවත්කාලීන නොලැබේ. හොඳම අත්දැකීම සඳහා ඔබේ Chromebook උත්ශ්‍රේණි කරන්න.</translation>
 <translation id="133535873114485416">වඩා කැමති ආදාන</translation>
-<translation id="1335437153193710305">ඔබට මුරපද බැලීමට අවශ්‍ය පැතිකඩ තෝරා ගැනීමට හැක</translation>
 <translation id="1335929031622236846">ඔබේ උපාංගය ඇතුළත් කරන්න</translation>
 <translation id="1336902454946927954">ඔබේ ඇඟිලි සලකුණ හඳුනාගත නොහැකි වූ බැවින් ඔබේ ආරක්‍ෂක යතුර අගුලු වැටී ඇත. අගුලු ඇරීමට, ඔබේ රහස් අංකය ඇතුළත් කරන්න.</translation>
 <translation id="1338631221631423366">යුගල කරමින්...</translation>
@@ -3316,7 +3316,6 @@
 <translation id="383669374481694771">මේ (බැටරි මට්ටම, පද්ධති සහ යෙදුම් ක්‍රියාකාරකම්, සහ දෝෂ වැනි) මෙම උපාංගය සහ එය භාවිත කෙරෙන ආකාරය පිළිබඳ සාමාන්‍ය තොරතුරු වෙයි. Android වැඩි දියුණු කිරීමට දත්ත භාවිත කරන අතර සමහර රැස් කළ තොරතුරු Google යෙදුම් සහ Android සංවර්ධකයන් වැනි, හවුල්කරුවන්ට ඔවුන්ගේ යෙදුම් සහ නිෂ්පාදන වඩා යහපත් කිරීමට ද උදවු කරයි.</translation>
 <translation id="3838085852053358637">දිගුව පූරණය කිරීම අසාර්ථක විය</translation>
 <translation id="3838486795898716504">තව <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">සුරකින ලද මුරපද Google මුරපද කළමනාකරු වෙත එක් කරන්න</translation>
 <translation id="383891835335927981">කිසිදු අඩවියක් විශාලනය හෝ කුඩා කර නැත</translation>
 <translation id="3839509547554145593">මූසික අනුචලන ත්වරණය සබල කරන්න</translation>
 <translation id="3839516600093027468"><ph name="HOST" /> පසුරු පුවරුව දැකීමෙන් සැමවිටම අවහිර කරන්න</translation>
diff --git a/chrome/app/resources/generated_resources_sk.xtb b/chrome/app/resources/generated_resources_sk.xtb
index bf9a69be..965b2ea 100644
--- a/chrome/app/resources/generated_resources_sk.xtb
+++ b/chrome/app/resources/generated_resources_sk.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Na používanie systému Linux sa vyžaduje minimálne <ph name="INSTALL_SIZE" /> voľného priestoru. Uvoľníte ho odstránením súborov zo zariadenia.</translation>
 <translation id="1038643060055067718">Riadky:</translation>
 <translation id="1039337018183941703">Neplatný alebo poškodený súbor</translation>
+<translation id="1040761927998636252">Záložka bez názvu pre <ph name="URL" /></translation>
 <translation id="1041175011127912238">Táto stránka nereaguje</translation>
 <translation id="1041263367839475438">Dostupné zariadenia</translation>
 <translation id="1042174272890264476">Váš počítač má tiež vstavanú knižnicu RLZ prehliadača <ph name="SHORT_PRODUCT_NAME" />. Knižnica RLZ priradí nejedinečnú značku, pomocou ktorej sa nedá zistiť totožnosť, na meranie výsledkov a použitia prehliadača <ph name="SHORT_PRODUCT_NAME" /> vyplývajúceho z konkrétnej propagačnej kampane. Tieto menovky sa niekedy zobrazujú v dopytoch Vyhľadávania Google v prehliadači <ph name="PRODUCT_NAME" />.</translation>
@@ -389,7 +390,6 @@
 <translation id="1333965224356556482">Nepovoliť webom zobrazovať polohu</translation>
 <translation id="1335282218035876586">Váš Chromebook už nedostáva bezpečnostné aktualizácie ani aktualizácie softvéru. Ak chcete mať k dispozícii to najlepšie prostredie, inovujte Chromebook.</translation>
 <translation id="133535873114485416">Preferovaný vstup</translation>
-<translation id="1335437153193710305">Môžete vybrať profil, ktorého chcete heslá zobraziť</translation>
 <translation id="1335929031622236846">Registrácia vášho zariadenia</translation>
 <translation id="1336902454946927954">Bezpečnostný kľúč je uzamknutý, pretože sa nepodarilo rozpoznať odtlačok prsta. Ak ho chcete odomknúť, zadajte PIN.</translation>
 <translation id="1338631221631423366">Páruje sa…</translation>
@@ -3314,7 +3314,6 @@
 <translation id="383669374481694771">Toto sú všeobecné informácie o tomto zariadení a jeho používaní (napríklad stav batérie, aktivita v systéme a aplikáciách a chyby). Údaje sa použijú na zlepšenie Androidu a niektoré súhrnné informácie pomôžu tiež aplikáciám Google a partnerom (napríklad vývojárom pre Android) zlepšiť svoje aplikácie a produkty.</translation>
 <translation id="3838085852053358637">Načítanie rozšírenia zlyhalo</translation>
 <translation id="3838486795898716504">Ďalšie <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Pridanie uložených hesiel do Správcu hesiel Google</translation>
 <translation id="383891835335927981">Žiadne weby neboli priblížené ani oddialené</translation>
 <translation id="3839509547554145593">Povoliť zrýchlenie pri posúvaní myšou</translation>
 <translation id="3839516600093027468">Webu <ph name="HOST" /> vždy blokovať zobrazenie schránky</translation>
diff --git a/chrome/app/resources/generated_resources_sl.xtb b/chrome/app/resources/generated_resources_sl.xtb
index a2bc557..b8809af 100644
--- a/chrome/app/resources/generated_resources_sl.xtb
+++ b/chrome/app/resources/generated_resources_sl.xtb
@@ -393,7 +393,6 @@
 <translation id="1333965224356556482">Spletnim mestom ni dovoljen ogled vaše lokacije.</translation>
 <translation id="1335282218035876586">Vaš Chromebook ne prejema več varnostnih posodobitev in posodobitev programske opreme. Za najboljšo izkušnjo nadgradite Chromebook.</translation>
 <translation id="133535873114485416">Želeni način vnosa</translation>
-<translation id="1335437153193710305">Izberete lahko profil, za katerega si želite ogledati gesla.</translation>
 <translation id="1335929031622236846">Včlanite napravo</translation>
 <translation id="1336902454946927954">Varnostni ključ je zaklenjen, ker vašega prstnega odtisa ni bilo mogoče prepoznati. Če ga želite odkleniti, vnesite PIN.</translation>
 <translation id="1338631221631423366">Seznanjanje …</translation>
@@ -3331,7 +3330,6 @@
 <translation id="383669374481694771">Gre za splošne podatke o tej napravi in njeni uporabi, kot so raven napolnjenosti baterije, dejavnost sistema in aplikacije ter napake. Ti podatki bodo uporabljeni za izboljšanje sistema Android. Nekateri združeni podatki bodo pomagali tudi Googlovim aplikacijam in partnerjem, na primer razvijalcem za Android, izboljšati aplikacije in izdelke.</translation>
 <translation id="3838085852053358637">Ni bilo mogoče naložiti razširitve</translation>
 <translation id="3838486795898716504">Več <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Dodajte gesla v Googlovega upravitelja gesel.</translation>
 <translation id="383891835335927981">Nobeno spletno mesto ni povečano ali pomanjšano</translation>
 <translation id="3839509547554145593">Omogoči pospeševalnik drsenja z miško</translation>
 <translation id="3839516600093027468">Vedno prepreči naslovu <ph name="HOST" /> ogled odložišča</translation>
diff --git a/chrome/app/resources/generated_resources_sq.xtb b/chrome/app/resources/generated_resources_sq.xtb
index 787cae33..d564f92 100644
--- a/chrome/app/resources/generated_resources_sq.xtb
+++ b/chrome/app/resources/generated_resources_sq.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Për Linux rekomandohet të paktën <ph name="INSTALL_SIZE" /> hapësirë. Për të rritur nivelin e hapësirës së lirë, fshi skedarë nga pajisja jote.</translation>
 <translation id="1038643060055067718">Vijat:</translation>
 <translation id="1039337018183941703">Skedar i pavlefshëm ose i dëmtuar</translation>
+<translation id="1040761927998636252">Faqeshënues pa emër për <ph name="URL" /></translation>
 <translation id="1041175011127912238">Kjo faqe nuk përgjigjet</translation>
 <translation id="1041263367839475438">Pajisjet që ofrohen</translation>
 <translation id="1042174272890264476">Kompjuteri yt vjen po ashtu me bibliotekën RLZ të <ph name="SHORT_PRODUCT_NAME" /> të integruar. Parametri RLZ cakton një etiketë jo unike, jo personalisht të identifikueshme për të matur kërkimet dhe përdorimin e <ph name="SHORT_PRODUCT_NAME" /> të nxitur nga një fushatë promocionale të veçantë. Këto etiketa ndonjëherë shfaqen në pyetjet e "Kërko me Google" në <ph name="PRODUCT_NAME" />.</translation>
@@ -387,7 +388,6 @@
 <translation id="1333965224356556482">Mos lejo që sajtet të shikojnë vendndodhjen tënde</translation>
 <translation id="1335282218035876586">Pajisja jote Chromebook nuk merr më përditësime të sigurisë dhe të softuerit. Përmirësoje pajisjen tënde Chromebook për përvojën më të mirë.</translation>
 <translation id="133535873114485416">Hyrja e preferuar</translation>
-<translation id="1335437153193710305">Mund të zgjedhësh profilin nga i cili dëshiron të shikosh fjalëkalimet</translation>
 <translation id="1335929031622236846">Regjistro pajisjen tënde</translation>
 <translation id="1336902454946927954">Çelësi yt i sigurisë është i kyçur sepse gjurma jote e gishtit nuk mund të njihej. Për ta shkyçur, fut kodin PIN.</translation>
 <translation id="1338631221631423366">Po çiftohet...</translation>
@@ -3310,7 +3310,6 @@
 <translation id="383669374481694771">Këto janë informacione të përgjithshme për këtë pajisje dhe se si përdoret (si p.sh. niveli i baterisë, aktiviteti i sistemit dhe aplikacioneve dhe gabimet). Të dhënat do të përdoren për të përmirësuar Android dhe disa informacione të përmbledhura do t'i ndihmojnë po ashtu aplikacionet dhe partnerët e Google, si p.sh. zhvilluesit e Android, që të përmirësojnë aplikacionet dhe produktet e tyre.</translation>
 <translation id="3838085852053358637">Dështoi në ngarkimin e shtesës</translation>
 <translation id="3838486795898716504">Më shumë <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Shto fjalëkalimet e ruajtura te "Menaxheri i fjalëkalimeve i Google"</translation>
 <translation id="383891835335927981">Asnjë sajt nuk është zmadhuar apo zvogëluar</translation>
 <translation id="3839509547554145593">Aktivizo përshpejtimin e lëvizjes së miut</translation>
 <translation id="3839516600093027468">Blloko gjithmonë <ph name="HOST" /> që të mos shikojë kujtesën e fragmenteve</translation>
diff --git a/chrome/app/resources/generated_resources_sr-Latn.xtb b/chrome/app/resources/generated_resources_sr-Latn.xtb
index 7ffaff83..4746d9d 100644
--- a/chrome/app/resources/generated_resources_sr-Latn.xtb
+++ b/chrome/app/resources/generated_resources_sr-Latn.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">Ne dozvoljavaj sajtovima da vide vašu lokaciju</translation>
 <translation id="1335282218035876586">Chromebook više ne prima bezbednosna i softverska ažuriranja. Nadogradite Chromebook za najbolji doživljaj.</translation>
 <translation id="133535873114485416">Željeni način unosa</translation>
-<translation id="1335437153193710305">Možete da odaberete profil sa kog želite da vidite lozinke</translation>
 <translation id="1335929031622236846">Registrujte uređaj</translation>
 <translation id="1336902454946927954">Vaš bezbednosni ključ je zaključan jer nismo uspeli da prepoznamo otisak prsta. Da biste ga otključali, unesite PIN.</translation>
 <translation id="1338631221631423366">Uparuje se...</translation>
@@ -3313,7 +3312,6 @@
 <translation id="383669374481694771">Ovo su opšte informacije o ovom uređaju i načinu na koji se koristi (poput nivoa napunjenosti baterije, aktivnosti sistema i aplikacija, i grešaka). Podaci će se koristiti za poboljšanje Android-a, a neke objedinjene informacije će pomoći i Google aplikacijama i partnerima, kao što su Android programeri, da poboljšaju svoje aplikacije i proizvode.</translation>
 <translation id="3838085852053358637">Učitavanje dodatka nije uspelo</translation>
 <translation id="3838486795898716504">Još stranica <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Dodajte sačuvane lozinke u Google menadžer lozinki</translation>
 <translation id="383891835335927981">Nijedan sajt nije uvećan ni umanjen</translation>
 <translation id="3839509547554145593">Omogući ubrzanje pomeranja mišem</translation>
 <translation id="3839516600093027468">Uvek blokiraj uvid u privremenu memoriju stranici <ph name="HOST" /></translation>
diff --git a/chrome/app/resources/generated_resources_sr.xtb b/chrome/app/resources/generated_resources_sr.xtb
index 2bab8d8a..c952f56 100644
--- a/chrome/app/resources/generated_resources_sr.xtb
+++ b/chrome/app/resources/generated_resources_sr.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">Не дозвољавај сајтовима да виде вашу локацију</translation>
 <translation id="1335282218035876586">Chromebook више не прима безбедносна и софтверска ажурирања. Надоградите Chromebook за најбољи доживљај.</translation>
 <translation id="133535873114485416">Жељени начин уноса</translation>
-<translation id="1335437153193710305">Можете да одаберете профил са ког желите да видите лозинке</translation>
 <translation id="1335929031622236846">Региструјте уређај</translation>
 <translation id="1336902454946927954">Ваш безбедносни кључ је закључан јер нисмо успели да препознамо отисак прста. Да бисте га откључали, унесите PIN.</translation>
 <translation id="1338631221631423366">Упарује се...</translation>
@@ -3313,7 +3312,6 @@
 <translation id="383669374481694771">Ово су опште информације о овом уређају и начину на који се користи (попут нивоа напуњености батерије, активности система и апликација, и грешака). Подаци ће се користити за побољшање Android-а, а неке обједињене информације ће помоћи и Google апликацијама и партнерима, као што су Android програмери, да побољшају своје апликације и производе.</translation>
 <translation id="3838085852053358637">Учитавање додатка није успело</translation>
 <translation id="3838486795898716504">Још страница <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Додајте сачуване лозинке у Google менаџер лозинки</translation>
 <translation id="383891835335927981">Ниједан сајт није увећан ни умањен</translation>
 <translation id="3839509547554145593">Омогући убрзање померања мишем</translation>
 <translation id="3839516600093027468">Увек блокирај увид у привремену меморију страници <ph name="HOST" /></translation>
diff --git a/chrome/app/resources/generated_resources_sv.xtb b/chrome/app/resources/generated_resources_sv.xtb
index b04b6c7..cc095a7 100644
--- a/chrome/app/resources/generated_resources_sv.xtb
+++ b/chrome/app/resources/generated_resources_sv.xtb
@@ -390,7 +390,6 @@
 <translation id="1333965224356556482">Tillåt inte att webbplatser ser din plats</translation>
 <translation id="1335282218035876586">Din Chromebook får inte längre säkerhets- och programvaruuppdateringar. Uppgradera din Chromebook för bästa möjliga upplevelse.</translation>
 <translation id="133535873114485416">Föredraget inmatningssätt</translation>
-<translation id="1335437153193710305">Du kan välja den profil som du vill se lösenorden från</translation>
 <translation id="1335929031622236846">Registrera din enhet</translation>
 <translation id="1336902454946927954">Säkerhetsnyckeln är låst eftersom ditt fingeravtryck inte kändes igen. Lås upp den genom att ange pinkoden.</translation>
 <translation id="1338631221631423366">Parkopplar …</translation>
@@ -3329,7 +3328,6 @@
 <translation id="383669374481694771">Detta är allmän information om enheten och hur den används (till exempel batterinivå, system- och appaktivitet samt fel). Med hjälp av dessa uppgifter kan vi förbättra Android och vissa samlade uppgifter kan även hjälpa Googles appar och Googles partner, till exempel Android-utvecklare, att förbättra sina appar och produkter.</translation>
 <translation id="3838085852053358637">Det gick inte att läsa in tillägget</translation>
 <translation id="3838486795898716504">Mer <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Lägg till sparade lösenord i Google Lösenordshantering</translation>
 <translation id="383891835335927981">Inga webbplatser har zoomats in eller ut</translation>
 <translation id="3839509547554145593">Aktivera scrollningsacceleration för musen</translation>
 <translation id="3839516600093027468">Blockera alltid tillgången till Urklipp för <ph name="HOST" /></translation>
diff --git a/chrome/app/resources/generated_resources_sw.xtb b/chrome/app/resources/generated_resources_sw.xtb
index d2d195c55..9e4713e 100644
--- a/chrome/app/resources/generated_resources_sw.xtb
+++ b/chrome/app/resources/generated_resources_sw.xtb
@@ -390,7 +390,6 @@
 <translation id="1333965224356556482">Usiruhusu tovuti zione mahali ulipo</translation>
 <translation id="1335282218035876586">Chromebook yako haipokei tena masasisho ya usalama na programu. Sasisha Chromebook yako ili upate hali bora ya utumiaji.</translation>
 <translation id="133535873114485416">Mbinu unayopendelea ya kuingiza sauti</translation>
-<translation id="1335437153193710305">Unaweza kuchagua wasifu ambako ungependa uone manenosiri</translation>
 <translation id="1335929031622236846">Andikisha kifaa chako</translation>
 <translation id="1336902454946927954">Ufunguo wako wa usalama umefungwa kwa sababu tumeshindwa kutambua alama yako ya kidole. Ili uufungue, weka PIN yako.</translation>
 <translation id="1338631221631423366">Inaoanisha...</translation>
@@ -3325,7 +3324,6 @@
 <translation id="383669374481694771">Haya ni maelezo ya jumla kuhusu kifaa hiki na jinsi kinavyotumika (kama vile hitilafu, kiwango cha chaji ya betri, shughuli za programu na mfumo). Data itatumika kuboresha Android na baadhi ya maelezo yanayojumlishwa yatasaidia pia programu na washirika wa Google, kama vile wasanidi programu za Android, kuboresha programu na bidhaa zao.</translation>
 <translation id="3838085852053358637">Haijafaulu kupakia kiendelezi</translation>
 <translation id="3838486795898716504"><ph name="PAGE_TITLE" /> zaidi</translation>
-<translation id="3838487810283346084">Weka manenosiri yaliyohifadhiwa kwenye Kidhibiti cha Manenosiri cha Google</translation>
 <translation id="383891835335927981">Hakuna tovuti zilizovutwa karibu wala kusogezwa mbali</translation>
 <translation id="3839509547554145593">Ruhusu hali ya kuongeza kasi ya kusogeza kipanya</translation>
 <translation id="3839516600093027468">Zuia <ph name="HOST" /> kila wakati ili isione ubao wa kunakili</translation>
diff --git a/chrome/app/resources/generated_resources_ta.xtb b/chrome/app/resources/generated_resources_ta.xtb
index c168c50..392e9f0 100644
--- a/chrome/app/resources/generated_resources_ta.xtb
+++ b/chrome/app/resources/generated_resources_ta.xtb
@@ -390,7 +390,6 @@
 <translation id="1333965224356556482">எனது இருப்பிட விவரத்தை அறிய தளங்களை அனுமதிக்காதே</translation>
 <translation id="1335282218035876586">உங்கள் Chromebook இனி பாதுகாப்பு மற்றும் மென்பொருள் புதுப்பிப்புகளைப் பெறாது. சிறந்த அனுபவத்தைப் பெற உங்கள் Chromebookகை மேம்படுத்தவும்.</translation>
 <translation id="133535873114485416">விருப்பமான உள்ளீட்டு முறை</translation>
-<translation id="1335437153193710305">நீங்கள் கடவுச்சொற்களைப் பார்க்க விரும்பும் சுயவிவரத்தைத் தேர்வுசெய்யலாம்</translation>
 <translation id="1335929031622236846">உங்கள் சாதனத்தைப் பதிவுசெய்யவும்</translation>
 <translation id="1336902454946927954">உங்களின் கைரேகையை அடையாளங்காண முடியவில்லை என்பதால் பாதுகாப்பு விசை பூட்டப்பட்டுள்ளது. அன்லாக் செய்ய, உங்கள் பின்னை உள்ளிடவும்.</translation>
 <translation id="1338631221631423366">இணைக்கிறது...</translation>
@@ -3328,7 +3327,6 @@
 <translation id="383669374481694771">இந்தச் சாதனம் மற்றும் இதைப் பயன்படுத்தும் விதம் (பேட்டரியின் அளவு, சிஸ்டம் மற்றும் ஆப்ஸ் செயல்பாடு மற்றும் பிழைகள் போன்றவை) குறித்த பொதுவான தகவல் இது. Androidடை மேம்படுத்த இந்தத் தரவு பயன்படுத்தப்படும். மேலும், Google ஆப்ஸுக்கும் Android டெவெலப்பர்கள் போன்ற கூட்டாளர்கள் தங்களின் ஆப்ஸ் மற்றும் தயாரிப்புகளைச் சிறப்பாக அமைக்கவும் ஒருங்கிணைக்கப்பட்ட சில தரவு உதவும்.</translation>
 <translation id="3838085852053358637">நீட்டிப்பை ஏற்ற முடியவில்லை</translation>
 <translation id="3838486795898716504">மேலும் <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">சேமிக்கப்பட்ட கடவுச்சொற்களை Google Password Managerரில் சேர்க்கலாம்</translation>
 <translation id="383891835335927981">எந்தத் தளங்களும் பெரிதாக்கப்படவோ சிறிதாக்கப்படவோ இல்லை</translation>
 <translation id="3839509547554145593">'மவுஸைத் துரிதமாக நகர்த்துதல்' அம்சத்தை இயக்கு</translation>
 <translation id="3839516600093027468"><ph name="HOST" />, கிளிப்போர்டைப் பார்ப்பதை எப்போதும் தடைசெய்</translation>
diff --git a/chrome/app/resources/generated_resources_te.xtb b/chrome/app/resources/generated_resources_te.xtb
index 5009490..c312e10 100644
--- a/chrome/app/resources/generated_resources_te.xtb
+++ b/chrome/app/resources/generated_resources_te.xtb
@@ -118,6 +118,7 @@
 <translation id="1090541560108055381">పెయిర్ చేసే ముందు, రెండు పరికరాల్లో ఈ కోడ్ ఒకేలా ఉందని నిర్ధారించుకోండి</translation>
 <translation id="1091767800771861448">దాటవేయడానికి ESCAPEను నొక్కండి (అనధికార బిల్డ్‌లకు మాత్రమే)</translation>
 <translation id="1093457606523402488">కనిపిస్తున్న నెట్‌వర్క్‌లు:</translation>
+<translation id="1094219634413363886">మేనేజ్ చేసే ఈ పరికరంలో రికార్డింగ్ ప్రారంభమైతే, మీకు నోటిఫికేషన్ కనిపిస్తుంది</translation>
 <translation id="1095761715416917775">మీ సింక్ డేటాను మీరు ఎల్లప్పుడూ యాక్సెస్ చేయగలరని నిర్ధారించుకోండి</translation>
 <translation id="1095879482467973146">వెబ్‌లో Google Password Manager</translation>
 <translation id="109647177154844434">Parallels desktopను అన్‌ఇన్‌స్టాల్ చేస్తే మీ Windows యొక్క ఇమేజ్ తొలగించబడుతుంది. ఇందులో దాని యాప్‌లు, సెట్టింగ్‌లు, డేటా ఉంటాయి. మీరు ఖచ్చితంగా కొనసాగించాలనుకుంటున్నారా?</translation>
@@ -390,7 +391,6 @@
 <translation id="1333965224356556482">మీ లొకేషన్‌ను చూడటానికి సైట్‌లను అనుమతించకండి</translation>
 <translation id="1335282218035876586">ఇప్పటి నుండి, మీ Chromebook సెక్యూరిటీ, సాఫ్ట్‌వేర్ అప్‌డేట్‌లను అందుకోదు. ఉత్తమ అనుభవం కోసం మీ Chromebookను అప్‌గ్రేడ్ చేయండి.</translation>
 <translation id="133535873114485416">ప్రాధాన్య ఇన్‌పుట్</translation>
-<translation id="1335437153193710305">మీరు పాస్‌వర్డ్‌లను చూడాలనుకుంటున్న ప్రొఫైల్‌ను ఎంచుకోవచ్చు</translation>
 <translation id="1335929031622236846">మీ పరికరాన్ని నమోదు చేయండి</translation>
 <translation id="1336902454946927954">మీ వేలిముద్రను గుర్తించలేకపోయినందున మీ సెక్యూరిటీ కీ లాక్ చేయబడింది. దానిని అన్‌లాక్ చేయడానికి, మీ పిన్‌ను ఎంటర్ చేయండి.</translation>
 <translation id="1338631221631423366">పెయిరింగ్...</translation>
@@ -3326,7 +3326,6 @@
 <translation id="383669374481694771">ఈ పరికరం, దీనిని ఉపయోగించే పద్ధతి (బ్యాటరీ స్థాయి, సిస్టమ్, యాప్ యాక్టివిటీ, ఎర్రర్‌లు లాంటివి) గురించి ఇది సాధారణ సమాచారం. ఈ డేటా Androidను మెరుగుపరచడం కోసం ఉపయోగించబడుతుంది. కొంత ఏకీకృత సమాచారం కూడా Google యాప్‌లు, Android డెవలపర్‌ల లాంటి భాగస్వాముల యాప్‌లు, ప్రోడక్టులను మెరుగుపరచడంలో సహాయపడుతుంది.</translation>
 <translation id="3838085852053358637">ఎక్స్‌టెన్షన్‌ను లోడ్ చేయడం విఫలమైంది</translation>
 <translation id="3838486795898716504">మరిన్ని <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">సేవ్ చేసిన పాస్‌వర్డ్‌లను Google Password Managerకు జోడించండి</translation>
 <translation id="383891835335927981">సైట్‌లు ఏవీ దగ్గరకు లేదా దూరానికి జూమ్ చేయబడలేదు</translation>
 <translation id="3839509547554145593">మౌస్ స్క్రోల్ యాక్సిలరేషన్‌ను ఎనేబుల్ చేయండి</translation>
 <translation id="3839516600093027468">క్లిప్‌బోర్డ్‌ను చూడనీయకుండా ఎల్లప్పుడూ <ph name="HOST" />ని బ్లాక్ చేయండి</translation>
@@ -3866,6 +3865,7 @@
 <translation id="4340125850502689798">చెల్లని యూజర్‌నేమ్</translation>
 <translation id="4340515029017875942"><ph name="ORIGIN" />, <ph name="EXTENSION_NAME" />యాప్‌తో కమ్యూనికేట్ చేయాలనుకుంటోంది</translation>
 <translation id="4340799661701629185">నోటిఫికేషన్‌లను పంపడానికి సైట్‌లు అడగగలవు</translation>
+<translation id="4341280816303414009">మీ స్క్రీన్ రికార్డ్ కావచ్చు</translation>
 <translation id="4341577178275615435">క్యారెట్ బ్రౌజింగ్‌ను ఆన్ లేదా ఆఫ్ చేయడానికి, షార్ట్‌కట్ F7ను ఉపయోగించండి</translation>
 <translation id="4341905082470253054">TPM స్టేటస్‌ను చెక్ చేస్తోంది...</translation>
 <translation id="434198521554309404">వేగవంతమైనది. సురక్షితమైనది. శ్రమ లేనిది.</translation>
@@ -5689,6 +5689,7 @@
 <translation id="5979421442488174909"><ph name="LANGUAGE" />కు &amp;అనువదించు</translation>
 <translation id="5979469435153841984">పేజీలను బుక్‌మార్క్ చేయాలంటే, అడ్రస్‌ బార్‌లో ఉన్న నక్షత్రాన్ని క్లిక్ చేయండి</translation>
 <translation id="5981362776161841923">ఎక్స్‌టెన్షన్‌ను అనుమతించడానికి, కింద ఉన్న మీ ఆటోమేటిక్ సెట్టింగ్‌ను మార్చండి.</translation>
+<translation id="5982578203375898585">డౌన్‌లోడ్ చేయడం పూర్తయిన తర్వాత వాటిని చూడండి</translation>
 <translation id="5984222099446776634">ఇటీవల సందర్శించినవి</translation>
 <translation id="5985458664595100876">URL ఫార్మాట్ చెల్లదు. మద్దతు ఉన్న ఫార్మాట్‌లు \\server\share మరియు smb://server/share.</translation>
 <translation id="598810097218913399">కేటాయింపును తీసివేయండి</translation>
diff --git a/chrome/app/resources/generated_resources_th.xtb b/chrome/app/resources/generated_resources_th.xtb
index 430baac..b225b0c 100644
--- a/chrome/app/resources/generated_resources_th.xtb
+++ b/chrome/app/resources/generated_resources_th.xtb
@@ -388,7 +388,6 @@
 <translation id="1333965224356556482">ไม่อนุญาตให้เว็บไซต์ดูตำแหน่งของคุณ</translation>
 <translation id="1335282218035876586">Chromebook ของคุณจะไม่ได้รับการอัปเดตความปลอดภัยและซอฟต์แวร์อีกต่อไป เปลี่ยนไปใช้ Chromebook รุ่นใหม่เพื่อประสบการณ์การใช้งานที่ดีที่สุด</translation>
 <translation id="133535873114485416">วิธีป้อนข้อมูลที่ต้องการ</translation>
-<translation id="1335437153193710305">คุณเลือกโปรไฟล์ที่ต้องการดูรหัสผ่านได้</translation>
 <translation id="1335929031622236846">ลงทะเบียนอุปกรณ์ของคุณ</translation>
 <translation id="1336902454946927954">คีย์ความปลอดภัยล็อกอยู่เนื่องจากระบบจดจำลายนิ้วมือของคุณไม่ได้ โปรดป้อน PIN เพื่อปลดล็อก</translation>
 <translation id="1338631221631423366">กำลังจับคู่...</translation>
@@ -3313,7 +3312,6 @@
 <translation id="383669374481694771">นี่คือข้อมูลทั่วไปเกี่ยวกับอุปกรณ์และการใช้งานอุปกรณ์ (เช่น ระดับแบตเตอรี่ กิจกรรมในระบบและแอป ตลอดจนข้อผิดพลาด) ระบบจะใช้ข้อมูลเพื่อปรับปรุง Android และข้อมูลที่รวบรวมมาบางส่วนก็ยังจะช่วยให้แอปและพาร์ทเนอร์ของ Google เช่น นักพัฒนาแอป Android พัฒนาแอปและผลิตภัณฑ์ของตนให้ดีขึ้นด้วย</translation>
 <translation id="3838085852053358637">ไม่สามารถโหลดส่วนขยาย</translation>
 <translation id="3838486795898716504"><ph name="PAGE_TITLE" /> เพิ่มเติม</translation>
-<translation id="3838487810283346084">เพิ่มรหัสผ่านที่บันทึกไว้ลงในเครื่องมือจัดการรหัสผ่านบน Google</translation>
 <translation id="383891835335927981">ไม่มีการซูมเข้าหรือซูมออกเว็บไซต์ใดๆ</translation>
 <translation id="3839509547554145593">เปิดใช้การเร่งการเลื่อนเมาส์</translation>
 <translation id="3839516600093027468">บล็อก <ph name="HOST" /> ไม่ให้ดูคลิปบอร์ดเสมอ</translation>
diff --git a/chrome/app/resources/generated_resources_tr.xtb b/chrome/app/resources/generated_resources_tr.xtb
index 85ee4ed..c033d6f5 100644
--- a/chrome/app/resources/generated_resources_tr.xtb
+++ b/chrome/app/resources/generated_resources_tr.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Linux için en az <ph name="INSTALL_SIZE" /> alan olması önerilir. Boş alanı artırmak için cihazdan bazı dosyaları silin.</translation>
 <translation id="1038643060055067718">Satır sayısı:</translation>
 <translation id="1039337018183941703">Geçersiz veya bozuk dosya</translation>
+<translation id="1040761927998636252"><ph name="URL" /> için adsız yer işareti</translation>
 <translation id="1041175011127912238">Bu sayfa yanıt vermiyor</translation>
 <translation id="1041263367839475438">Kullanılabilir cihazlar</translation>
 <translation id="1042174272890264476">Bilgisayarınızda aynı zamanda yerleşik <ph name="SHORT_PRODUCT_NAME" /> RLZ kitaplığı da bulunur. RLZ, aramaları ve belirli bir promosyon kampanyasının sağladığı <ph name="SHORT_PRODUCT_NAME" /> kullanımını ölçmek için benzersiz olmayan ve kimlik bilgileri içermeyen bir etiket atar. Bu etiketler bazen <ph name="PRODUCT_NAME" /> içindeki Google Arama sorgularında görünür.</translation>
@@ -387,7 +388,6 @@
 <translation id="1333965224356556482">Sitelerin konumumu görmesine izin verme</translation>
 <translation id="1335282218035876586">Chromebook'unuz artık güvenlik ve yazılım güncellemeleri almıyor. En iyi deneyim için Chromebook'unuzu yükseltin.</translation>
 <translation id="133535873114485416">Tercih edilen giriş</translation>
-<translation id="1335437153193710305">Şifrelerini görmek istediğiniz profili seçebilirsiniz</translation>
 <translation id="1335929031622236846">Cihazınızı kaydettirin</translation>
 <translation id="1336902454946927954">Parmak iziniz tanınmadığı için güvenlik anahtarınız kilitlendi. Kilidini açmak için PIN'inizi girin.</translation>
 <translation id="1338631221631423366">Eşleniyor...</translation>
@@ -3310,7 +3310,6 @@
 <translation id="383669374481694771">Buradaki bilgiler (ör. pil seviyesi, sistem ve uygulama etkinliği, hatalar), bu cihazla ve cihazın nasıl kullanıldığıyla ilgili genel bilgilerdir. Bu veriler Android'i iyileştirmek için kullanılır. Toplu hale getirilen bazı bilgiler, Google uygulamalarının ve Android geliştiricileri gibi iş ortaklarına ait uygulama ve ürünlerin iyileştirilmesine de yardımcı olur.</translation>
 <translation id="3838085852053358637">Uzantı yüklenemedi</translation>
 <translation id="3838486795898716504">Diğer <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Kayıtlı şifreleri Google Şifre Yöneticisi'ne ekleyin</translation>
 <translation id="383891835335927981">Yakınlaştırılmış veya uzaklaştırılmış herhangi bir site yok</translation>
 <translation id="3839509547554145593">Fare kaydırma hızlandırmasını etkinleştir</translation>
 <translation id="3839516600093027468"><ph name="HOST" /> sitesinin panoyu görmesini her zaman engelle</translation>
diff --git a/chrome/app/resources/generated_resources_uk.xtb b/chrome/app/resources/generated_resources_uk.xtb
index ce4b7a3..968c35f 100644
--- a/chrome/app/resources/generated_resources_uk.xtb
+++ b/chrome/app/resources/generated_resources_uk.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Для Linux потрібно принаймні <ph name="INSTALL_SIZE" /> вільного місця. Щоб звільнити місце, видаліть файли з пристрою.</translation>
 <translation id="1038643060055067718">Рядків:</translation>
 <translation id="1039337018183941703">Недійсний або пошкоджений файл</translation>
+<translation id="1040761927998636252">Закладка без назви (<ph name="URL" />)</translation>
 <translation id="1041175011127912238">Ця сторінка не відповідає</translation>
 <translation id="1041263367839475438">Доступні пристрої</translation>
 <translation id="1042174272890264476">Ваш комп’ютер також має вбудовану бібліотеку RLZ у <ph name="SHORT_PRODUCT_NAME" />. Параметр RLZ призначає неунікальний тег, який не містить особисті дані, проте дозволяє вимірювати пошуки й користування <ph name="SHORT_PRODUCT_NAME" /> у рамках певної рекламної кампанії. Ці мітки інколи з’являються в пошукових запитах Google у <ph name="PRODUCT_NAME" />.</translation>
@@ -392,7 +393,6 @@
 <translation id="1333965224356556482">Заборонити сайтам переглядати ваше місцезнаходження</translation>
 <translation id="1335282218035876586">Ваш Chromebook більше не отримує оновлення системи безпеки й програмного забезпечення. Для оптимальної роботи оновіть Chromebook.</translation>
 <translation id="133535873114485416">Вибраний спосіб введення</translation>
-<translation id="1335437153193710305">Ви можете вибрати профіль, паролі якого потрібно переглянути</translation>
 <translation id="1335929031622236846">Зареєструйте свій пристрій</translation>
 <translation id="1336902454946927954">Ключ безпеки заблоковано, оскільки не вдалося розпізнати ваш відбиток пальця. Щоб розблокувати його, введіть PIN-код.</translation>
 <translation id="1338631221631423366">Підключення…</translation>
@@ -3330,7 +3330,6 @@
 <translation id="383669374481694771">Це загальна інформація про цей пристрій і його використання (як-от дані про рівень заряду акумулятора, систему, історію додатків та помилки). Ці відомості використовуватимуться, щоб покращити Android, а деякі зведені дані корисні для додатків і партнерів Google, як-от розробників Android.</translation>
 <translation id="3838085852053358637">Не вдалося завантажити розширення</translation>
 <translation id="3838486795898716504">Інші <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">Додавайте збережені паролі в Google Менеджер паролів</translation>
 <translation id="383891835335927981">Масштабування сайтів не змінено</translation>
 <translation id="3839509547554145593">Увімкнути прискорення прокрутки мишею</translation>
 <translation id="3839516600093027468">Завжди забороняти сайту <ph name="HOST" /> переглядати буфер обміну</translation>
diff --git a/chrome/app/resources/generated_resources_ur.xtb b/chrome/app/resources/generated_resources_ur.xtb
index d604658..be9e0f9 100644
--- a/chrome/app/resources/generated_resources_ur.xtb
+++ b/chrome/app/resources/generated_resources_ur.xtb
@@ -388,7 +388,6 @@
 <translation id="1333965224356556482">سائٹس کو اپنا مقام دیکھنے کی اجازت نہ دیں</translation>
 <translation id="1335282218035876586">‏اب آپ کے Chromebook کو سیکیورٹی اور سافٹ ویئر اپ ڈیٹس موصول نہیں ہو رہی ہیں۔ بہترین تجربے کیلئے اپنا Chromebook اپ گریڈ کریں۔</translation>
 <translation id="133535873114485416">ترجیحی ان پٹ</translation>
-<translation id="1335437153193710305">آپ اس پروفائل کا انتخاب کر سکتے ہیں جن سے آپ پاس ورڈز دیکھنا چاہتے ہیں</translation>
 <translation id="1335929031622236846">اپنے آلہ کا اندراج کرائيں</translation>
 <translation id="1336902454946927954">‏آپ کی سیکیورٹی کلید مقفل ہے کیونکہ آپ کے فنگر پرنٹ کی شناخت نہیں ہو سکی۔ اسے غیر مقفل کرنے کے لیے اپنا PIN درج کریں۔</translation>
 <translation id="1338631221631423366">جوڑا بنایا جا رہا ہے...</translation>
@@ -3316,7 +3315,6 @@
 <translation id="383669374481694771">‏یہ اس آلہ اور اس کے استعمال کیے جانے (جیسے بیٹری کی سطح، سسٹم، ایپ کی سرگرمی اور خرابیوں) کے بارے میں ایک عام معلومات ہے۔ Android کو بہتر بنانے کی خاطر ڈیٹا کا استعمال کیا جائے گا، اور کچھ مجموعی معلومات سے Google ایپس اور پارٹنرز، جیسے کہ Android ڈیولپرز، کو ان کی ایپس اور پروڈکٹس کو بہتر بنانے میں بھی مدد ملے گی۔</translation>
 <translation id="3838085852053358637">ایکسٹیشن لوڈ کرنے میں ناکام</translation>
 <translation id="3838486795898716504">مزید <ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">‏Google پاس ورڈ مینیجر میں محفوظ کردہ پاس ورڈز شامل کریں</translation>
 <translation id="383891835335927981">کسی بھی سائٹ کو زوم ان یا زوم آؤٹ نہیں کیا گیا ہے</translation>
 <translation id="3839509547554145593">ماؤس کے اسکرول ایکسلریٹر کو فعال کریں</translation>
 <translation id="3839516600093027468">کلپ بورڈ کو دیکھنے سے <ph name="HOST" /> کو ہمیشہ مسدود کریں</translation>
diff --git a/chrome/app/resources/generated_resources_uz.xtb b/chrome/app/resources/generated_resources_uz.xtb
index e6eec951..1cb529a 100644
--- a/chrome/app/resources/generated_resources_uz.xtb
+++ b/chrome/app/resources/generated_resources_uz.xtb
@@ -46,6 +46,7 @@
 <translation id="1038462104119736705">Linux uchun kamida <ph name="INSTALL_SIZE" /> joy ochilishi tavsiya etiladi. Boʻsh joyni koʻpaytirish uchun qurilma xotirasidan fayllarni oʻchiring.</translation>
 <translation id="1038643060055067718">Qatorlar:</translation>
 <translation id="1039337018183941703">Fayl yaroqsiz yoki shikastlangan</translation>
+<translation id="1040761927998636252"><ph name="URL" /> uchun nomsiz bukmark</translation>
 <translation id="1041175011127912238">Bu sahifa javob bermayapti.</translation>
 <translation id="1041263367839475438">Mavjud qurilmalar</translation>
 <translation id="1042174272890264476">Kompyuteringizda ichki o‘rnatilgan <ph name="SHORT_PRODUCT_NAME" /> RLZ kutubxonasi mavjud. RLZ mahsulotimiz(<ph name="SHORT_PRODUCT_NAME" />) reklama kompaniyalari natijalari asosidagi qidiruv so‘rovlari soni va mahsulotdan foydalanish statistikasini baholashimizga yordam beradigan ko‘rinmas va foydalanuvchini aniqlamaydigan yorliq tayinlaydi. Ushbu yorliqlar ba’zida mahsulotimiz (<ph name="PRODUCT_NAME" />) orqali bajarilgan qidiruv so‘rovlarida paydo bo‘lishi mumkin.</translation>
@@ -387,7 +388,6 @@
 <translation id="1333965224356556482">Saytlarga joylashuvingiz axborotini koʻrishni taqiqlash</translation>
 <translation id="1335282218035876586">Chromebook qurilmangiz endi xavfsizlikka oid va dasturiy yangilanishlar olmaydi. Barcha imkoniyatlardan foydalanish uchun Chromebookni yangilang.</translation>
 <translation id="133535873114485416">Asosiy matn kiritish usuli</translation>
-<translation id="1335437153193710305">Parollarini koʻrish uchun kerakli profilni tanlash mumkin</translation>
 <translation id="1335929031622236846">Qurilmangizni qayd qiling</translation>
 <translation id="1336902454946927954">Barmoq izingiz tasdiqlanmagani sababli elektron kalitingiz qulflandi. Uni qulfdan chiqarish uchun PIN kodingizni kiriting.</translation>
 <translation id="1338631221631423366">Ulanmoqda...</translation>
@@ -3314,7 +3314,6 @@
 <translation id="383669374481694771">Bunga qurilma va undan qanday foydalanish haqidagi umumiy axborot, masalan, batareya quvvati darajasi, tizim va ilovalardan qanday foydalanishingiz, ishdan chiqish hisobotlari kiradi. Ayrim toʻplangan maʼlumotlar Android dasturchilar kabi hamkorlarimizga ham oʻz ilovalari va mahsulotlarini yanada yaxshilashga yordam beradi.</translation>
 <translation id="3838085852053358637">Kengaytma yuklanmadi</translation>
 <translation id="3838486795898716504"><ph name="PAGE_TITLE" /> sarlavhasiga ega boshqa sahifalar</translation>
-<translation id="3838487810283346084">Saqlangan parollarni Google Parollar menejeriga kiritish</translation>
 <translation id="383891835335927981">Hech qanday sayt uchun masshtab tayinlanmagan</translation>
 <translation id="3839509547554145593">Sichqonchada tez varaqlash funksiyasini yoqish</translation>
 <translation id="3839516600093027468"><ph name="HOST" /> saytiga klipbordni ko‘rishga ruxsat har doim taqiqlansin</translation>
diff --git a/chrome/app/resources/generated_resources_vi.xtb b/chrome/app/resources/generated_resources_vi.xtb
index 680c3aa..adaba38 100644
--- a/chrome/app/resources/generated_resources_vi.xtb
+++ b/chrome/app/resources/generated_resources_vi.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">Không cho phép trang web xem thông tin vị trí của bạn</translation>
 <translation id="1335282218035876586">Chromebook của bạn sẽ không nhận được các bản cập nhật bảo mật và phần mềm nữa. Hãy nâng cấp Chromebook để có trải nghiệm tốt nhất.</translation>
 <translation id="133535873114485416">Phương thức nhập ưu tiên</translation>
-<translation id="1335437153193710305">Bạn có thể chọn hồ sơ mà bạn muốn xem mật khẩu</translation>
 <translation id="1335929031622236846">Đăng ký thiết bị của bạn</translation>
 <translation id="1336902454946927954">Khóa bảo mật của bạn đã bị khóa do hệ thống không nhận dạng được vân tay của bạn. Để mở khóa, hãy nhập mã PIN của bạn.</translation>
 <translation id="1338631221631423366">Đang ghép nối...</translation>
@@ -3330,7 +3329,6 @@
 <translation id="383669374481694771">Đây là thông tin chung về thiết bị này và cách bạn sử dụng thiết bị (như mức pin, hoạt động của ứng dụng và hệ thống cũng như các lỗi). Dữ liệu sẽ dùng để cải thiện Android và một số thông tin tổng hợp cũng sẽ giúp các ứng dụng và đối tác của Google, chẳng hạn như nhà phát triển Android, cải thiện ứng dụng và sản phẩm của họ.</translation>
 <translation id="3838085852053358637">Không tải được tiện ích</translation>
 <translation id="3838486795898716504"><ph name="PAGE_TITLE" /> khác</translation>
-<translation id="3838487810283346084">Thêm mật khẩu đã lưu vào Trình quản lý mật khẩu của Google</translation>
 <translation id="383891835335927981">Không có trang web nào được phóng to hoặc thu nhỏ</translation>
 <translation id="3839509547554145593">Bật tính năng tăng tốc độ cuộn chuột</translation>
 <translation id="3839516600093027468">Luôn chặn <ph name="HOST" /> xem bảng nhớ tạm</translation>
diff --git a/chrome/app/resources/generated_resources_zh-CN.xtb b/chrome/app/resources/generated_resources_zh-CN.xtb
index 53c39de0..3ce960d9 100644
--- a/chrome/app/resources/generated_resources_zh-CN.xtb
+++ b/chrome/app/resources/generated_resources_zh-CN.xtb
@@ -389,7 +389,6 @@
 <translation id="1333965224356556482">不允许网站查看您所在的位置</translation>
 <translation id="1335282218035876586">您的 Chromebook 将不会再收到安全更新和软件更新。请升级您的 Chromebook 以获得最佳体验。</translation>
 <translation id="133535873114485416">首选输入模式</translation>
-<translation id="1335437153193710305">您可以选择要查看密码的个人资料</translation>
 <translation id="1335929031622236846">注册您的设备</translation>
 <translation id="1336902454946927954">您的安全密钥已被锁定,因为无法识别您的指纹。若要解锁,请输入 PIN 码。</translation>
 <translation id="1338631221631423366">正在配对…</translation>
@@ -3306,7 +3305,6 @@
 <translation id="383669374481694771">这是关于此设备及其使用情况(例如电池电量、系统与应用活动以及错误)的一般信息。我们会使用这些数据来改善 Android,部分汇总信息还会有助于改善 Google 应用,并会协助我们的合作伙伴(例如 Android 开发者)改善其应用和产品。</translation>
 <translation id="3838085852053358637">未能成功加载扩展程序</translation>
 <translation id="3838486795898716504">更多“<ph name="PAGE_TITLE" />”</translation>
-<translation id="3838487810283346084">将已保存的密码添加到 Google 密码管理工具</translation>
 <translation id="383891835335927981">未对任何网站设置缩放级别</translation>
 <translation id="3839509547554145593">启用鼠标滚屏加速</translation>
 <translation id="3839516600093027468">始终禁止 <ph name="HOST" /> 查看剪贴板</translation>
@@ -6942,7 +6940,7 @@
 <translation id="7123302939607518173">如果您认为与某项兴趣或某个网站相关的广告对您有用,可以添加该兴趣或网站。</translation>
 <translation id="7124013154139278147">为“上一项”操作分配开关</translation>
 <translation id="7124712201233930202">不符合贵组织的政策</translation>
-<translation id="7125029162161377569">Privacy Sandbox 试用计划推出后,网站既能减少使用您的信息,又能提供同样出色的浏览体验。这意味着您的隐私会受到更好的保护,而且跨网站跟踪也会减少。一旦新的功能可供试用,我们即会添加相应功能。</translation>
+<translation id="7125029162161377569">Privacy Sandbox 试用版推出后,网站既能减少使用您的信息,又能提供同样出色的浏览体验。这意味着您的隐私会受到更好的保护,而且跨网站跟踪也会减少。一旦新的功能可供试用,我们即会添加相应功能。</translation>
 <translation id="7125148293026877011">删除 Crostini</translation>
 <translation id="7127980134843952133">下载记录</translation>
 <translation id="7128151990937044829">当通知处于屏蔽状态时在地址栏中显示“已屏蔽”图标</translation>
diff --git a/chrome/app/resources/generated_resources_zh-HK.xtb b/chrome/app/resources/generated_resources_zh-HK.xtb
index 94c72f6..83e7359 100644
--- a/chrome/app/resources/generated_resources_zh-HK.xtb
+++ b/chrome/app/resources/generated_resources_zh-HK.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">不允許網站查看您的位置</translation>
 <translation id="1335282218035876586">Chromebook 不會再收到安全和軟件更新。請改用新 Chromebook,以獲得最佳使用體驗。</translation>
 <translation id="133535873114485416">偏好的輸入模式</translation>
-<translation id="1335437153193710305">您可選擇要查看密碼的個人檔案</translation>
 <translation id="1335929031622236846">註冊您的裝置</translation>
 <translation id="1336902454946927954">無法辨識您的指紋,因此安全密鑰已被鎖定。如要解鎖,請輸入您的 PIN。</translation>
 <translation id="1338631221631423366">正在配對…</translation>
@@ -3329,7 +3328,6 @@
 <translation id="383669374481694771">這個選項會提供此裝置的一般資料和使用情况 (例如電量、系統及應用程式活動和錯誤)。這些資料將會用來改善 Android。部分彙整資料還能協助 Google 應用程式和合作夥伴 (例如 Android 開發人員) 改良應用程式和產品。</translation>
 <translation id="3838085852053358637">無法載入擴充程式</translation>
 <translation id="3838486795898716504">更多<ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">將已儲存的密碼加入「Google 密碼管理工具」</translation>
 <translation id="383891835335927981">沒有已放大或縮小的網站</translation>
 <translation id="3839509547554145593">啟用滑鼠捲動加速功能</translation>
 <translation id="3839516600093027468">一律禁止 <ph name="HOST" /> 查看剪貼簿</translation>
diff --git a/chrome/app/resources/generated_resources_zh-TW.xtb b/chrome/app/resources/generated_resources_zh-TW.xtb
index 14608f8..21114b7 100644
--- a/chrome/app/resources/generated_resources_zh-TW.xtb
+++ b/chrome/app/resources/generated_resources_zh-TW.xtb
@@ -388,7 +388,6 @@
 <translation id="1333965224356556482">禁止網站查看你的位置資訊</translation>
 <translation id="1335282218035876586">你的 Chromebook 不會再收到安全性和軟體更新。如要獲得最佳體驗,請改用新款 Chromebook。</translation>
 <translation id="133535873114485416">偏好的輸入來源</translation>
-<translation id="1335437153193710305">你可以選擇要查看密碼的設定檔</translation>
 <translation id="1335929031622236846">註冊你的裝置</translation>
 <translation id="1336902454946927954">系統無法辨識你的指紋,因此你的安全金鑰已遭到鎖定。如要解鎖,請輸入你的 PIN 碼。</translation>
 <translation id="1338631221631423366">配對中...</translation>
@@ -2345,7 +2344,7 @@
 <translation id="2979639724566107830">於新視窗中開啟</translation>
 <translation id="2981113813906970160">顯示大型滑鼠游標</translation>
 <translation id="2981293774053328982">這個檔案含有惡意軟體,可能會入侵你的社群網路或個人帳戶</translation>
-<translation id="2983102365694924129">根據你在網站上的活動獨家推薦。這項設定已關閉。</translation>
+<translation id="2983102365694924129">以你的網站活動做為依據。這項設定已關閉。</translation>
 <translation id="2983373101216420412">充電盒電量為 <ph name="PERCENTAGE" />%。</translation>
 <translation id="2985348301114641460">要傳送「<ph name="EXTENSION_NAME" />」的安裝要求給系統管理員嗎?</translation>
 <translation id="2987620471460279764">從其他裝置分享的文字</translation>
@@ -2410,7 +2409,7 @@
 <translation id="3024374909719388945">使用 24 小時制時鐘</translation>
 <translation id="3025174326431589540">{COUNT,plural, =0{未儲存密碼}=1{已檢查 {COUNT} 個網站的密碼}other{已檢查 {COUNT} 個網站和應用程式的密碼}}</translation>
 <translation id="3027296729579831126">開啟鄰近分享功能</translation>
-<translation id="3027644380269727216">根據你在網站上的活動獨家推薦。這項設定已開啟。</translation>
+<translation id="3027644380269727216">以你的網站活動做為依據。這項設定已開啟。</translation>
 <translation id="3029276696788198026">不使用預先載入模式</translation>
 <translation id="3029466929721441205">在檔案櫃中顯示觸控筆工具</translation>
 <translation id="3029808567601324798">鎖定時間</translation>
@@ -3313,7 +3312,6 @@
 <translation id="383669374481694771">這個頁面會顯示這部裝置和裝置使用情況的一般資訊 (例如電池電量、系統和應用程式活動,以及錯誤資訊)。這些資料將用於改善 Android,且部分匯總資訊還能協助 Google 應用程式和合作夥伴 (例如 Android 開發人員) 提高應用程式和產品的服務品質。</translation>
 <translation id="3838085852053358637">無法載入擴充功能</translation>
 <translation id="3838486795898716504">更多<ph name="PAGE_TITLE" /></translation>
-<translation id="3838487810283346084">將已儲存的密碼加入 Google 密碼管理工具</translation>
 <translation id="383891835335927981">未針對任何網站設定縮放等級</translation>
 <translation id="3839509547554145593">啟用滑鼠捲動加速功能</translation>
 <translation id="3839516600093027468">一律禁止 <ph name="HOST" /> 讀取剪貼簿</translation>
@@ -3482,7 +3480,7 @@
 <translation id="3979748722126423326">啟用 <ph name="NETWORKDEVICE" /></translation>
 <translation id="3981058120448670012">以「<ph name="DEVICE_NAME" />」的名稱向附近的裝置顯示 <ph name="REMAINING_TIME" />...</translation>
 <translation id="3981760180856053153">輸入的儲存類型無效。</translation>
-<translation id="3981902534690264083">廣告客戶可以瞭解廣告成效</translation>
+<translation id="3981902534690264083">廣告商可以瞭解廣告成效</translation>
 <translation id="3982375475032951137">只要簡單幾個步驟就能完成瀏覽器設定</translation>
 <translation id="3983400541576569538">某些應用程式的資料可能會遺失</translation>
 <translation id="3983586614702900908">製造商不明的裝置</translation>
@@ -4911,7 +4909,7 @@
 <translation id="5299109548848736476">不追蹤</translation>
 <translation id="5299558715747014286">查看及管理分頁群組</translation>
 <translation id="5300287940468717207">要重設網站權限嗎?</translation>
-<translation id="5300426565656326054">以瀏覽器為主的廣告個人化</translation>
+<translation id="5300426565656326054">根據瀏覽器的使用記錄放送個人化廣告</translation>
 <translation id="5300589172476337783">顯示</translation>
 <translation id="5300719150368506519">將你造訪的網頁網址傳送給 Google</translation>
 <translation id="5301751748813680278">正在以訪客身分登入。</translation>
@@ -7214,7 +7212,7 @@
 <translation id="7387273928653486359">可以接受</translation>
 <translation id="7387951778417998929">如要使用非系統預設的搜尋引擎,請在網址列中輸入相應的快捷字詞,然後按下你慣用的鍵盤快速鍵。你也可以在這裡變更你的預設搜尋引擎。</translation>
 <translation id="7388209873137778229">只顯示支援的裝置。</translation>
-<translation id="7388615499319468910">網站和廣告客戶可以瞭解廣告成效。這項設定已關閉。</translation>
+<translation id="7388615499319468910">網站和廣告商可以瞭解廣告成效。這項設定已關閉。</translation>
 <translation id="7392118418926456391">病毒掃描失敗</translation>
 <translation id="7392915005464253525">重新開啟已關閉視窗(&amp;E)</translation>
 <translation id="7393073300870882456">{COUNT,plural, =1{已複製 1 個項目}other{已複製 {COUNT} 個項目}}</translation>
@@ -7294,7 +7292,7 @@
 <translation id="7453467225369441013">大多數網站都會將你登出,但系統並不會將你登出 Google 帳戶。</translation>
 <translation id="7454548535253569100">入口網站:<ph name="SUBFRAME_SITE" /></translation>
 <translation id="7455730275746867420">管理其他容器</translation>
-<translation id="7455988709578031708">根據你的瀏覽記錄獨家推薦。這項設定已開啟。</translation>
+<translation id="7455988709578031708">以你的瀏覽記錄做為依據。這項設定已開啟。</translation>
 <translation id="7456142309650173560">開發人員版</translation>
 <translation id="7456774706094330779">延伸預先載入模式</translation>
 <translation id="7456847797759667638">開啟位置...</translation>
@@ -8684,7 +8682,7 @@
 <translation id="8665180165765946056">備份完成</translation>
 <translation id="866611985033792019">信任這個用於識別電子郵件使用者的憑證</translation>
 <translation id="8666321716757704924">已重新授權給 <ph name="WEBSITE" /></translation>
-<translation id="8666759526542103597">關於以瀏覽器為主的廣告個人化</translation>
+<translation id="8666759526542103597">「根據瀏覽器的使用記錄放送個人化廣告」的相關說明</translation>
 <translation id="8667261224612332309">你有密碼修改建議</translation>
 <translation id="8667328578593601900"><ph name="FULLSCREEN_ORIGIN" /> 已顯示為全螢幕,並且停用了滑鼠游標。</translation>
 <translation id="8667760277771450375">我們正在開發限制跨網站追蹤的方法,同時讓網站能夠防範廣告垃圾內容和欺詐行為。</translation>
@@ -9188,12 +9186,12 @@
 <translation id="9095364055741191097">無法復原本機資料</translation>
 <translation id="909554839118732438">關閉無痕模式</translation>
 <translation id="9096776523567481218">未安裝在本機</translation>
-<translation id="9099220545925418560">根據你的瀏覽記錄獨家推薦。這項設定已關閉。</translation>
+<translation id="9099220545925418560">以你的瀏覽記錄做為依據。這項設定已關閉。</translation>
 <translation id="9100416672768993722">如要切換到上次使用的輸入法,請按下 <ph name="BEGIN_SHORTCUT" /><ph name="BEGIN_CTRL" />Ctrl<ph name="END_CTRL" /><ph name="SEPARATOR" /><ph name="BEGIN_SPACE" />Space<ph name="END_SPACE" /><ph name="END_SHORTCUT" /> 鍵</translation>
 <translation id="9100765901046053179">進階設定</translation>
 <translation id="9101691533782776290">啟動應用程式</translation>
 <translation id="9102610709270966160">啟用擴充功能</translation>
-<translation id="9102864637938129124">網站和廣告客戶可以瞭解廣告成效。這項設定已開啟。</translation>
+<translation id="9102864637938129124">網站和廣告商可以瞭解廣告成效。這項設定已開啟。</translation>
 <translation id="9103479157856427471">放大的螢幕畫面會追蹤鍵盤焦點</translation>
 <translation id="9103868373786083162">按下即可返回,內容選單會顯示歷史記錄</translation>
 <translation id="9108035152087032312">命名視窗...(&amp;W)</translation>
diff --git a/chrome/app/resources/generated_resources_zu.xtb b/chrome/app/resources/generated_resources_zu.xtb
index ffa6c9d5..e2156805 100644
--- a/chrome/app/resources/generated_resources_zu.xtb
+++ b/chrome/app/resources/generated_resources_zu.xtb
@@ -391,7 +391,6 @@
 <translation id="1333965224356556482">Ungavumeli amasayithi abone indawo yakho</translation>
 <translation id="1335282218035876586">I-Chromebook yakho ayisatholi izibuyekezo zokuvikeleka nesofthiwe. Thuthukisa i-Chromebook yakho ukuze uthole ukuzizwisa okungcono kakhulu.</translation>
 <translation id="133535873114485416">Okokufaka okuncamelayo</translation>
-<translation id="1335437153193710305">Ungakhetha iphrofayela ofuna ukubona kuyo amaphasiwedi</translation>
 <translation id="1335929031622236846">Bhalisa idivayisi yakho</translation>
 <translation id="1336902454946927954">Ukhiye wakho wokuqinisekisa ubunikazi ukhiyiwe ngoba isigxivizo somunwe asaziwanga. Ukuze uwuvule, faka iphinikhodi yakho.</translation>
 <translation id="1338631221631423366">Iyabhanqa…</translation>
@@ -3141,6 +3140,7 @@
 <translation id="369489984217678710">Amaphasiwedi nenye idatha yokungena ngemvume</translation>
 <translation id="369522892592566391">{NUM_FILES,plural, =0{Ukuhlola ezokuphepha kwenziwe. Idatha yakho izolayishwa}=1{Ukuhlola ezokuphepha kwenziwe. Ifayela lakho lizolayishwa.}one{Ukuhlola ezokuphepha kwenziwe. Amafayela akho azolayishwa}other{Ukuhlola ezokuphepha kwenziwe. Amafayela akho azolayishwa}}</translation>
 <translation id="3696817060563289264">Amafayela okubona umbhalo adawunilodiwe</translation>
+<translation id="3697716475445175867">kugcine ukuvulwa</translation>
 <translation id="3698471669415859717">Ukubuyekeza kuqedile</translation>
 <translation id="3698825735945432002">Uhlobo lokuhlunga</translation>
 <translation id="3699624789011381381">Ikheli le-imeyili</translation>
@@ -3329,7 +3329,6 @@
 <translation id="383669374481694771">Lolu ulwazi oluvamile mayelana nedivayisi yakho nokuthi isetshenziswa kanjani (njengeleveli yebhethri, umsebenzi wesistimu nohlelo lokusebenza, namaphutha). Idatha izosetshenziselwa ukuthuthukisa i-Android, nolunye ulwazi olulinganiselwe luzophinda lusize izinhlelo zokusebenza ze-Google nozakwethu, abafana nonjiniyela be-Android, benze izinhlelo zabo zokusebenza nemikhiqizo ibe ngcono.</translation>
 <translation id="3838085852053358637">Yehlulekile ukulayisha isandiso</translation>
 <translation id="3838486795898716504">I-<ph name="PAGE_TITLE" /> eningi</translation>
-<translation id="3838487810283346084">Engeza amaphasiwedi alondoloziwe Kumphathi Wephasiwedi Ye-Google</translation>
 <translation id="383891835335927981">Awekho amasayithi asondezwe noma ahlehliselwe isithombe</translation>
 <translation id="3839509547554145593">Nika amandla ukusheshisa ukuskrola kwegundane</translation>
 <translation id="3839516600093027468">Hlala uvimbela u-<ph name="HOST" /> ekuboneni ibhodi lokunamathisela</translation>
@@ -6372,6 +6371,7 @@
 <translation id="6596816719288285829">Ikheli le-IP</translation>
 <translation id="6597017209724497268">Amasampuli</translation>
 <translation id="6597331566371766302">Izandiso ezilandelayo zivinjelwe ngumlawuli wakho:</translation>
+<translation id="659894938503552850">okusha kakhulu</translation>
 <translation id="6601262427770154296">Phatha izichazamazwi zomsebenzi</translation>
 <translation id="6601612474695404578">Amanye amasayithi asebenzisa amakhukhi enkampani yangaphandle ukuze alayishe amakhasi awo. Uma isayithi lingasebenzi, ungazama ukuvumela amakhukhi.</translation>
 <translation id="6602937173026466876">Finyelela amaphrinta akho</translation>
@@ -8153,6 +8153,7 @@
 <translation id="8161293209665121583">Imodi yomfundi yamakhasi ewebhu</translation>
 <translation id="8161604891089629425">Ifonti yohlaka</translation>
 <translation id="8162984717805647492">{NUM_TABS,plural, =1{Hambisa ithebhu kuwindi elisha}one{Hambisa amathebhu kuwindi elisha}other{Hambisa amathebhu kuwindi elisha}}</translation>
+<translation id="8163708146810922598">okudala kakhulu</translation>
 <translation id="8165997195302308593">Ukudlulisela ngembobo ye-Crostini</translation>
 <translation id="816704878106051517">{COUNT,plural, =1{inombolo yefoni}one{izinombolo zefoni ezingu-#}other{izinombolo zefoni ezingu-#}}</translation>
 <translation id="8168071266284693455">Amabhukhimakhi akho, amaphasiwedi, umlando, nokunye kuyavunyelaniswa kuwo wonke amadivayisi akho</translation>
@@ -8667,6 +8668,7 @@
 <translation id="8637688295594795546">Ukubuyekezwa kwesistimu kuyatholakala. Ilungiselela ukulanda…</translation>
 <translation id="8639047128869322042">Ihlola isofthiwe eyingozi...</translation>
 <translation id="8639635302972078117">Thumela idatha yokusetshenziswa neyokuxilonga. Le divayisi manje ithumela ngokuzenzakalela idatha yokuxilonga, yedivayisi, neyokusetshenziswa kwedatha ku-Google. Lokhu ngeke kusetshenziselwe ukukhomba ingane yakho futhi kuzosiza ukuzinza kwesistimu nokohlelo lokusebenza nokunye ukuthuthukiswa. Enye idatha izophinda isize izinhlelo zokusebenza ze-Google nozakwethu, abafana nonjiniyela be-Android. Uma isilungiselelo esingeziwe sewebhu nesohlelo lokusebenza sivulelwe ingane yakho, le datha ingalondolozwa ku-akhawunti yakhe ye-Google.</translation>
+<translation id="8640575194957831802">Kugcine ukuvulwa</translation>
 <translation id="8642900771896232685">2 amasekhondi</translation>
 <translation id="8642947597466641025">Yenza umbhalo ube mkhulu</translation>
 <translation id="8643403533759285912">Sula Iqembu</translation>
diff --git a/chrome/app/resources/google_chrome_strings_es-419.xtb b/chrome/app/resources/google_chrome_strings_es-419.xtb
index 0e011ae..3158cb2 100644
--- a/chrome/app/resources/google_chrome_strings_es-419.xtb
+++ b/chrome/app/resources/google_chrome_strings_es-419.xtb
@@ -214,7 +214,7 @@
 <translation id="4970761609246024540">Te damos la bienvenida a los perfiles de Chrome</translation>
 <translation id="4970880042055371251">Versión de ChromeOS</translation>
 <translation id="4970947549776831107">Chrome bloqueó este archivo porque este tipo de archivo es peligroso</translation>
-<translation id="4990567037958725628">Google Chrome Canario</translation>
+<translation id="4990567037958725628">Google Chrome Canary</translation>
 <translation id="5064155331105009416">{COUNT,plural, =1{El administrador cierra Chrome automáticamente si no lo usas durante 1 minuto. Se borran los datos de navegación. Esto puede incluir el historial, los datos de Autocompletar y las descargas.}other{El administrador cierra Chrome automáticamente si no lo usas durante # minutos. Se borran los datos de navegación. Esto puede incluir el historial, los datos de Autocompletar y las descargas.}}</translation>
 <translation id="5098668839038261629">Si activas esta opción, saldrás de Chrome</translation>
 <translation id="5132929315877954718">Descubre aplicaciones, juegos, extensiones y temas geniales para Google Chrome.</translation>
diff --git a/chrome/app/resources/google_chrome_strings_zh-TW.xtb b/chrome/app/resources/google_chrome_strings_zh-TW.xtb
index 9bf5a7d6..0d7230e 100644
--- a/chrome/app/resources/google_chrome_strings_zh-TW.xtb
+++ b/chrome/app/resources/google_chrome_strings_zh-TW.xtb
@@ -111,7 +111,7 @@
 <translation id="2929907241665500097">發生錯誤,Chrome 未能更新。<ph name="BEGIN_LINK" />請修正 Chrome 更新問題與更新失敗項目。<ph name="END_LINK" /></translation>
 <translation id="2969728957078202736"><ph name="PAGE_TITLE" /> - 網路登入 - Chrome</translation>
 <translation id="3019382870990049182">重新啟動以更新 ChromeOS Flex</translation>
-<translation id="303514781271618814">Chrome 正在探索新功能,讓網站能在使用較少資料的情況下提供相同的瀏覽體驗</translation>
+<translation id="303514781271618814">Chrome 團隊正在研究新功能,設法讓網站減少存取個人資訊的情況,同時讓使用者享有相同的瀏覽體驗</translation>
 <translation id="3037838751736561277">Google Chrome 正在背景模式中執行。</translation>
 <translation id="3038232873781883849">正在等待安裝...</translation>
 <translation id="3059710691562604940">安全瀏覽功能已停用。Chrome 建議啟用這項功能。</translation>
@@ -164,7 +164,7 @@
 <translation id="4035053306113201399">Chrome OS 必須重新啟動,才能套用更新。</translation>
 <translation id="4050175100176540509">最新版本包含重要的安全性改善與新功能。</translation>
 <translation id="4053720452172726777">自訂及管理 Google Chrome</translation>
-<translation id="4106587138345390261">Chrome 正在探索新功能,讓網站在存取較少個人資訊的情況下,仍能提供相同的瀏覽體驗</translation>
+<translation id="4106587138345390261">Chrome 團隊正在研究新功能,設法讓網站減少存取個人資訊的情況,同時讓使用者享有相同的瀏覽體驗。</translation>
 <translation id="4110895483821904099">設定新的 Chrome 設定檔</translation>
 <translation id="4147555960264124640">你已登入管理化環境下的帳戶,並將管理控制權授予你的 Chrome 設定檔。你的 Chrome 資料 (例如應用程式、書籤、記錄、密碼和其他設定) 均將永久與 <ph name="USER_NAME" /> 建立關聯。你可以透過 Google 帳戶資訊主頁刪除這些資料,但你無法將這些資料與其他帳戶建立關聯。<ph name="LEARN_MORE" /></translation>
 <translation id="4148957013307229264">安裝中...</translation>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index df1cb312..76fb880 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -56,6 +56,18 @@
     <message name="IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_DESCRIPTION" desc="Explanatory text for the link to the 'Get the most out of Chrome' page.">
       This guide helps you understand your choices, so that Chrome works the way you want to
     </message>
+    <message name="IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_INTRO" desc="Introduction to the 'Get the most out of Chrome' page.">
+      This guide helps you understand important choices you have as you use Chrome. And it helps you make those choices, so that Chrome works the way you want it to.
+    </message>
+    <message name="IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_MORE_THAN_A_BROWSER" desc="Title of the 'More than a browser' section of the 'Get the most out of Chrome' page.">
+      More than a browser
+    </message>
+    <message name="IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_YOUR_DATA_IN_CHROME" desc="Title of the 'Your data in Chrome' section of the 'Get the most out of Chrome' page.">
+      Your data in Chrome
+    </message>
+    <message name="IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_BEYOND_COOKIES" desc="Title of the 'Beyond cookies' section of the 'Get the most out of Chrome' page.">
+      Beyond cookies
+    </message>
   </if>
   <if expr="is_macosx">
     <message name="IDS_ABOUT_CHROME_AUTOUPDATE_ALL" desc="The 'Automatically update Chrome for all users.' button in the About window.  Mac-only.">
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_BEYOND_COOKIES.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_BEYOND_COOKIES.png.sha1
new file mode 100644
index 0000000..cc1c341
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_BEYOND_COOKIES.png.sha1
@@ -0,0 +1 @@
+9280e234ecb392af8a19ea800eba09c176ac4109
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_INTRO.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_INTRO.png.sha1
new file mode 100644
index 0000000..cc1c341
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_INTRO.png.sha1
@@ -0,0 +1 @@
+9280e234ecb392af8a19ea800eba09c176ac4109
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_MORE_THAN_A_BROWSER.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_MORE_THAN_A_BROWSER.png.sha1
new file mode 100644
index 0000000..cc1c341
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_MORE_THAN_A_BROWSER.png.sha1
@@ -0,0 +1 @@
+9280e234ecb392af8a19ea800eba09c176ac4109
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_YOUR_DATA_IN_CHROME.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_YOUR_DATA_IN_CHROME.png.sha1
new file mode 100644
index 0000000..cc1c341
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_YOUR_DATA_IN_CHROME.png.sha1
@@ -0,0 +1 @@
+9280e234ecb392af8a19ea800eba09c176ac4109
\ No newline at end of file
diff --git a/chrome/app/vector_icons/tab_groups_sync.icon b/chrome/app/vector_icons/tab_groups_sync.icon
index a5c4c8b..8353209 100644
--- a/chrome/app/vector_icons/tab_groups_sync.icon
+++ b/chrome/app/vector_icons/tab_groups_sync.icon
@@ -2,40 +2,32 @@
 // Use of this source code is governed by a BSD-style license that can be

 // found in the LICENSE file.

 

-MOVE_TO, 8.35f, 40,

-R_V_LINE_TO, -3,

-R_H_LINE_TO, 6.5f,

-R_LINE_TO, -0.75f, -0.6f,

-R_QUADRATIC_TO, -3.2f, -2.55f, -4.65f, -5.55f,

-R_QUADRATIC_TO, -1.45f, -3, -1.45f, -6.7f,

-R_QUADRATIC_TO, 0, -5.3f, 3.13f, -9.52f,

-QUADRATIC_TO, 14.25f, 10.4f, 19.35f, 8.8f,

-R_V_LINE_TO, 3.1f,

-R_QUADRATIC_TO, -3.75f, 1.45f, -6.05f, 4.83f,

-QUADRATIC_TO_SHORTHAND, 11, 24.15f,

-R_QUADRATIC_TO, 0, 3.15f, 1.18f, 5.48f,

-R_QUADRATIC_TO, 1.18f, 2.33f, 3.18f, 4.03f,

-R_LINE_TO, 1.5f, 1.05f,

-R_V_LINE_TO, -6.2f,

-R_H_LINE_TO, 3,

-V_LINE_TO, 40,

+CANVAS_DIMENSIONS, 16,

+MOVE_TO, 2, 8,

+CUBIC_TO, 2, 9.8f, 2.8f, 11.4f, 4.05f, 12.5f,

+H_LINE_TO, 2.5f,

+V_LINE_TO, 14,

+H_LINE_TO, 6.5f,

+V_LINE_TO, 10,

+H_LINE_TO, 5,

+V_LINE_TO, 11.32f,

+CUBIC_TO, 4.09f, 10.5f, 3.5f, 9.32f, 3.5f, 8,

+CUBIC_TO, 3.5f, 6.05f, 4.76f, 4.4f, 6.5f, 3.78f,

+V_LINE_TO, 2.2f,

+CUBIC_TO, 3.91f, 2.86f, 2, 5.21f, 2, 8,

 CLOSE,

-R_MOVE_TO, 20.35f, -0.75f,

-V_LINE_TO, 36.1f,

-R_QUADRATIC_TO, 3.8f, -1.45f, 6.05f, -4.82f,

-QUADRATIC_TO_SHORTHAND, 37, 23.85f,

-R_QUADRATIC_TO, 0, -2.4f, -1.17f, -4.87f,

-QUADRATIC_TO_SHORTHAND, 32.75f, 14.6f,

-R_LINE_TO, -1.45f, -1.3f,

-R_V_LINE_TO, 6.2f,

-R_H_LINE_TO, -3,

-V_LINE_TO, 8,

-R_H_LINE_TO, 11.5f,

-R_V_LINE_TO, 3,

-R_H_LINE_TO, -6.55f,

-R_LINE_TO, 0.75f, 0.7f,

-R_QUADRATIC_TO, 3, 2.8f, 4.5f, 6,

-R_QUADRATIC_TO, 1.5f, 3.2f, 1.5f, 6.15f,

-R_QUADRATIC_TO, 0, 5.3f, -3.1f, 9.55f,

-R_QUADRATIC_TO, -3.1f, 4.25f, -8.2f, 5.85f,

-CLOSE

+NEW_PATH,

+MOVE_TO, 11.95f, 3.5f,

+H_LINE_TO, 13.5f,

+V_LINE_TO, 2,

+H_LINE_TO, 9.5f,

+V_LINE_TO, 6,

+H_LINE_TO, 11,

+V_LINE_TO, 4.68f,

+CUBIC_TO, 11.91f, 5.5f, 12.5f, 6.67f, 12.5f, 8,

+CUBIC_TO, 12.5f, 9.95f, 11.24f, 11.6f, 9.5f, 12.22f,

+V_LINE_TO, 13.8f,

+CUBIC_TO, 12.09f, 13.13f, 14, 10.79f, 14, 8,

+CUBIC_TO, 14, 6.2f, 13.2f, 4.6f, 11.95f, 3.5f,

+CLOSE,

+NEW_PATH

diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index ac67bae..5a8c567 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2373,6 +2373,7 @@
     "//printing/buildflags",
     "//rlz/buildflags",
     "//services/audio/public/cpp",
+    "//services/audio/public/cpp:audio_features",
     "//services/cert_verifier:lib",
     "//services/data_decoder/public/cpp",
     "//services/device/public/cpp:device_features",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index d6aa71d..67a75b0 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1526,23 +1526,20 @@
          std::size(kOmniboxRichAutocompletionAggressive4), nullptr},
 };
 
-const FeatureEntry::FeatureParam
-    kOmniboxMlRelevanceScoringRescoreFinalSuggestionsOnly[] = {
-        {"MlRelevanceScoringIncreaseNumCandidates", "false"},
+const FeatureEntry::FeatureParam kOmniboxMlUrlScoringCounterfactual[] = {
+    {"MlUrlScoringCounterfactual", "true"},
+};
+const FeatureEntry::FeatureParam kOmniboxMlUrlScoringIncreaseNumCandidates[] = {
+    {"MlUrlScoringIncreaseNumCandidates", "true"},
 };
 
-const FeatureEntry::FeatureParam
-    kOmniboxMlRelevanceScoringIncreaseNumCandidates[] = {
-        {"MlRelevanceScoringIncreaseNumCandidates", "true"},
-};
-
-const FeatureEntry::FeatureVariation kOmniboxMlRelevanceScoringVariations[] = {
-    {"Re-score final set of suggestions only",
-     kOmniboxMlRelevanceScoringRescoreFinalSuggestionsOnly,
-     std::size(kOmniboxMlRelevanceScoringRescoreFinalSuggestionsOnly), nullptr},
-    {"Re-score with more candidates",
-     kOmniboxMlRelevanceScoringIncreaseNumCandidates,
-     std::size(kOmniboxMlRelevanceScoringIncreaseNumCandidates), nullptr},
+const FeatureEntry::FeatureVariation kOmniboxMlUrlScoringVariations[] = {
+    {"Run the model but do not rescore or rerank the matches",
+     kOmniboxMlUrlScoringCounterfactual,
+     std::size(kOmniboxMlUrlScoringCounterfactual), nullptr},
+    {"Score additional candidates from providers",
+     kOmniboxMlUrlScoringIncreaseNumCandidates,
+     std::size(kOmniboxMlUrlScoringIncreaseNumCandidates), nullptr},
 };
 
 const FeatureEntry::FeatureParam kRealboxTwoPreviousSearchRelatedSuggestions[] =
@@ -5605,12 +5602,11 @@
      flag_descriptions::kOmniboxMlLogUrlScoringSignalsName,
      flag_descriptions::kOmniboxMlLogUrlScoringSignalsDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(omnibox::kLogUrlScoringSignals)},
-    {"omnibox-ml-relevance-scoring",
-     flag_descriptions::kOmniboxMlRelevanceScoringName,
-     flag_descriptions::kOmniboxMlRelevanceScoringDescription, kOsDesktop,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(omnibox::kMlRelevanceScoring,
-                                    kOmniboxMlRelevanceScoringVariations,
-                                    "MlRelevanceScoring")},
+    {"omnibox-ml-url-scoring", flag_descriptions::kOmniboxMlUrlScoringName,
+     flag_descriptions::kOmniboxMlUrlScoringDescription, kOsDesktop,
+     FEATURE_WITH_PARAMS_VALUE_TYPE(omnibox::kMlUrlScoring,
+                                    kOmniboxMlUrlScoringVariations,
+                                    "MlUrlScoring")},
     {"omnibox-ml-url-scoring-model",
      flag_descriptions::kOmniboxMlUrlScoringModelName,
      flag_descriptions::kOmniboxMlUrlScoringModelDescription, kOsDesktop,
@@ -5758,6 +5754,10 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(omnibox::kUniformRowHeight,
                                     kOmniboxSuggestionHeightVariations,
                                     "Uniform Omnibox Suggest Heights")},
+    {"omnibox-cr23-action-chips",
+     flag_descriptions::kOmniboxCR23ActionChipsName,
+     flag_descriptions::kOmniboxCR23ActionChipsDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(omnibox::kCr2023ActionChips)},
 
     {"omnibox-cr23-expanded-state-height",
      flag_descriptions::kOmniboxCR23ExpandedStateHeightName,
@@ -6533,6 +6533,10 @@
                                     kTabStripRedesignVariations,
                                     "TabStripRedesignAndroid")},
 
+    {"enable-empty-states", flag_descriptions::kEmptyStatesAndroidName,
+     flag_descriptions::kEmptyStatesAndroidDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kEmptyStates)},
+
     {"enable-foldable-jank-fix", flag_descriptions::kFoldableJankFixAndroidName,
      flag_descriptions::kFoldableJankFixAndroidDescription, kOsAndroid,
      FEATURE_WITH_PARAMS_VALUE_TYPE(chrome::android::kFoldableJankFix,
diff --git a/chrome/browser/android/servicification_background_service_jni.cc b/chrome/browser/android/servicification_background_service_jni.cc
index d360b0c..77480f8 100644
--- a/chrome/browser/android/servicification_background_service_jni.cc
+++ b/chrome/browser/android/servicification_background_service_jni.cc
@@ -99,8 +99,12 @@
     return false;
   }
 
+  base::FieldTrial::ActiveGroups active_groups;
   std::vector<variations::ActiveGroupId> field_trial_ids;
-  variations::GetFieldTrialActiveGroupIds("", &field_trial_ids);
+  // The persistent histograms on disk do not include low anonymity trials (as
+  // we do not include those in metrics reports).
+  base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  variations::GetFieldTrialActiveGroupIds("", active_groups, &field_trial_ids);
   int expected_size = static_cast<int>(field_trial_ids.size());
 
   // The active field trial "Foo" is guaranteed in the list.
diff --git a/chrome/browser/android/vr/gvr_graphics_delegate.cc b/chrome/browser/android/vr/gvr_graphics_delegate.cc
index 506d3b74..7f15359 100644
--- a/chrome/browser/android/vr/gvr_graphics_delegate.cc
+++ b/chrome/browser/android/vr/gvr_graphics_delegate.cc
@@ -19,11 +19,6 @@
 #include "chrome/browser/vr/vr_geometry_util.h"
 #include "device/vr/android/web_xr_presentation_state.h"
 #include "device/vr/vr_gl_util.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkEncodedImageFormat.h"
-#include "third_party/skia/include/core/SkImageEncoder.h"
-#include "third_party/skia/include/core/SkPixmap.h"
-#include "third_party/skia/include/core/SkStream.h"
 #include "ui/gfx/geometry/angle_conversions.h"
 #include "ui/gl/android/scoped_java_surface.h"
 #include "ui/gl/android/surface_texture.h"
diff --git a/chrome/browser/apps/app_service/publishers/extension_apps_base.cc b/chrome/browser/apps/app_service/publishers/extension_apps_base.cc
index a2b6b44d..0d09e8e 100644
--- a/chrome/browser/apps/app_service/publishers/extension_apps_base.cc
+++ b/chrome/browser/apps/app_service/publishers/extension_apps_base.cc
@@ -114,7 +114,7 @@
   // uninstallation.
   auto app = std::make_unique<App>(app_type(), extension->id());
   app->readiness = reason == extensions::UNINSTALL_REASON_MIGRATED
-                       ? Readiness::kUninstalledByMigration
+                       ? Readiness::kUninstalledByNonUser
                        : Readiness::kUninstalledByUser;
   AppPublisher::Publish(std::move(app));
 }
diff --git a/chrome/browser/ash/app_list/app_list_sort_browsertest.cc b/chrome/browser/ash/app_list/app_list_sort_browsertest.cc
index 9b99ea3..9c612dc 100644
--- a/chrome/browser/ash/app_list/app_list_sort_browsertest.cc
+++ b/chrome/browser/ash/app_list/app_list_sort_browsertest.cc
@@ -32,9 +32,9 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkData.h"
-#include "third_party/skia/include/core/SkEncodedImageFormat.h"
 #include "third_party/skia/include/core/SkImage.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
+#include "third_party/skia/include/encode/SkPngEncoder.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/test/layer_animation_stopped_waiter.h"
 #include "ui/compositor/test/test_utils.h"
@@ -1411,8 +1411,8 @@
     icon = gfx::ImageSkiaOperations::CreateImageWithCircleBackground(
         icon_size / 2, icon_color, icon);
     const sk_sp<SkImage> image = SkImages::RasterFromBitmap(*icon.bitmap());
-    const sk_sp<SkData> png_data(
-        image->encodeToData(SkEncodedImageFormat::kPNG, /*quality=*/100));
+    const sk_sp<SkData> png_data =
+        SkPngEncoder::Encode(nullptr, image.get(), {});
     icon_file.Write(0, (const char*)png_data->data(), png_data->size());
     icon_file.Close();
 
diff --git a/chrome/browser/ash/app_list/app_service/app_service_app_model_builder.cc b/chrome/browser/ash/app_list/app_service/app_service_app_model_builder.cc
index 5fbef10a..66bf7ed 100644
--- a/chrome/browser/ash/app_list/app_service/app_service_app_model_builder.cc
+++ b/chrome/browser/ash/app_list/app_service/app_service_app_model_builder.cc
@@ -80,7 +80,7 @@
         unsynced_change = true;
       }
 
-      if (update.Readiness() == apps::Readiness::kUninstalledByMigration) {
+      if (update.Readiness() == apps::Readiness::kUninstalledByNonUser) {
         // Don't sync migration uninstallations as it will interfere with other
         // devices doing their own migration.
         unsynced_change = true;
diff --git a/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc
index 28b3bf26..8cb0a27 100644
--- a/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc
+++ b/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc
@@ -109,6 +109,7 @@
 constexpr char kVersionName[] = "version_name";
 constexpr char kAppSizeBytesString[] = "app_size_bytes_string";
 constexpr char kDataSizeBytesString[] = "data_size_bytes_string";
+constexpr char kAppCategory[] = "app_category";
 // Deprecated perfs fields.
 constexpr char kDeprecatePackagePrefsSystem[] = "system";
 
@@ -1009,6 +1010,10 @@
   WindowLayout window_layout =
       WindowLayoutFromDict(app_dict->FindDict(kWindowLayout));
 
+  const auto app_category = static_cast<arc::mojom::AppCategory>(
+      app_dict->FindInt(kAppCategory)
+          .value_or(static_cast<int32_t>(arc::mojom::AppCategory::kUndefined)));
+
   return std::make_unique<AppInfo>(
       name, package_name, activity, intent_uri, icon_resource_id, version_name,
       last_launch_time, GetInstallTime(app_id),
@@ -1018,7 +1023,7 @@
       window_layout, ready_apps_.count(app_id) > 0 /* ready */,
       app_dict->FindBool(kSuspended).value_or(false),
       launchable && arc::ShouldShowInLauncher(app_id), shortcut, launchable,
-      need_fixup, app_size_in_bytes, data_size_in_bytes);
+      need_fixup, app_size_in_bytes, data_size_in_bytes, app_category);
 }
 
 bool ArcAppListPrefs::IsRegistered(const std::string& app_id) const {
@@ -1300,6 +1305,16 @@
   return app_info->resize_lock_state;
 }
 
+arc::mojom::AppCategory ArcAppListPrefs::GetAppCategory(
+    const std::string& app_id) const {
+  std::unique_ptr<AppInfo> app_info = GetApp(app_id);
+  if (!app_info) {
+    VLOG(2) << "Failed to get app info: " << app_id << ".";
+    return arc::mojom::AppCategory::kUndefined;
+  }
+  return app_info->app_category;
+}
+
 void ArcAppListPrefs::SetResizeLockState(const std::string& app_id,
                                          arc::mojom::ArcResizeLockState state) {
   if (!IsRegistered(app_id)) {
@@ -1414,7 +1429,8 @@
         false /* notifications_enabled */, false /* app_ready */,
         false /* suspended */, false /* shortcut */, true /* launchable */,
         false /* need_fixup */, ArcAppListPrefs::WindowLayout(),
-        absl::nullopt /* app_size */, absl::nullopt /* data_size */);
+        absl::nullopt /* app_size */, absl::nullopt /* data_size */,
+        GetAppCategory(app_id));
   }
 }
 
@@ -1514,7 +1530,8 @@
         false /* notifications_enabled */, true /* app_ready */,
         false /* suspended */, false /* shortcut */, false /* launchable */,
         false /* need_fixup */, ArcAppListPrefs::WindowLayout(),
-        absl::nullopt /* app_size */, absl::nullopt /* data_size */);
+        absl::nullopt /* app_size */, absl::nullopt /* data_size */,
+        GetAppCategory(app_id));
   }
 }
 
@@ -1534,7 +1551,8 @@
     const bool need_fixup,
     const WindowLayout& initial_window_layout,
     const absl::optional<uint64_t> app_size_in_bytes,
-    const absl::optional<uint64_t> data_size_in_bytes) {
+    const absl::optional<uint64_t> data_size_in_bytes,
+    const arc::mojom::AppCategory app_category) {
   const std::string app_id = shortcut ? GetAppId(package_name, intent_uri)
                                       : GetAppId(package_name, activity);
 
@@ -1592,6 +1610,7 @@
   app_dict.Set(kShortcut, shortcut);
   app_dict.Set(kLaunchable, launchable);
   app_dict.Set(kNeedFixup, need_fixup);
+  app_dict.Set(kAppCategory, static_cast<int32_t>(app_category));
 
   app_dict.Set(kWindowLayout, WindowLayoutToDict(initial_window_layout));
 
@@ -1621,7 +1640,7 @@
       notifications_enabled, resize_lock_state, resize_lock_needs_confirmation,
       initial_window_layout, app_ready, suspended,
       launchable && arc::ShouldShowInLauncher(app_id), shortcut, launchable,
-      need_fixup, app_size_in_bytes, data_size_in_bytes);
+      need_fixup, app_size_in_bytes, data_size_in_bytes, app_category);
 
   if (was_tracked) {
     if (AreAppStatesChanged(*app_old_info, app_info)) {
@@ -1840,7 +1859,7 @@
         app->version_name, app->sticky, app->notifications_enabled,
         true /* app_ready */, app->suspended, false /* shortcut */,
         true /* launchable */, app->need_fixup, WindowLayoutFromApp(*app),
-        app_size_in_bytes, data_size_in_bytes);
+        app_size_in_bytes, data_size_in_bytes, app->app_category);
   }
 
   // Detect removed ARC apps after current refresh.
@@ -1927,7 +1946,7 @@
       app_info.version_name, app_info.sticky, app_info.notifications_enabled,
       true /* app_ready */, app_info.suspended, false /* shortcut */,
       true /* launchable */, app_info.need_fixup, WindowLayoutFromApp(app_info),
-      app_size_in_bytes, data_size_in_bytes);
+      app_size_in_bytes, data_size_in_bytes, app_info.app_category);
 }
 
 void ArcAppListPrefs::OnAppAddedDeprecated(arc::mojom::AppInfoPtr app) {
@@ -2019,7 +2038,8 @@
       false /* notifications_enabled */, true /* app_ready */,
       false /* suspended */, true /* shortcut */, true /* launchable */,
       false /* need_fixup */, ArcAppListPrefs::WindowLayout(),
-      absl::nullopt /* app_size */, absl::nullopt /* data_size */);
+      absl::nullopt /* app_size */, absl::nullopt /* data_size */,
+      GetAppCategory(GetAppId(shortcut->package_name, shortcut->intent_uri)));
 }
 
 void ArcAppListPrefs::OnUninstallShortcut(const std::string& package_name,
@@ -2476,7 +2496,8 @@
     bool launchable,
     bool need_fixup,
     const absl::optional<uint64_t> app_size_in_bytes,
-    const absl::optional<uint64_t> data_size_in_bytes)
+    const absl::optional<uint64_t> data_size_in_bytes,
+    arc::mojom::AppCategory app_category)
     : name(name),
       package_name(package_name),
       activity(activity),
@@ -2497,7 +2518,8 @@
       launchable(launchable),
       need_fixup(need_fixup),
       app_size_in_bytes(app_size_in_bytes),
-      data_size_in_bytes(data_size_in_bytes) {
+      data_size_in_bytes(data_size_in_bytes),
+      app_category(app_category) {
   // If app is not launchable it also does not show in launcher.
   DCHECK(launchable || !show_in_launcher);
 }
@@ -2530,7 +2552,8 @@
          shortcut == other.shortcut && launchable == other.launchable &&
          need_fixup == other.need_fixup &&
          app_size_in_bytes == other.app_size_in_bytes &&
-         data_size_in_bytes == other.data_size_in_bytes;
+         data_size_in_bytes == other.data_size_in_bytes &&
+         app_category == other.app_category;
 }
 
 ArcAppListPrefs::PackageInfo::PackageInfo(
diff --git a/chrome/browser/ash/app_list/arc/arc_app_list_prefs.h b/chrome/browser/ash/app_list/arc/arc_app_list_prefs.h
index 64f25e5..727b35b 100644
--- a/chrome/browser/ash/app_list/arc/arc_app_list_prefs.h
+++ b/chrome/browser/ash/app_list/arc/arc_app_list_prefs.h
@@ -108,7 +108,8 @@
             bool launchable,
             bool need_fixup,
             absl::optional<uint64_t> app_size_in_bytes,
-            absl::optional<uint64_t> data_size_in_bytes);
+            absl::optional<uint64_t> data_size_in_bytes,
+            arc::mojom::AppCategory app_category);
     AppInfo(AppInfo&& other);
     AppInfo& operator=(AppInfo&& other);
     ~AppInfo();
@@ -152,6 +153,9 @@
     absl::optional<uint64_t> app_size_in_bytes;
     absl::optional<uint64_t> data_size_in_bytes;
 
+    // App category from PackageManager.
+    arc::mojom::AppCategory app_category;
+
     static void SetIgnoreCompareInstallTimeForTesting(bool ignore);
 
     bool operator==(const AppInfo& other) const;
@@ -464,6 +468,8 @@
   // Returns true if the package is a default package, even it's uninstalled.
   bool IsDefaultPackage(const std::string& package_name) const;
 
+  arc::mojom::AppCategory GetAppCategory(const std::string& app_id) const;
+
  private:
   friend class ChromeShelfControllerTestBase;
   friend class ArcAppModelBuilderTest;
@@ -555,7 +561,8 @@
                          const bool need_fixup,
                          const WindowLayout& initial_window_layout,
                          const absl::optional<uint64_t> app_size_in_bytes,
-                         const absl::optional<uint64_t> data_size_in_bytes);
+                         const absl::optional<uint64_t> data_size_in_bytes,
+                         const arc::mojom::AppCategory app_category);
   // Adds or updates local pref for given package.
   void AddOrUpdatePackagePrefs(const arc::mojom::ArcPackageInfo& package);
   // Removes given package from local pref.
diff --git a/chrome/browser/ash/app_list/arc/arc_app_test.cc b/chrome/browser/ash/app_list/arc/arc_app_test.cc
index 03595c1e..e1e9288 100644
--- a/chrome/browser/ash/app_list/arc/arc_app_test.cc
+++ b/chrome/browser/ash/app_list/arc/arc_app_test.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ash/app_list/arc/arc_app_test.h"
 
 #include "ash/components/arc/arc_util.h"
+#include "ash/components/arc/mojom/app.mojom-shared.h"
 #include "ash/components/arc/session/arc_bridge_service.h"
 #include "ash/components/arc/session/arc_service_manager.h"
 #include "ash/components/arc/session/arc_session_runner.h"
@@ -201,17 +202,21 @@
   arc::mojom::AppInfo app;
   // Make sure we have enough data for test.
   for (int i = 0; i < 3; ++i) {
-    fake_apps_.emplace_back(arc::mojom::AppInfo::New(
+    arc::mojom::AppInfoPtr app_info = arc::mojom::AppInfo::New(
         base::StringPrintf("Fake App %d", i),
         base::StringPrintf("fake.app.%d", i),
-        base::StringPrintf("fake.app.%d.activity", i), false /* sticky */));
+        base::StringPrintf("fake.app.%d.activity", i), false /* sticky */);
+    app_info->app_category = arc::mojom::AppCategory::kUndefined;
+    fake_apps_.emplace_back(std::move(app_info));
   }
   fake_apps_[0]->sticky = true;
 
   for (int i = 1; i <= 3; ++i) {
-    fake_default_apps_.emplace_back(arc::mojom::AppInfo::New(
+    arc::mojom::AppInfoPtr app_info = arc::mojom::AppInfo::New(
         base::StringPrintf("TestApp%d", i), base::StringPrintf("test.app%d", i),
-        base::StringPrintf("test.app%d.activity", i), true /* sticky */));
+        base::StringPrintf("test.app%d.activity", i), true /* sticky */);
+    app_info->app_category = arc::mojom::AppCategory::kUndefined;
+    fake_default_apps_.emplace_back(std::move(app_info));
   }
 
   base::flat_map<arc::mojom::AppPermission, arc::mojom::PermissionStatePtr>
diff --git a/chrome/browser/ash/app_list/arc/arc_app_unittest.cc b/chrome/browser/ash/app_list/arc/arc_app_unittest.cc
index a36314d..38fec63 100644
--- a/chrome/browser/ash/app_list/arc/arc_app_unittest.cc
+++ b/chrome/browser/ash/app_list/arc/arc_app_unittest.cc
@@ -452,7 +452,7 @@
       ArcAppListPrefs::WindowLayout(), true /* ready */, false /* suspended */,
       launchable /* show_in_launcher*/, false /* shortcut */, launchable,
       false /* need_fixup */, absl::nullopt /* app_size */,
-      absl::nullopt /* data_size */);
+      absl::nullopt /* data_size */, app.app_category);
 }
 
 MATCHER_P(ArcPackageInfoIs, package, "") {
diff --git a/chrome/browser/ash/app_list/search/arc/arc_app_shortcuts_search_provider_unittest.cc b/chrome/browser/ash/app_list/search/arc/arc_app_shortcuts_search_provider_unittest.cc
index ca9bbd6..6a394580 100644
--- a/chrome/browser/ash/app_list/search/arc/arc_app_shortcuts_search_provider_unittest.cc
+++ b/chrome/browser/ash/app_list/search/arc/arc_app_shortcuts_search_provider_unittest.cc
@@ -83,7 +83,7 @@
         true /* notifications_enabled */, true /* app_ready */,
         false /* suspended */, false /* shortcut */, launchable,
         app_info.need_fixup, ArcAppListPrefs::WindowLayout(), app_size_in_bytes,
-        data_size_in_bytes);
+        data_size_in_bytes, app_info.app_category);
     const std::string app_id =
         ArcAppListPrefs::GetAppId(app_info.package_name, app_info.activity);
     EXPECT_TRUE(prefs->GetApp(app_id));
diff --git a/chrome/browser/ash/app_list/search/desks_admin_template_provider.cc b/chrome/browser/ash/app_list/search/desks_admin_template_provider.cc
index 99406eb..4e87779 100644
--- a/chrome/browser/ash/app_list/search/desks_admin_template_provider.cc
+++ b/chrome/browser/ash/app_list/search/desks_admin_template_provider.cc
@@ -14,7 +14,10 @@
 #include "chrome/browser/ash/app_list/search/common/icon_constants.h"
 #include "chrome/browser/ash/app_list/search/types.h"
 #include "chrome/browser/profiles/profile.h"
-#include "ui/gfx/image/image_skia.h"
+#include "chromeos/constants/chromeos_features.h"
+#include "ui/base/models/image_model.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
+#include "ui/color/color_id.h"
 #include "ui/gfx/paint_vector_icon.h"
 
 namespace app_list {
@@ -30,7 +33,7 @@
     AppListControllerDelegate* list_controller,
     const base ::GUID& template_uuid,
     const std::u16string& title,
-    const gfx::ImageSkia& icon)
+    const ui::ImageModel& icon)
     : profile_(profile),
       list_controller_(list_controller),
       template_uuid_(template_uuid) {
@@ -42,7 +45,9 @@
   SetResultType(ResultType::kDesksAdminTemplate);
   SetDisplayType(DisplayType::kContinue);
   SetMetricsType(ash::DESKS_ADMIN_TEMPLATE);
-  SetChipIcon(icon);
+
+  // TODO(b/278271038): Change to use `SetIcon` here instead of `SetBadgeIcon`.
+  SetBadgeIcon(icon);
 }
 
 DesksAdminTemplateResult::~DesksAdminTemplateResult() = default;
@@ -66,16 +71,12 @@
 
   auto* controller = ash::SavedDeskController::Get();
 
-  // TODO(b/273799604): Change the `icon_color` after future discussion.
-  auto* color_provider = ash::ColorProvider::Get();
-  // NOTE: Color provider may not be set in unit tests.
-  SkColor icon_color =
-      color_provider
-          ? color_provider->GetContentLayerColor(
-                ash::ColorProvider::ContentLayerType::kIconColorPrimary)
-          : gfx::kGoogleGrey900;
-  gfx::ImageSkia icon = gfx::CreateVectorIcon(
-      ash::kDesksTemplatesIcon, app_list::kSystemIconDimension, icon_color);
+  ui::ColorId color_id =
+      chromeos::features::IsJellyEnabled()
+          ? cros_tokens::kCrosSysTertiary
+          : static_cast<ui::ColorId>(cros_tokens::kIconColorPrimary);
+  ui::ImageModel icon = ui::ImageModel::FromVectorIcon(
+      ash::kDesksTemplatesIcon, color_id, kSystemIconDimension);
 
   for (const auto& metadata : controller->GetAdminTemplateMetadata()) {
     // With productivity launcher enabled, release notes are shown in continue
diff --git a/chrome/browser/ash/app_list/search/desks_admin_template_provider.h b/chrome/browser/ash/app_list/search/desks_admin_template_provider.h
index fb52e06..6283f984 100644
--- a/chrome/browser/ash/app_list/search/desks_admin_template_provider.h
+++ b/chrome/browser/ash/app_list/search/desks_admin_template_provider.h
@@ -16,9 +16,9 @@
 class AppListControllerDelegate;
 class Profile;
 
-namespace gfx {
-class ImageSkia;
-}  // namespace gfx
+namespace ui {
+class ImageModel;
+}  // namespace ui
 
 namespace app_list {
 
@@ -29,7 +29,7 @@
                            AppListControllerDelegate* list_controller,
                            const base::GUID& template_uuid,
                            const std::u16string& title,
-                           const gfx::ImageSkia& icon);
+                           const ui::ImageModel& icon);
 
   ~DesksAdminTemplateResult() override;
 
diff --git a/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.cc b/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.cc
index 8a81bd2..7692613 100644
--- a/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.cc
+++ b/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.cc
@@ -9,6 +9,8 @@
 #include "ash/components/arc/bluetooth/bluetooth_type_converters.h"
 #include "base/functional/callback_helpers.h"
 #include "base/guid.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "chrome/browser/ash/arc/bluetooth/arc_floss_bridge.h"
 #include "device/bluetooth/bluetooth_socket.h"
 #include "device/bluetooth/floss/floss_dbus_manager.h"
@@ -164,11 +166,48 @@
       std::move(response_callback), service_handle);
 }
 
+namespace {
+
+void OnNoOpBtifResult(
+    floss::DBusResult<floss::FlossDBusClient::BtifStatus> result) {}
+
+floss::FlossSocketManager::Security GetSecureFromFlags(
+    const mojom::BluetoothSocketFlagsPtr flags) {
+  // From Floss's masking logic secure = encrypt+auth
+  return (flags->encrypt && flags->auth)
+             ? floss::FlossSocketManager::Security::kSecure
+             : floss::FlossSocketManager::Security::kInsecure;
+}
+
+}  // namespace
+
+void ArcFlossBridge::OnCloseBluetoothListeningSocketComplete(
+    BluetoothListeningSocket* socket,
+    floss::DBusResult<floss::FlossDBusClient::BtifStatus> result) {
+  // We are not going to keep the socket around regardless of whether Floss
+  // succeeded, but we give it a chance.
+  listening_sockets_.erase(socket);
+}
+
 void ArcFlossBridge::CloseBluetoothListeningSocket(
-    BluetoothListeningSocket* ptr) {}
+    BluetoothListeningSocket* ptr) {
+  if (!listening_sockets_.contains(ptr)) {
+    return;
+  }
+
+  floss::ResponseCallback<floss::FlossAdapterClient::BtifStatus>
+      response_callback = base::BindOnce(
+          &ArcFlossBridge::OnCloseBluetoothListeningSocketComplete,
+          weak_factory_.GetWeakPtr(), ptr);
+  floss::FlossDBusManager::Get()->GetSocketManager()->Close(
+      listening_sockets_[ptr].second, std::move(response_callback));
+}
 
 void ArcFlossBridge::CloseBluetoothConnectingSocket(
-    BluetoothConnectingSocket* ptr) {}
+    BluetoothConnectingSocket* ptr) {
+  auto found = connecting_sockets_.find(ptr);
+  connecting_sockets_.erase(found);
+}
 
 void ArcFlossBridge::SdpSearchComplete(
     const floss::FlossDeviceId device,
@@ -181,6 +220,16 @@
     records_bluez.push_back(
         mojo::TypeConverter<bluez::BluetoothServiceRecordBlueZ,
                             floss::BtSdpRecord>::Convert(record));
+    absl::optional<floss::BtSdpHeaderOverlay> header =
+        GetHeaderOverlayFromSdpRecord(record);
+    if (!header.has_value()) {
+      continue;
+    }
+    // This record may be for an L2CAP service, but callers have to specify what
+    // protocol they want to use anyway.
+    uuid_lookups_.insert_or_assign(
+        std::make_pair(device.address, header->rfcomm_channel_number),
+        header->uuid);
   }
   OnGetServiceRecordsFinished(std::move(address), uuid, records_bluez);
 }
@@ -223,12 +272,61 @@
         GetDeviceProperties(mojom::BluetoothPropertyType::ALL, device));
   }
 }
+
 void ArcFlossBridge::CreateBluetoothListenSocket(
     mojom::BluetoothSocketType type,
     mojom::BluetoothSocketFlagsPtr flags,
     int port,
     ArcFlossBridge::BluetoothSocketListenCallback callback) {
-  NOTIMPLEMENTED();
+  if (!AdapterReadyAndRegistered()) {
+    return;
+  }
+  if (type != mojom::BluetoothSocketType::TYPE_RFCOMM &&
+      type != mojom::BluetoothSocketType::TYPE_L2CAP_LE) {
+    std::move(callback).Run(
+        mojom::BluetoothStatus::FAIL, /*port=*/0,
+        mojo::PendingReceiver<mojom::BluetoothListenSocketClient>());
+    return;
+  }
+  auto sock_wrapper = std::make_unique<BluetoothListeningSocket>();
+  sock_wrapper->sock_type = type;
+  auto connection_accepted_callback =
+      base::BindRepeating(&ArcFlossBridge::OnConnectionAccepted,
+                          weak_factory_.GetWeakPtr(), sock_wrapper.get());
+  int socket_ready_callback_id = next_socket_ready_callback_id_++;
+  socket_ready_callbacks_.insert_or_assign(socket_ready_callback_id,
+                                           std::move(callback));
+  auto connection_state_changed_callback = base::BindRepeating(
+      &ArcFlossBridge::OnConnectionStateChanged, weak_factory_.GetWeakPtr(),
+      sock_wrapper.get(), socket_ready_callback_id);
+  floss::ResponseCallback<floss::FlossDBusClient::BtifStatus>
+      response_callback =
+          base::BindOnce(&ArcFlossBridge::OnCreateListenSocketCallback,
+                         weak_factory_.GetWeakPtr(), std::move(sock_wrapper),
+                         socket_ready_callback_id);
+  switch (type) {
+    case mojom::BluetoothSocketType::TYPE_RFCOMM: {
+      floss::FlossDBusManager::Get()->GetSocketManager()->ListenUsingRfcommAlt(
+          absl::nullopt, absl::nullopt, port,
+          floss::FlossSocketManager::GetRawFlossFlagsFromBluetoothFlags(
+              flags->encrypt, flags->auth, flags->auth_mitm,
+              flags->auth_16_digit, /*no_sdp=*/true),
+          std::move(response_callback),
+          std::move(connection_state_changed_callback),
+          std::move(connection_accepted_callback));
+      break;
+    }
+    case mojom::BluetoothSocketType::TYPE_L2CAP_LE: {
+      floss::FlossDBusManager::Get()->GetSocketManager()->ListenUsingL2capLe(
+          GetSecureFromFlags(std::move(flags)), std::move(response_callback),
+          std::move(connection_state_changed_callback),
+          std::move(connection_accepted_callback));
+      break;
+    }
+    default: {
+      return;
+    }
+  }
 }
 
 void ArcFlossBridge::CreateBluetoothConnectSocket(
@@ -237,7 +335,256 @@
     mojom::BluetoothAddressPtr addr,
     int port,
     ArcFlossBridge::BluetoothSocketConnectCallback callback) {
-  NOTIMPLEMENTED();
+  if (!AdapterReadyAndRegistered()) {
+    return;
+  }
+  const floss::FlossDeviceId remote_device =
+      floss::FlossDeviceId({.address = addr->To<std::string>(), .name = ""});
+  auto sock_wrapper = std::make_unique<BluetoothConnectingSocket>();
+  sock_wrapper->sock_type = type;
+  switch (type) {
+    case mojom::BluetoothSocketType::TYPE_RFCOMM: {
+      const std::pair<std::string, int32_t> uuid_lookup_key =
+          std::make_pair(remote_device.address, port);
+      if (!uuid_lookups_.contains(uuid_lookup_key)) {
+        std::move(callback).Run(
+            mojom::BluetoothStatus::FAIL,
+            mojo::PendingReceiver<mojom::BluetoothConnectSocketClient>());
+        return;
+      }
+      floss::FlossDBusManager::Get()->GetSocketManager()->ConnectUsingRfcomm(
+          remote_device, uuid_lookups_.at(uuid_lookup_key),
+          GetSecureFromFlags(std::move(flags)),
+          base::BindOnce(&ArcFlossBridge::OnCreateConnectSocketCallback,
+                         weak_factory_.GetWeakPtr(), std::move(sock_wrapper),
+                         std::move(callback)));
+      break;
+    }
+    case mojom::BluetoothSocketType::TYPE_L2CAP_LE: {
+      floss::FlossDBusManager::Get()->GetSocketManager()->ConnectUsingL2capLe(
+          remote_device, port, GetSecureFromFlags(std::move(flags)),
+          base::BindOnce(&ArcFlossBridge::OnCreateConnectSocketCallback,
+                         weak_factory_.GetWeakPtr(), std::move(sock_wrapper),
+                         std::move(callback)));
+      break;
+    }
+    default: {
+      std::move(callback).Run(
+          mojom::BluetoothStatus::FAIL,
+          mojo::PendingReceiver<mojom::BluetoothConnectSocketClient>());
+      return;
+    }
+  }
+}
+
+void ArcFlossBridge::OnCreateListenSocketCallback(
+    std::unique_ptr<ArcBluetoothBridge::BluetoothListeningSocket> sock_wrapper,
+    int socket_ready_callback_id,
+    floss::DBusResult<floss::FlossDBusClient::BtifStatus> result) {
+  ArcBluetoothBridge::BluetoothListeningSocket* sock_wrapper_to_pass =
+      sock_wrapper.get();
+  listening_sockets_.insert_or_assign(
+      sock_wrapper.get(),
+      std::make_pair(std::move(sock_wrapper), empty_socket_id_));
+  if (!result.has_value()) {
+    CompleteListenSocketReady(socket_ready_callback_id,
+                              mojom::BluetoothStatus::FAIL,
+                              sock_wrapper_to_pass);
+    return;
+  }
+
+  if (*result != floss::FlossDBusClient::BtifStatus::kSuccess) {
+    CompleteListenSocketReady(socket_ready_callback_id,
+                              mojom::BluetoothStatus::FAIL,
+                              sock_wrapper_to_pass);
+    return;
+  }
+}
+
+void ArcFlossBridge::OnCreateConnectSocketCallback(
+    std::unique_ptr<ArcBluetoothBridge::BluetoothConnectingSocket> sock_wrapper,
+    ArcFlossBridge::BluetoothSocketConnectCallback callback,
+    floss::FlossDBusClient::BtifStatus status,
+    absl::optional<floss::FlossSocketManager::FlossSocket>&& socket) {
+  if (status != floss::FlossDBusClient::BtifStatus::kSuccess) {
+    std::move(callback).Run(
+        mojom::BluetoothStatus::FAIL,
+        mojo::PendingReceiver<mojom::BluetoothConnectSocketClient>());
+    return;
+  }
+
+  if (!socket || !socket->fd) {
+    std::move(callback).Run(
+        mojom::BluetoothStatus::FAIL,
+        mojo::PendingReceiver<mojom::BluetoothConnectSocketClient>());
+    return;
+  }
+
+  sock_wrapper->file = std::move(socket->fd.value());
+  std::move(callback).Run(mojom::BluetoothStatus::SUCCESS,
+                          sock_wrapper->remote.BindNewPipeAndPassReceiver());
+  auto connection = mojom::BluetoothSocketConnection::New();
+  mojo::ScopedHandle handle = mojo::WrapPlatformHandle(
+      mojo::PlatformHandle(std::move(sock_wrapper->file)));
+  connection->sock = std::move(handle);
+  switch (sock_wrapper->sock_type) {
+    case mojom::BluetoothSocketType::TYPE_RFCOMM:
+    case mojom::BluetoothSocketType::TYPE_L2CAP_LE:
+      connection->addr = mojom::BluetoothAddress::From<std::string>(
+          socket->remote_device.address);
+      connection->port = socket->port;
+      break;
+    default:
+      LOG(ERROR) << "Unknown socket type " << sock_wrapper->sock_type;
+      return;
+  }
+  sock_wrapper->remote->OnConnected(std::move(connection));
+  connecting_sockets_.insert(std::move(sock_wrapper));
+}
+
+void ArcFlossBridge::OnConnectionStateChanged(
+    ArcBluetoothBridge::BluetoothListeningSocket* sock_wrapper,
+    int socket_ready_callback_id,
+    floss::FlossSocketManager::ServerSocketState state,
+    floss::FlossSocketManager::FlossListeningSocket socket,
+    floss::FlossSocketManager::BtifStatus status) {
+  if (!sock_wrapper) {
+    // sock_wrapper has been disposed (or worse), nothing to do, but resolve
+    // callback with failure if it is still around.
+    CompleteListenSocketReady(socket_ready_callback_id,
+                              mojom::BluetoothStatus::FAIL, sock_wrapper,
+                              socket);
+    return;
+  }
+
+  if (status != floss::FlossSocketManager::BtifStatus::kSuccess) {
+    LOG(ERROR) << "Received OnConnectionStateChanged callback with "
+                  "non-Success status: "
+               << static_cast<int>(status);
+    CompleteListenSocketReady(socket_ready_callback_id,
+                              mojom::BluetoothStatus::FAIL, sock_wrapper,
+                              socket);
+    return;
+  }
+
+  if (state != floss::FlossSocketManager::ServerSocketState::kReady) {
+    // Socket isn't ready for accepting connections, nothing to do
+    return;
+  }
+
+  // At this point we may assume that listening socket creation was a
+  // success. Let CompleteListenSocketReady know if it doesn't already.
+  CompleteListenSocketReady(socket_ready_callback_id,
+                            mojom::BluetoothStatus::SUCCESS, sock_wrapper,
+                            socket);
+  if (!AdapterReadyAndRegistered()) {
+    return;
+  }
+
+  floss::ResponseCallback<floss::FlossDBusClient::BtifStatus>
+      response_callback = base::BindOnce(&OnNoOpBtifResult);
+  // TODO: figure out the correct timeout here
+  floss::FlossDBusManager::Get()->GetSocketManager()->Accept(
+      socket.id, /*timeout_ms=*/absl::nullopt, std::move(response_callback));
+}
+
+void ArcFlossBridge::OnConnectionAccepted(
+    const ArcBluetoothBridge::BluetoothListeningSocket* sock_wrapper,
+    floss::FlossSocketManager::FlossSocket&& socket) {
+  if (!sock_wrapper) {
+    // sock_wrapper has been disposed (or worse), nothing to do
+    return;
+  }
+
+  if (!socket.is_valid() || !socket.fd.has_value()) {
+    LOG(ERROR) << "New socket connection was accepted with invalid socket";
+    return;
+  }
+
+  mojo::ScopedHandle handle =
+      mojo::WrapPlatformHandle(mojo::PlatformHandle(std::move(*socket.fd)));
+  auto connection = mojom::BluetoothSocketConnection::New();
+  connection->sock = std::move(handle);
+  connection->addr =
+      mojom::BluetoothAddress::From(socket.remote_device.address);
+  connection->port = socket.port;
+  switch (socket.type) {
+    case floss::FlossSocketManager::SocketType::kRfcomm:
+    case floss::FlossSocketManager::SocketType::kL2cap:
+      sock_wrapper->remote->OnAccepted(std::move(connection));
+      break;
+    default:
+      return;
+  }
+}
+
+int ArcFlossBridge::GetPortOrChannel(
+    ArcBluetoothBridge::BluetoothListeningSocket* sock_wrapper,
+    floss::FlossSocketManager::FlossListeningSocket socket) {
+  switch (sock_wrapper->sock_type) {
+    case mojom::BluetoothSocketType::TYPE_RFCOMM:
+      if (!socket.channel) {
+        return 0;
+      }
+      return *socket.channel;
+    case mojom::BluetoothSocketType::TYPE_L2CAP_LE:
+      if (!socket.psm) {
+        return 0;
+      }
+      return *socket.psm;
+    default:
+      return 0;
+  }
+}
+
+void ArcFlossBridge::CompleteListenSocketReady(
+    int socket_ready_callback_id,
+    mojom::BluetoothStatus status,
+    ArcBluetoothBridge::BluetoothListeningSocket* sock_wrapper) {
+  CompleteListenSocketReady(socket_ready_callback_id, status,
+                            /*port_or_channel*/ 0, sock_wrapper);
+}
+
+void ArcFlossBridge::CompleteListenSocketReady(
+    int socket_ready_callback_id,
+    mojom::BluetoothStatus status,
+    int port_or_channel,
+    ArcBluetoothBridge::BluetoothListeningSocket* sock_wrapper) {
+  if (!socket_ready_callbacks_.contains(socket_ready_callback_id)) {
+    return;
+  }
+
+  BluetoothSocketListenCallback callback =
+      std::move(socket_ready_callbacks_[socket_ready_callback_id]);
+  socket_ready_callbacks_.erase(socket_ready_callback_id);
+  if (status != mojom::BluetoothStatus::SUCCESS) {
+    std::move(callback).Run(
+        mojom::BluetoothStatus::FAIL, /*port=*/0,
+        mojo::PendingReceiver<mojom::BluetoothListenSocketClient>());
+  } else {
+    std::move(callback).Run(mojom::BluetoothStatus::SUCCESS, port_or_channel,
+                            sock_wrapper->remote.BindNewPipeAndPassReceiver());
+    sock_wrapper->remote.set_disconnect_handler(
+        base::BindOnce(&ArcFlossBridge::CloseBluetoothListeningSocket,
+                       weak_factory_.GetWeakPtr(), sock_wrapper));
+  }
+}
+
+void ArcFlossBridge::CompleteListenSocketReady(
+    int socket_ready_callback_id,
+    mojom::BluetoothStatus status,
+    ArcBluetoothBridge::BluetoothListeningSocket* sock_wrapper,
+    floss::FlossSocketManager::FlossListeningSocket socket) {
+  if (!socket_ready_callbacks_.contains(socket_ready_callback_id)) {
+    return;
+  }
+  if (!listening_sockets_.contains(sock_wrapper)) {
+    return;
+  }
+  listening_sockets_[sock_wrapper].second = socket.id;
+  CompleteListenSocketReady(socket_ready_callback_id, status,
+                            GetPortOrChannel(sock_wrapper, socket),
+                            sock_wrapper);
 }
 
 void ArcFlossBridge::CompleteCreateSdpRecord(
diff --git a/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.h b/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.h
index 065e692..3b401159 100644
--- a/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.h
+++ b/chrome/browser/ash/arc/bluetooth/arc_floss_bridge.h
@@ -68,20 +68,16 @@
       device::BluetoothUUID uuid,
       arc::mojom::BluetoothCreateSdpRecordResultPtr result);
 
- private:
-  bool AdapterReadyAndRegistered();
-
-  // Map of SDP record UUIDs to CreateSdpRecordCallback for SdpRecordCreated to
-  // use to resolve CreateSdpRecord calls.
-  base::flat_map<device::BluetoothUUID, CreateSdpRecordCallback>
-      create_sdp_record_callbacks_{};
-
   void CreateBluetoothListenSocket(
       mojom::BluetoothSocketType type,
       mojom::BluetoothSocketFlagsPtr flags,
       int port,
       BluetoothSocketListenCallback callback) override;
 
+  void OnCloseBluetoothListeningSocketComplete(
+      BluetoothListeningSocket* socket,
+      floss::DBusResult<floss::FlossDBusClient::BtifStatus> result);
+
   void CreateBluetoothConnectSocket(
       mojom::BluetoothSocketType type,
       mojom::BluetoothSocketFlagsPtr flags,
@@ -89,6 +85,89 @@
       int port,
       BluetoothSocketConnectCallback callback) override;
 
+  void OnCreateListenSocketCallback(
+      std::unique_ptr<ArcBluetoothBridge::BluetoothListeningSocket>
+          sock_wrapper,
+      int socket_ready_id,
+      floss::DBusResult<floss::FlossDBusClient::BtifStatus> result);
+
+  void OnCreateConnectSocketCallback(
+      std::unique_ptr<ArcBluetoothBridge::BluetoothConnectingSocket>
+          sock_wrapper,
+      ArcFlossBridge::BluetoothSocketConnectCallback callback,
+      floss::FlossDBusClient::BtifStatus status,
+      absl::optional<floss::FlossSocketManager::FlossSocket>&& socket);
+
+  void OnBtifError(const std::string& error_message);
+
+  void OnBtifSuccess();
+
+  void OnConnectionStateChanged(
+      ArcBluetoothBridge::BluetoothListeningSocket* sock_wrapper,
+      int socket_ready_id,
+      floss::FlossSocketManager::ServerSocketState state,
+      floss::FlossSocketManager::FlossListeningSocket socket,
+      floss::FlossSocketManager::BtifStatus status);
+
+  void OnConnectionAccepted(
+      const ArcBluetoothBridge::BluetoothListeningSocket* sock_wrapper,
+      floss::FlossSocketManager::FlossSocket&& socket);
+
+  int GetPortOrChannel(
+      ArcBluetoothBridge::BluetoothListeningSocket* sock_wrapper,
+      floss::FlossSocketManager::FlossListeningSocket socket);
+
+  void CompleteListenSocketReady(
+      int socket_ready_id,
+      mojom::BluetoothStatus status,
+      int port_or_channel,
+      ArcBluetoothBridge::BluetoothListeningSocket* sock_wrapper);
+
+  void CompleteListenSocketReady(
+      int socket_ready_id,
+      mojom::BluetoothStatus status,
+      ArcBluetoothBridge::BluetoothListeningSocket* sock_wrapper);
+
+  void CompleteListenSocketReady(
+      int socket_ready_id,
+      mojom::BluetoothStatus status,
+      ArcBluetoothBridge::BluetoothListeningSocket* sock_wrapper,
+      floss::FlossSocketManager::FlossListeningSocket socket);
+
+ private:
+  bool AdapterReadyAndRegistered();
+
+  // Map of socket_ready_id -> listen callback
+  base::flat_map<int, BluetoothSocketListenCallback> socket_ready_callbacks_{};
+  // The next callback id to use. Starts at a non-zero number for easier
+  // debugging.
+  int next_socket_ready_callback_id_{42};
+
+  // Map of SDP record UUIDs to CreateSdpRecordCallback for SdpRecordCreated to
+  // use to resolve CreateSdpRecord calls.
+  base::flat_map<device::BluetoothUUID, CreateSdpRecordCallback>
+      create_sdp_record_callbacks_{};
+
+  // Lookup for mapping listening socket pointers to SocketIds so they can be
+  // closed with Floss.
+  base::flat_map<
+      ArcBluetoothBridge::BluetoothListeningSocket*,
+      std::pair<std::unique_ptr<ArcBluetoothBridge::BluetoothListeningSocket>,
+                floss::FlossSocketManager::SocketId>>
+      listening_sockets_{};
+  // Default SocketId until a real one is obtained.
+  static constexpr floss::FlossSocketManager::SocketId empty_socket_id_ = 0;
+
+  // Floss doesn't require us to close connecting sockets through it so we don't
+  // need to keep the SocketId.
+  std::set<std::unique_ptr<BluetoothConnectingSocket>,
+           base::UniquePtrComparator>
+      connecting_sockets_;
+
+  // Map of device+channel combinations to service UUIDs
+  base::flat_map<std::pair<std::string, int32_t>, device::BluetoothUUID>
+      uuid_lookups_{};
+
   // WeakPtrFactory to use for callbacks.
   base::WeakPtrFactory<ArcFlossBridge> weak_factory_{this};
 };
diff --git a/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util.cc b/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util.cc
index 6a3dee1..57cb7d20 100644
--- a/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util.cc
+++ b/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util.cc
@@ -13,69 +13,321 @@
 // Entries must be lower-case and sorted by lexicographical order for
 // binary search.
 //
-// The current list was taken from aosp-nougat version of
-// frameworks/base/media/java/android/media/MediaFile.java, and included
-// file type categories are:
-// - Audio
-// - MIDI
-// - Video
-// - Image
-// - Raw image
+// The current list includes all the extensions supported in P, R or T.
+// For P, the set of supported extension is obtained from
+// frameworks/base/media/java/android/media/MediaFile.java.
+// For R+, it is calculated from the set of MIME types that map to "Image",
+// "Audio", "Video", "Document", "Playlist", or "Subtitle" media type as defined
+// in .../MediaProvider/src/com/android/providers/media/util/MimeUtils.java,
+// and the extension-to-MIME-type mappings defined in
+// external/mime-support/mime.types and
+// frameworks/base/mime/java-res/android.mime.types.
+//
+// The comment for each extension shows its corresponding MIME type in T.
 const char* kAndroidSupportedMediaExtensions[] = {
-    ".3g2",    // FILE_TYPE_3GPP2, video/3gpp2
-    ".3gp",    // FILE_TYPE_3GPP, video/3gpp
-    ".3gpp",   // FILE_TYPE_3GPP, video/3gpp
-    ".3gpp2",  // FILE_TYPE_3GPP2, video/3gpp2
-    ".aac",    // FILE_TYPE_AAC, audio/aac, audio/aac-adts
-    ".amr",    // FILE_TYPE_AMR, audio/amr
-    ".arw",    // FILE_TYPE_ARW, image/x-sony-arw
-    ".asf",    // FILE_TYPE_ASF, video/x-ms-asf
-    ".avi",    // FILE_TYPE_AVI, video/avi
-    ".awb",    // FILE_TYPE_AWB, audio/amr-wb
-    ".bmp",    // FILE_TYPE_BMP, image/x-ms-bmp
-    ".cr2",    // FILE_TYPE_CR2, image/x-canon-cr2
-    ".dng",    // FILE_TYPE_DNG, image/x-adobe-dng
-    ".fl",     // FILE_TYPE_FL, application/x-android-drm-fl
-    ".gif",    // FILE_TYPE_GIF, image/gif
-    ".imy",    // FILE_TYPE_IMY, audio/imelody
-    ".jpeg",   // FILE_TYPE_JPEG, image/jpeg
-    ".jpg",    // FILE_TYPE_JPEG, image/jpeg
-    ".m4a",    // FILE_TYPE_M4A, audio/mp4
-    ".m4v",    // FILE_TYPE_M4V, video/mp4
-    ".mid",    // FILE_TYPE_MID, audio/midi
-    ".midi",   // FILE_TYPE_MID, audio/midi
-    ".mka",    // FILE_TYPE_MKA, audio/x-matroska
-    ".mkv",    // FILE_TYPE_MKV, video/x-matroska
-    ".mov",    // FILE_TYPE_QT, video/quicktime
-    ".mp3",    // FILE_TYPE_MP3, audio/mpeg
-    ".mp4",    // FILE_TYPE_MP4, video/mp4
-    ".mpeg",   // FILE_TYPE_MP4, video/mpeg, video/mp2p
-    ".mpg",    // FILE_TYPE_MP4, video/mpeg, video/mp2p
-    ".mpga",   // FILE_TYPE_MP3, audio/mpeg
-    ".mxmf",   // FILE_TYPE_MID, audio/midi
-    ".nef",    // FILE_TYPE_NEF, image/x-nikon-nef
-    ".nrw",    // FILE_TYPE_NRW, image/x-nikon-nrw
-    ".oga",    // FILE_TYPE_OGG, application/ogg
-    ".ogg",    // FILE_TYPE_OGG, audio/ogg, application/ogg
-    ".orf",    // FILE_TYPE_ORF, image/x-olympus-orf
-    ".ota",    // FILE_TYPE_MID, audio/midi
-    ".pef",    // FILE_TYPE_PEF, image/x-pentax-pef
-    ".png",    // FILE_TYPE_PNG, image/png
-    ".raf",    // FILE_TYPE_RAF, image/x-fuji-raf
-    ".rtttl",  // FILE_TYPE_MID, audio/midi
-    ".rtx",    // FILE_TYPE_MID, audio/midi
-    ".rw2",    // FILE_TYPE_RW2, image/x-panasonic-rw2
-    ".smf",    // FILE_TYPE_SMF, audio/sp-midi
-    ".srw",    // FILE_TYPE_SRW, image/x-samsung-srw
-    ".ts",     // FILE_TYPE_MP2TS, video/mp2ts
-    ".wav",    // FILE_TYPE_WAV, audio/x-wav
-    ".wbmp",   // FILE_TYPE_WBMP, image/vnd.wap.wbmp
-    ".webm",   // FILE_TYPE_WEBM, video/webm
-    ".webp",   // FILE_TYPE_WEBP, image/webp
-    ".wma",    // FILE_TYPE_WMA, audio/x-ms-wma
-    ".wmv",    // FILE_TYPE_WMV, video/x-ms-wmv
-    ".xmf",    // FILE_TYPE_MID, audio/midi
+    ".323",       // text/h323
+    ".3g2",       // video/3gpp2
+    ".3ga",       // audio/3gpp
+    ".3gp",       // video/3gpp
+    ".3gp2",      // video/3gpp2
+    ".3gpp",      // video/3gpp
+    ".3gpp2",     // video/3gpp2
+    ".a52",       // audio/ac3
+    ".aac",       // audio/aac
+    ".ac3",       // audio/ac3
+    ".adt",       // audio/aac
+    ".adts",      // audio/aac
+    ".aif",       // audio/x-aiff
+    ".aifc",      // audio/x-aiff
+    ".aiff",      // audio/x-aiff
+    ".amr",       // audio/amr
+    ".appcache",  // text/cache-manifest
+    ".art",       // image/x-jg
+    ".arw",       // image/x-sony-arw
+    ".asc",       // text/plain
+    ".asf",       // video/x-ms-asf
+    ".asx",       // video/x-ms-asf
+    ".au",        // audio/basic
+    ".avi",       // video/avi
+    ".avif",      // image/avif
+    ".awb",       // audio/amr-wb
+    ".axa",       // audio/annodex
+    ".axv",       // video/annodex
+    ".bib",       // text/x-bibtex
+    ".bmp",       // image/x-ms-bmp
+    ".boo",       // text/x-boo
+    ".brf",       // text/plain
+    ".c",         // text/x-csrc
+    ".c++",       // text/x-c++src
+    ".cc",        // text/x-c++src
+    ".cdr",       // image/x-coreldraw
+    ".cdt",       // image/x-coreldrawtemplate
+    ".cls",       // text/x-tex
+    ".cpp",       // text/x-c++src
+    ".cpt",       // image/x-corelphotopaint
+    ".cr2",       // image/x-canon-cr2
+    ".crw",       // image/x-canon-crw
+    ".csd",       // audio/csound
+    ".csh",       // text/x-csh
+    ".css",       // text/css
+    ".csv",       // text/comma-separated-values
+    ".cur",       // image/ico
+    ".cxx",       // text/x-c++src
+    ".d",         // text/x-dsrc
+    ".dfxp",      // application/ttml+xml
+    ".dif",       // video/dv
+    ".diff",      // text/plain
+    ".djv",       // image/vnd.djvu
+    ".djvu",      // image/vnd.djvu
+    ".dl",        // video/dl
+    ".dng",       // image/x-adobe-dng
+    ".doc",       // application/msword
+    // application/vnd.openxmlformats-officedocument.wordprocessingml.document
+    ".docx",
+    ".dot",  // application/msword
+    // application/vnd.openxmlformats-officedocument.wordprocessingml.template
+    ".dotx",
+    ".dv",        // video/dv
+    ".epub",      // application/epub+zip
+    ".erf",       // image/x-epson-erf
+    ".etx",       // text/x-setext
+    ".f4a",       // audio/mp4
+    ".f4b",       // audio/mp4
+    ".f4p",       // audio/mp4
+    ".f4v",       // video/mp4
+    ".fl",        // application/x-android-drm-fl (supported as DRM file)
+    ".flac",      // audio/flac
+    ".fli",       // video/fli
+    ".flv",       // video/x-flv
+    ".gcd",       // text/x-pcs-gcd
+    ".gif",       // image/gif
+    ".gl",        // video/gl
+    ".gsm",       // audio/x-gsm
+    ".h",         // text/x-chdr
+    ".h++",       // text/x-c++hdr
+    ".heic",      // image/heic
+    ".heics",     // image/heic-sequence
+    ".heif",      // image/heif
+    ".heifs",     // image/heif-sequence
+    ".hh",        // text/x-c++hdr
+    ".hif",       // image/heif
+    ".hpp",       // text/x-c++hdr
+    ".hs",        // text/x-haskell
+    ".htc",       // text/x-component
+    ".htm",       // text/html
+    ".html",      // text/html
+    ".hxx",       // text/x-c++hdr
+    ".ico",       // image/x-icon
+    ".ics",       // text/calendar
+    ".icz",       // text/calendar
+    ".ief",       // image/ief
+    ".imy",       // audio/imelody
+    ".jad",       // text/vnd.sun.j2me.app-descriptor
+    ".java",      // text/x-java
+    ".jng",       // image/x-jng
+    ".jp2",       // image/jp2
+    ".jpe",       // image/jpeg
+    ".jpeg",      // image/jpeg
+    ".jpf",       // image/jpx
+    ".jpg",       // image/jpeg
+    ".jpg2",      // image/jp2
+    ".jpm",       // image/jpm
+    ".jpx",       // image/jpx
+    ".kar",       // audio/midi
+    ".lhs",       // text/x-literate-haskell
+    ".lrc",       // application/lrc
+    ".lsf",       // video/x-la-asf
+    ".lsx",       // video/x-la-asf
+    ".ltx",       // text/x-tex
+    ".ly",        // text/x-lilypond
+    ".m1v",       // video/mpeg
+    ".m2t",       // video/mpeg
+    ".m2ts",      // video/mp2t
+    ".m2v",       // video/mpeg
+    ".m3u",       // audio/x-mpegurl
+    ".m3u8",      // audio/x-mpegurl
+    ".m4a",       // audio/mpeg
+    ".m4b",       // audio/mp4
+    ".m4p",       // audio/mp4
+    ".m4r",       // audio/mpeg
+    ".m4v",       // video/mp4
+    ".markdown",  // text/markdown
+    ".md",        // text/markdown
+    ".mid",       // audio/midi
+    ".midi",      // audio/midi
+    ".mka",       // audio/x-matroska
+    ".mkv",       // video/x-matroska
+    ".mml",       // text/mathml
+    ".mng",       // video/x-mng
+    ".moc",       // text/x-moc
+    ".mov",       // video/quicktime
+    ".movie",     // video/x-sgi-movie
+    ".mp1",       // audio/mpeg
+    ".mp1v",      // video/mpeg
+    ".mp2",       // audio/mpeg
+    ".mp2v",      // video/mpeg
+    ".mp3",       // audio/mpeg
+    ".mp4",       // video/mp4
+    ".mp4v",      // video/mp4
+    ".mpa",       // audio/mpeg
+    ".mpe",       // video/mpeg
+    ".mpeg",      // video/mpeg
+    ".mpeg1",     // video/mpeg
+    ".mpeg2",     // video/mpeg
+    ".mpeg4",     // video/mp4
+    ".mpega",     // audio/mpeg
+    ".mpg",       // video/mpeg
+    ".mpga",      // audio/mpeg
+    ".mpv",       // video/x-matroska
+    ".mpv1",      // video/mpeg
+    ".mpv2",      // video/mpeg
+    ".mts",       // video/mp2t
+    ".mxmf",      // audio/mobile-xmf
+    ".mxu",       // video/vnd.mpegurl
+    ".nef",       // image/x-nikon-nef
+    ".nrw",       // image/x-nikon-nrw
+    ".odb",       // application/vnd.oasis.opendocument.database
+    ".odc",       // application/vnd.oasis.opendocument.chart
+    ".odf",       // application/vnd.oasis.opendocument.formula
+    ".odg",       // application/vnd.oasis.opendocument.graphics
+    ".odm",       // application/vnd.oasis.opendocument.text-master
+    ".odp",       // application/vnd.oasis.opendocument.presentation
+    ".ods",       // application/vnd.oasis.opendocument.spreadsheet
+    ".odt",       // application/vnd.oasis.opendocument.text
+    ".oga",       // audio/ogg
+    ".ogg",       // audio/ogg
+    ".ogv",       // video/ogg
+    ".opus",      // audio/ogg
+    ".orc",       // audio/csound
+    ".orf",       // image/x-olympus-orf
+    ".ota",       // application/vnd.android.ota (supported only in P as
+                  // audio/midi)
+    ".otg",       // application/vnd.oasis.opendocument.graphics-template
+    ".oth",       // application/vnd.oasis.opendocument.text-web
+    ".otp",       // application/vnd.oasis.opendocument.presentation-template
+    ".ots",       // application/vnd.oasis.opendocument.spreadsheet-template
+    ".ott",       // application/vnd.oasis.opendocument.text-template
+    ".p",         // text/x-pascal
+    ".pas",       // text/x-pascal
+    ".pat",       // image/x-coreldrawpattern
+    ".patch",     // text/x-diff
+    ".pbm",       // image/x-portable-bitmap
+    ".pcx",       // image/pcx
+    ".pdf",       // application/pdf
+    ".pef",       // image/x-pentax-pef
+    ".pgm",       // image/x-portable-graymap
+    ".phps",      // text/text
+    ".pl",        // text/x-perl
+    ".pls",       // audio/x-scpls
+    ".pm",        // text/x-perl
+    ".png",       // image/png
+    ".pnm",       // image/x-portable-anymap
+    ".po",        // text/plain
+    ".pot",       // application/vnd.ms-powerpoint
+    // application/vnd.openxmlformats-officedocument.presentationml.template
+    ".potx",
+    ".ppm",  // image/x-portable-pixmap
+    ".pps",  // application/vnd.ms-powerpoint
+    // application/vnd.openxmlformats-officedocument.presentationml.slideshow
+    ".ppsx",
+    ".ppt",  // application/vnd.ms-powerpoint
+    // application/vnd.openxmlformats-officedocument.presentationml.presentation
+    ".pptx",
+    ".psd",    // image/x-photoshop
+    ".py",     // text/x-python
+    ".qt",     // video/quicktime
+    ".ra",     // audio/x-pn-realaudio
+    ".raf",    // image/x-fuji-raf
+    ".ram",    // audio/x-pn-realaudio
+    ".ras",    // image/x-cmu-raster
+    ".rgb",    // image/x-rgb
+    ".rm",     // audio/x-pn-realaudio
+    ".rtf",    // text/rtf
+    ".rtttl",  // audio/midi
+    ".rtx",    // audio/midi
+    ".rw2",    // image/x-panasonic-rw2
+    ".scala",  // text/x-scala
+    ".sco",    // audio/csound
+    ".sct",    // text/scriptlet
+    ".sd2",    // audio/x-sd2
+    ".sda",    // application/vnd.stardivision.draw
+    ".sdc",    // application/vnd.stardivision.calc
+    ".sdd",    // application/vnd.stardivision.impress
+    ".sdp",    // application/vnd.stardivision.impress
+    ".sds",    // application/vnd.stardivision.chart
+    ".sdw",    // application/vnd.stardivision.writer
+    ".sfv",    // text/x-sfv
+    ".sgl",    // application/vnd.stardivision.writer-global
+    ".sh",     // text/x-sh
+    ".shtml",  // text/html
+    ".sid",    // audio/prs.sid
+    ".smf",    // audio/sp-midi
+    ".smi",    // application/smil+xml
+    ".smil",   // application/smil+xml
+    ".snd",    // audio/basic
+    ".spx",    // audio/ogg
+    ".srt",    // application/x-subrip
+    ".srw",    // image/x-samsung-srw
+    ".stc",    // application/vnd.sun.xml.calc.template
+    ".std",    // application/vnd.sun.xml.draw.template
+    ".sti",    // application/vnd.sun.xml.impress.template
+    ".sty",    // text/x-tex
+    ".svg",    // image/svg+xml
+    ".svgz",   // image/svg+xml
+    ".sxc",    // application/vnd.sun.xml.calc
+    ".sxd",    // application/vnd.sun.xml.draw
+    ".sxg",    // application/vnd.sun.xml.writer.global
+    ".sxi",    // application/vnd.sun.xml.impress
+    ".sxm",    // application/vnd.sun.xml.math
+    ".sxw",    // application/vnd.sun.xml.writer
+    ".tcl",    // text/x-tcl
+    ".tex",    // text/x-tex
+    ".text",   // text/plain
+    ".tif",    // image/tiff
+    ".tiff",   // image/tiff
+    ".tk",     // text/x-tcl
+    ".tm",     // text/texmacs
+    ".ts",     // video/mp2ts
+    ".tsv",    // text/tab-separated-values
+    ".ttl",    // text/turtle
+    ".ttml",   // application/ttml+xml
+    ".txt",    // text/plain
+    ".uls",    // text/iuls
+    ".vcard",  // text/vcard
+    ".vcf",    // text/x-vcard
+    ".vcs",    // text/x-vcalendar
+    ".vor",    // application/vnd.stardivision.writer
+    ".wav",    // audio/x-wav
+    ".wax",    // audio/x-ms-wax
+    ".wbmp",   // image/vnd.wap.wbmp
+    ".webm",   // video/webm
+    ".webp",   // image/webp
+    ".wm",     // video/x-ms-wm
+    ".wma",    // audio/x-ms-wma
+    ".wml",    // text/vnd.wap.wml
+    ".wmls",   // text/vnd.wap.wmlscript
+    ".wmv",    // video/x-ms-wmv
+    ".wmx",    // video/x-ms-wmx
+    ".wpl",    // application/vnd.ms-wpl
+    ".wrf",    // video/x-webex
+    ".wsc",    // text/scriptlet
+    ".wvx",    // video/x-ms-wvx
+    ".xbm",    // image/x-xbitmap
+    ".xlb",    // application/vnd.ms-excel
+    ".xls",    // application/vnd.ms-excel
+    // application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
+    ".xlsx",
+    ".xlt",  // application/vnd.ms-excel
+    // application/vnd.openxmlformats-officedocument.spreadsheetml.template
+    ".xltx",
+    ".xmf",   // audio/midi
+    ".xml",   // text/xml
+    ".xpm",   // image/x-xpixmap
+    ".xspf",  // application/xspf+xml
+    ".xwd",   // image/x-xwindowdump
+    ".yt",    // video/vnd.youtube.yt
 };
+
 const int kAndroidSupportedMediaExtensionsSize =
     std::size(kAndroidSupportedMediaExtensions);
 
diff --git a/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util_unittest.cc b/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util_unittest.cc
index 48a3275..1f21242 100644
--- a/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util_unittest.cc
+++ b/chrome/browser/ash/arc/file_system_watcher/arc_file_system_watcher_util_unittest.cc
@@ -139,6 +139,10 @@
       base::FilePath(FILE_PATH_LITERAL("/tmp/kitten.xmf"))));
   EXPECT_TRUE(HasAndroidSupportedMediaExtension(
       base::FilePath(FILE_PATH_LITERAL("/tmp/kitten.nef"))));
+  EXPECT_TRUE(HasAndroidSupportedMediaExtension(
+      base::FilePath(FILE_PATH_LITERAL("/tmp/kitten.txt"))));
+  EXPECT_TRUE(HasAndroidSupportedMediaExtension(
+      base::FilePath(FILE_PATH_LITERAL("/tmp/kitten.pdf"))));
 
   EXPECT_TRUE(HasAndroidSupportedMediaExtension(
       base::FilePath(FILE_PATH_LITERAL("/tmp/kitten.JPEG"))));
@@ -148,7 +152,7 @@
       base::FilePath(FILE_PATH_LITERAL("/tmp/.kitten.jpg"))));
 
   EXPECT_FALSE(HasAndroidSupportedMediaExtension(
-      base::FilePath(FILE_PATH_LITERAL("/tmp/kitten.txt"))));
+      base::FilePath(FILE_PATH_LITERAL("/tmp/kitten.zip"))));
   EXPECT_FALSE(HasAndroidSupportedMediaExtension(
       base::FilePath(FILE_PATH_LITERAL("/tmp/kitten.jpg.exe"))));
   EXPECT_FALSE(HasAndroidSupportedMediaExtension(
diff --git a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.cc b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.cc
index 2464131..393c0a6 100644
--- a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.cc
+++ b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.cc
@@ -28,6 +28,7 @@
 #include "components/exo/shell_surface_base.h"
 #include "components/exo/shell_surface_util.h"
 #include "ui/aura/window_tree_host.h"
+#include "ui/base/ime/input_method.h"
 #include "ui/base/ime/input_method_observer.h"
 #include "ui/base/ime/text_input_client.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.h b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.h
index 27563dca..be66f75 100644
--- a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.h
+++ b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.h
@@ -25,12 +25,15 @@
 #include "ui/aura/env_observer.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
-#include "ui/base/ime/input_method.h"
 #include "ui/display/display_observer.h"
 
 namespace content {
 class BrowserContext;
-}
+}  // namespace content
+
+namespace ui {
+class InputMethod;
+}  // namespace ui
 
 namespace arc::input_overlay {
 
diff --git a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h
index 4f582ab..4bd7ad6 100644
--- a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h
+++ b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.h
@@ -25,6 +25,7 @@
 }  // namespace ash
 
 namespace arc::input_overlay {
+
 class Action;
 class ActionEditMenu;
 class ActionView;
diff --git a/chrome/browser/ash/arc/input_overlay/touch_injector.h b/chrome/browser/ash/arc/input_overlay/touch_injector.h
index b43e7148..902164a 100644
--- a/chrome/browser/ash/arc/input_overlay/touch_injector.h
+++ b/chrome/browser/ash/arc/input_overlay/touch_injector.h
@@ -27,9 +27,10 @@
 }  // namespace ui
 
 namespace arc::input_overlay {
+
+class Action;
 class ArcInputOverlayManagerTest;
 class DisplayOverlayController;
-class Action;
 
 // If the following touch move sent immediately, the touch move event is not
 // processed correctly by apps. This is a delayed time to send touch move
diff --git a/chrome/browser/ash/arc/input_overlay/ui/action_view.h b/chrome/browser/ash/arc/input_overlay/ui/action_view.h
index 74911d9..38a1a06 100644
--- a/chrome/browser/ash/arc/input_overlay/ui/action_view.h
+++ b/chrome/browser/ash/arc/input_overlay/ui/action_view.h
@@ -19,8 +19,8 @@
 namespace arc::input_overlay {
 
 class Action;
-class DisplayOverlayController;
 class ActionEditButton;
+class DisplayOverlayController;
 
 // Represents the default label index. Default -1 means all the index.
 constexpr int kDefaultLabelIndex = -1;
diff --git a/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.h b/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.h
index 109d54d9..d634ad67 100644
--- a/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.h
+++ b/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.h
@@ -13,8 +13,8 @@
 namespace arc::input_overlay {
 
 class Action;
-
 class DisplayOverlayController;
+
 // InputMappingView shows all the input mappings.
 class InputMappingView : public views::View {
  public:
diff --git a/chrome/browser/ash/arc/input_overlay/ui/input_menu_view.h b/chrome/browser/ash/arc/input_overlay/ui/input_menu_view.h
index 28eda4b..99800fe 100644
--- a/chrome/browser/ash/arc/input_overlay/ui/input_menu_view.h
+++ b/chrome/browser/ash/arc/input_overlay/ui/input_menu_view.h
@@ -34,7 +34,9 @@
 //   +---------------------------------+
 
 namespace arc::input_overlay {
+
 class DisplayOverlayController;
+
 class InputMenuView : public views::View {
  public:
   static std::unique_ptr<InputMenuView> BuildMenuView(
diff --git a/chrome/browser/ash/arc/input_overlay/ui/message_view.h b/chrome/browser/ash/arc/input_overlay/ui/message_view.h
index 14aeae1..e92b7bb 100644
--- a/chrome/browser/ash/arc/input_overlay/ui/message_view.h
+++ b/chrome/browser/ash/arc/input_overlay/ui/message_view.h
@@ -11,6 +11,7 @@
 #include "ui/views/controls/label.h"
 
 namespace arc::input_overlay {
+
 class DisplayOverlayController;
 
 // MessageView shows info or error message on the top center of the window.
diff --git a/chrome/browser/ash/arc/instance_throttle/arc_app_launch_throttle_observer_unittest.cc b/chrome/browser/ash/arc/instance_throttle/arc_app_launch_throttle_observer_unittest.cc
index 527c9c5..267a6f92 100644
--- a/chrome/browser/ash/arc/instance_throttle/arc_app_launch_throttle_observer_unittest.cc
+++ b/chrome/browser/ash/arc/instance_throttle/arc_app_launch_throttle_observer_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <string>
 
+#include "ash/components/arc/mojom/app.mojom.h"
 #include "ash/components/arc/mojom/compatibility_mode.mojom.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
@@ -33,7 +34,8 @@
       ArcAppListPrefs::WindowLayout(), true /* ready */, true /* suspended */,
       true /* show_in_launcher */, true /* shortcut */, true /* launchable */,
       false /* need_fixup */, absl::nullopt /* app_size_in_bytes */,
-      absl::nullopt /* data_size_in_bytes */);
+      absl::nullopt /* data_size_in_bytes */,
+      arc::mojom::AppCategory::kUndefined);
 }
 
 class ArcAppLaunchThrottleObserverTest : public testing::Test {
diff --git a/chrome/browser/ash/child_accounts/time_limits/app_service_wrapper.cc b/chrome/browser/ash/child_accounts/time_limits/app_service_wrapper.cc
index 83554ea..36bfbcf 100644
--- a/chrome/browser/ash/child_accounts/time_limits/app_service_wrapper.cc
+++ b/chrome/browser/ash/child_accounts/time_limits/app_service_wrapper.cc
@@ -241,7 +241,7 @@
         }
       break;
     case apps::Readiness::kUninstalledByUser:
-    case apps::Readiness::kUninstalledByMigration:
+    case apps::Readiness::kUninstalledByNonUser:
       for (auto& listener : listeners_)
         listener.OnAppUninstalled(app_id);
       break;
diff --git a/chrome/browser/ash/chrome_browser_main_parts_ash.cc b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
index f7d717a..2b52d34 100644
--- a/chrome/browser/ash/chrome_browser_main_parts_ash.cc
+++ b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
@@ -174,7 +174,6 @@
 #include "chrome/browser/net/chrome_network_delegate.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/startup_data.h"
 #include "chrome/browser/task_manager/task_manager_interface.h"
 #include "chrome/browser/ui/ash/assistant/assistant_browser_delegate_impl.h"
@@ -1574,12 +1573,18 @@
   // Must occur before BrowserProcessImpl::StartTearDown() destroys the
   // ProfileManager.
   if (pre_profile_init_called_) {
-    Profile* primary_user = ProfileManager::GetPrimaryUserProfile();
+    auto* primary_user = user_manager::UserManager::Get()->GetPrimaryUser();
     if (primary_user) {
-      // See startup_settings_cache::ReadAppLocale() comment for why we do this.
-      startup_settings_cache::WriteAppLocale(
-          primary_user->GetPrefs()->GetString(
-              language::prefs::kApplicationLocale));
+      // During a login restart-to-apply-flags the primary profile may not be
+      // loaded yet. See http://crbug.com/1432237
+      auto* primary_profile = Profile::FromBrowserContext(
+          BrowserContextHelper::Get()->GetBrowserContextByUser(primary_user));
+      if (primary_profile) {
+        // See startup_settings_cache::ReadAppLocale() comment.
+        startup_settings_cache::WriteAppLocale(
+            primary_profile->GetPrefs()->GetString(
+                language::prefs::kApplicationLocale));
+      }
     }
   }
 
diff --git a/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc
index e50016a..1ac5b27 100644
--- a/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc
@@ -479,7 +479,7 @@
           APP_READINESS_UNINSTALLEDBYUSER;
     case apps::Readiness::kRemoved:
       return api::autotest_private::AppReadiness::APP_READINESS_REMOVED;
-    case apps::Readiness::kUninstalledByMigration:
+    case apps::Readiness::kUninstalledByNonUser:
       return api::autotest_private::AppReadiness::
           APP_READINESS_UNINSTALLEDBYMIGRATION;
     case apps::Readiness::kUnknown:
diff --git a/chrome/browser/ash/extensions/file_manager/private_api_thumbnail.cc b/chrome/browser/ash/extensions/file_manager/private_api_thumbnail.cc
index 75af55c..7483bcd 100644
--- a/chrome/browser/ash/extensions/file_manager/private_api_thumbnail.cc
+++ b/chrome/browser/ash/extensions/file_manager/private_api_thumbnail.cc
@@ -32,9 +32,10 @@
 #include "storage/common/file_system/file_system_util.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkData.h"
-#include "third_party/skia/include/core/SkEncodedImageFormat.h"
 #include "third_party/skia/include/core/SkImage.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
+#include "third_party/skia/include/core/SkStream.h"
+#include "third_party/skia/include/encode/SkPngEncoder.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace extensions {
@@ -56,12 +57,13 @@
     DLOG(WARNING) << "Got an invalid bitmap";
     return std::string();
   }
-  sk_sp<SkImage> image = SkImages::RasterFromBitmap(bitmap);
-  sk_sp<SkData> png_data(image->encodeToData(SkEncodedImageFormat::kPNG, 100));
-  if (!png_data) {
+  SkDynamicMemoryWStream stream;
+  if (!SkPngEncoder::Encode(&stream, bitmap.pixmap(), {}) ||
+      !stream.bytesWritten()) {
     DLOG(WARNING) << "Thumbnail encoding error";
     return std::string();
   }
+  sk_sp<SkData> png_data = stream.detachAsData();
   return MakeThumbnailDataUrlOnThreadPool(
       kMimeTypeImagePng, base::make_span(png_data->bytes(), png_data->size()));
 }
diff --git a/chrome/browser/ash/login/users/avatar/user_image_loader_unittest.cc b/chrome/browser/ash/login/users/avatar/user_image_loader_unittest.cc
index 43f670f..6cb1abc 100644
--- a/chrome/browser/ash/login/users/avatar/user_image_loader_unittest.cc
+++ b/chrome/browser/ash/login/users/avatar/user_image_loader_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/test/task_environment.h"
-#include "chrome/browser/ash/login/users/avatar/user_image_manager_test_util.h"
 #include "chrome/common/chrome_paths.h"
 #include "components/user_manager/user_image/user_image.h"
 #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
@@ -22,6 +21,15 @@
 
 namespace ash {
 
+namespace {
+
+// Points to a webp file with 3 frames of red, green, blue solid colors,
+// respectively.
+constexpr base::StringPiece kUserAvatarWebpRelativePath =
+    "chromeos/avatars/avatar.webp";
+
+}  // namespace
+
 class UserImageLoaderTest : public testing::Test {
  public:
   UserImageLoaderTest() = default;
@@ -41,7 +49,7 @@
   ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
 
   const base::FilePath image_path =
-      test_dir.Append(test::kUserAvatarWebpRelativePath);
+      test_dir.Append(kUserAvatarWebpRelativePath);
 
   std::string original_contents;
   base::ReadFileToString(image_path, &original_contents);
diff --git a/chrome/browser/ash/login/users/avatar/user_image_manager_test_util.cc b/chrome/browser/ash/login/users/avatar/user_image_manager_test_util.cc
index 33f17c4..7299bee1 100644
--- a/chrome/browser/ash/login/users/avatar/user_image_manager_test_util.cc
+++ b/chrome/browser/ash/login/users/avatar/user_image_manager_test_util.cc
@@ -21,7 +21,6 @@
 const char kUserAvatarImage1RelativePath[] = "chromeos/avatars/avatar1.jpg";
 const char kUserAvatarImage2RelativePath[] = "chromeos/avatars/avatar2.jpg";
 const char kUserAvatarImage3RelativePath[] = "chromeos/avatars/avatar3.png";
-const char kUserAvatarWebpRelativePath[] = "chromeos/avatars/avatar.webp";
 
 bool AreImagesEqual(const gfx::ImageSkia& first, const gfx::ImageSkia& second) {
   if (first.width() != second.width() || first.height() != second.height())
diff --git a/chrome/browser/ash/login/users/avatar/user_image_manager_test_util.h b/chrome/browser/ash/login/users/avatar/user_image_manager_test_util.h
index bd99768..5152514 100644
--- a/chrome/browser/ash/login/users/avatar/user_image_manager_test_util.h
+++ b/chrome/browser/ash/login/users/avatar/user_image_manager_test_util.h
@@ -21,9 +21,6 @@
 extern const char kUserAvatarImage2RelativePath[];
 // Points to a png file with transparent pixels.
 extern const char kUserAvatarImage3RelativePath[];
-// Points to a webp file with 3 frames of red, green, blue solid colors,
-// respectively.
-extern const char kUserAvatarWebpRelativePath[];
 
 // Returns `true` if the two given images are pixel-for-pixel identical.
 bool AreImagesEqual(const gfx::ImageSkia& first, const gfx::ImageSkia& second);
diff --git a/chrome/browser/ash/nearby/presence/nearby_presence_service_factory.cc b/chrome/browser/ash/nearby/presence/nearby_presence_service_factory.cc
index 8830c68..b2679b7f 100644
--- a/chrome/browser/ash/nearby/presence/nearby_presence_service_factory.cc
+++ b/chrome/browser/ash/nearby/presence/nearby_presence_service_factory.cc
@@ -13,7 +13,10 @@
 #include "chrome/browser/browser_features.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/ash/components/nearby/presence/nearby_presence_service_impl.h"
+#include "chromeos/ash/components/nearby/presence/prefs/nearby_presence_prefs.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/browser_context.h"
@@ -74,10 +77,13 @@
   // TODO(b/276344576): add the NearbyPresence feature flag.
 
   VLOG(1) << __func__ << ": creating NearbyPresenceService.";
-  return new NearbyPresenceServiceImpl();
+  return new NearbyPresenceServiceImpl(
+      Profile::FromBrowserContext(context)->GetPrefs());
 }
 
 void NearbyPresenceServiceFactory::RegisterProfilePrefs(
-    user_prefs::PrefRegistrySyncable* registry) {}
+    user_prefs::PrefRegistrySyncable* registry) {
+  RegisterNearbyPresencePrefs(registry);
+}
 
 }  // namespace ash::nearby::presence
diff --git a/chrome/browser/ash/policy/status_collector/app_info_generator.cc b/chrome/browser/ash/policy/status_collector/app_info_generator.cc
index 9223860..58f5785f 100644
--- a/chrome/browser/ash/policy/status_collector/app_info_generator.cc
+++ b/chrome/browser/ash/policy/status_collector/app_info_generator.cc
@@ -39,7 +39,7 @@
       return em::AppInfo::Status::AppInfo_Status_STATUS_INSTALLED;
     case apps::Readiness::kRemoved:
     case apps::Readiness::kUninstalledByUser:
-    case apps::Readiness::kUninstalledByMigration:
+    case apps::Readiness::kUninstalledByNonUser:
       return em::AppInfo::Status::AppInfo_Status_STATUS_UNINSTALLED;
     case apps::Readiness::kDisabledByBlocklist:
     case apps::Readiness::kDisabledByPolicy:
diff --git a/chrome/browser/ash/system_web_apps/system_web_app_manager_browsertest.cc b/chrome/browser/ash/system_web_apps/system_web_app_manager_browsertest.cc
index ef0eb5def..e5ad66c3 100644
--- a/chrome/browser/ash/system_web_apps/system_web_app_manager_browsertest.cc
+++ b/chrome/browser/ash/system_web_apps/system_web_app_manager_browsertest.cc
@@ -1020,7 +1020,7 @@
       [&](const apps::AppUpdate& app) {
         if ((app.AppType() == apps::AppType::kSystemWeb ||
              app.AppType() == apps::AppType::kWeb) &&
-            app.Readiness() != apps::Readiness::kUninstalledByMigration &&
+            app.Readiness() != apps::Readiness::kUninstalledByNonUser &&
             app.Readiness() != apps::Readiness::kUninstalledByUser) {
           swa_found = true;
         }
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.cc
index a9ee047..9c88e99 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.cc
@@ -210,6 +210,11 @@
   MaybeUpdateTopicSource(ash::AmbientModeTopicSource::kGooglePhotos);
 }
 
+void PersonalizationAppAmbientProviderImpl::SetScreenSaverDuration(
+    int minutes) {
+  Shell::Get()->ambient_controller()->SetScreenSaverDuration(minutes);
+}
+
 void PersonalizationAppAmbientProviderImpl::SetTemperatureUnit(
     ash::AmbientModeTemperatureUnit temperature_unit) {
   if (settings_->temperature_unit != temperature_unit) {
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.h b/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.h
index 3720bb5..85c5dc5 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.h
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl.h
@@ -54,6 +54,7 @@
           observer) override;
   void SetAmbientModeEnabled(bool enabled) override;
   void SetAnimationTheme(ash::AmbientTheme animation_theme) override;
+  void SetScreenSaverDuration(int minutes) override;
   void SetTopicSource(ash::AmbientModeTopicSource topic_source) override;
   void SetTemperatureUnit(
       ash::AmbientModeTemperatureUnit temperature_unit) override;
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl_unittest.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl_unittest.cc
index 1792b67..b802540 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl_unittest.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_ambient_provider_impl_unittest.cc
@@ -283,6 +283,10 @@
     ambient_provider_->UpdateSettings();
   }
 
+  void SetScreenSaverDuration(int minutes) {
+    ambient_provider_->SetScreenSaverDuration(minutes);
+  }
+
   void SetTopicSource(ash::AmbientModeTopicSource topic_source) {
     ambient_provider_->SetTopicSource(topic_source);
   }
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index 890cf13..39156bc6 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/feature_list.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "build/config/chromebox_for_meetings/buildflags.h"
@@ -312,6 +313,7 @@
 #include "chromeos/ash/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h"
 #include "chromeos/ash/services/cellular_setup/public/mojom/cellular_setup.mojom.h"
 #include "chromeos/ash/services/cellular_setup/public/mojom/esim_manager.mojom.h"
+#include "chromeos/ash/services/connectivity/public/mojom/passpoint.mojom.h"
 #include "chromeos/ash/services/hotspot_config/public/mojom/cros_hotspot_config.mojom.h"
 #include "chromeos/ash/services/multidevice_setup/multidevice_setup_service.h"
 #include "chromeos/ash/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
@@ -1223,6 +1225,13 @@
       ash::OobeUI, ash::settings::OSSettingsUI, ash::LockScreenNetworkUI,
       ash::ShimlessRMADialogUI>(map);
 
+  if (ash::features::IsPasspointSettingsEnabled()) {
+    RegisterWebUIControllerInterfaceBinder<
+        chromeos::connectivity::mojom::PasspointService,
+        ash::InternetDetailDialogUI, ash::NetworkUI,
+        ash::settings::OSSettingsUI>(map);
+  }
+
   RegisterWebUIControllerInterfaceBinder<
       chromeos::printing::printing_manager::mojom::PrintingMetadataProvider,
       ash::printing::printing_manager::PrintManagementUI>(map);
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_service_launcher.cc b/chrome/browser/chromeos/app_mode/kiosk_app_service_launcher.cc
index a69ec9c..a1a9685 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_service_launcher.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_service_launcher.cc
@@ -58,7 +58,7 @@
     case apps::Readiness::kDisabledByUser:
     case apps::Readiness::kUninstalledByUser:
     case apps::Readiness::kRemoved:
-    case apps::Readiness::kUninstalledByMigration:
+    case apps::Readiness::kUninstalledByNonUser:
       SYSLOG(ERROR) << "Kiosk app should not have readiness "
                     << base::to_underlying(readiness);
       if (app_launched_callback_.has_value()) {
diff --git a/chrome/browser/commerce/price_tracking/android/BUILD.gn b/chrome/browser/commerce/price_tracking/android/BUILD.gn
index 63bb412..b69e05e 100644
--- a/chrome/browser/commerce/price_tracking/android/BUILD.gn
+++ b/chrome/browser/commerce/price_tracking/android/BUILD.gn
@@ -18,11 +18,13 @@
 
   deps = [
     "//base:base_java",
+    "//chrome/browser/commerce/android:java",
     "//chrome/browser/flags:java",
     "//chrome/browser/notifications:java",
     "//chrome/browser/preferences:java",
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/signin/services/android:java",
+    "//components/commerce/core/android:core_java",
     "//components/signin/public/android:java",
     "//third_party/androidx:androidx_annotation_annotation_java",
   ]
diff --git a/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeatures.java b/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeatures.java
index 01257c4..64d1aa1 100644
--- a/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeatures.java
+++ b/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeatures.java
@@ -7,10 +7,13 @@
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.FeatureList;
+import org.chromium.chrome.browser.commerce.ShoppingServiceFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.profiles.ProfileManager;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.browser.signin.services.UnifiedConsentServiceBridge;
+import org.chromium.components.commerce.core.ShoppingService;
 import org.chromium.components.signin.identitymanager.ConsentLevel;
 
 import java.util.concurrent.TimeUnit;
@@ -18,8 +21,6 @@
 /** Flag configuration for price tracking features. */
 public class PriceTrackingFeatures {
     @VisibleForTesting
-    public static final String PRICE_TRACKING_PARAM = "enable_price_tracking";
-    @VisibleForTesting
     public static final String ALLOW_DISABLE_PRICE_ANNOTATIONS_PARAM =
             "allow_disable_price_annotations";
     @VisibleForTesting
@@ -29,23 +30,19 @@
             "price_annotations_enabled_metrics_window_duration_ms";
 
     private static Boolean sIsSignedInAndSyncEnabledForTesting;
-
-    /**
-     * @return whether or not price tracking is enabled.
-     */
-    public static boolean getPriceTrackingEnabled() {
-        if (FeatureList.isInitialized()) {
-            return ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
-                    ChromeFeatureList.COMMERCE_PRICE_TRACKING, PRICE_TRACKING_PARAM, false);
-        }
-        return false;
-    }
+    private static Boolean sPriceTrackingEnabledForTesting;
 
     /**
      * @return Whether the price tracking feature is eligible to work. Now it is used to determine
      *         whether the menu item "track prices" is visible and whether the tab has {@link
      *         TabProperties#SHOPPING_PERSISTED_TAB_DATA_FETCHER}.
      */
+    // TODO(b:277218890): Currently the method isPriceTrackingEnabled() is gating some
+    // infrastructure setup such as registering the message card in the tab switcher and adding
+    // observers for the price annotation preference, while the method isPriceTrackingEligible()
+    // requires users to sign in and enable MSBB and the returned value can change at runtime. We
+    // should implement this method in native as well and rename isPriceTrackingEnabled() to be less
+    // confusing.
     public static boolean isPriceTrackingEligible() {
         if (sIsSignedInAndSyncEnabledForTesting != null) {
             return isPriceTrackingEnabled() && sIsSignedInAndSyncEnabledForTesting;
@@ -53,11 +50,18 @@
         return isPriceTrackingEnabled() && isSignedIn() && isAnonymizedUrlDataCollectionEnabled();
     }
 
-    /**
-     * @return Whether the price tracking feature is enabled and available for use.
-     */
+    /** Wrapper function for ShoppingService.isCommercePriceTrackingEnabled(). */
     public static boolean isPriceTrackingEnabled() {
-        return getPriceTrackingEnabled();
+        if (sPriceTrackingEnabledForTesting != null) return sPriceTrackingEnabledForTesting;
+        if (!ProfileManager.isInitialized()) return false;
+
+        // TODO(b:277218890): Pass profile into this method/class instead of calling the
+        // Profile.getLastUsedRegularProfile() method.
+        Profile profile = Profile.getLastUsedRegularProfile();
+        if (profile == null) return false;
+        ShoppingService service = ShoppingServiceFactory.getForProfile(profile);
+        if (service == null) return false;
+        return service.isCommercePriceTrackingEnabled();
     }
 
     private static boolean isSignedIn() {
@@ -122,4 +126,9 @@
         }
         return isPriceTrackingEligible();
     }
-}
\ No newline at end of file
+
+    @VisibleForTesting
+    public static void setPriceTrackingEnabledForTesting(Boolean enabled) {
+        sPriceTrackingEnabledForTesting = enabled;
+    }
+}
diff --git a/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeaturesTest.java b/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeaturesTest.java
index 608673b..c66990e 100644
--- a/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeaturesTest.java
+++ b/chrome/browser/commerce/price_tracking/android/javatests/src/org/chromium/chrome/browser/price_tracking/PriceTrackingFeaturesTest.java
@@ -24,9 +24,6 @@
 import org.chromium.base.CollectionUtil;
 import org.chromium.base.test.UiThreadTest;
 import org.chromium.base.test.util.Batch;
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
-import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.browser.signin.services.UnifiedConsentServiceBridge;
@@ -35,7 +32,6 @@
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule;
 import org.chromium.chrome.test.util.browser.Features;
-import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.components.signin.identitymanager.IdentityManager;
 import org.chromium.components.sync.ModelType;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
@@ -45,10 +41,6 @@
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @Batch(Batch.PER_CLASS)
-@Features.DisableFeatures({ChromeFeatureList.START_SURFACE_ANDROID})
-@EnableFeatures({ChromeFeatureList.COMMERCE_PRICE_TRACKING + "<Study"})
-@CommandLineFlags.
-Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "force-fieldtrials=Study/Group"})
 public class PriceTrackingFeaturesTest {
     @ClassRule
     public static ChromeTabbedActivityTestRule sActivityTestRule =
@@ -80,6 +72,7 @@
         setMbbStatus(true);
         setSignedInStatus(true);
         setTabSyncStatus(true, true);
+        PriceTrackingFeatures.setPriceTrackingEnabledForTesting(true);
     }
 
     @After
@@ -87,12 +80,12 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> SyncService.resetForTests());
         IdentityServicesProvider.setInstanceForTests(null);
         PriceTrackingFeatures.setIsSignedInAndSyncEnabledForTesting(null);
+        PriceTrackingFeatures.setPriceTrackingEnabledForTesting(null);
     }
 
     @UiThreadTest
     @Test
     @SmallTest
-    @CommandLineFlags.Add({"force-fieldtrial-params=Study.Group:enable_price_tracking/true"})
     public void testIsPriceTrackingEligible() {
         Assert.assertTrue(PriceTrackingFeatures.isPriceTrackingEligible());
     }
@@ -100,16 +93,14 @@
     @UiThreadTest
     @Test
     @SmallTest
-    @CommandLineFlags.Add({"force-fieldtrial-params=Study.Group:enable_price_tracking/false"})
     public void testIsPriceTrackingEligibleFlagIsDisabled() {
+        PriceTrackingFeatures.setPriceTrackingEnabledForTesting(false);
         Assert.assertFalse(PriceTrackingFeatures.isPriceTrackingEligible());
     }
 
     @UiThreadTest
     @Test
     @SmallTest
-    @CommandLineFlags.Add({"force-fieldtrial-params=Study.Group:enable_price_tracking/true"})
-
     public void testIsPriceTrackingEligibleNoMbb() {
         setMbbStatus(false);
         Assert.assertFalse(PriceTrackingFeatures.isPriceTrackingEligible());
@@ -118,8 +109,6 @@
     @UiThreadTest
     @Test
     @SmallTest
-    @CommandLineFlags.Add({"force-fieldtrial-params=Study.Group:enable_price_tracking/true"})
-
     public void testIsPriceTrackingEligibleNotSignedIn() {
         setSignedInStatus(false);
         Assert.assertFalse(PriceTrackingFeatures.isPriceTrackingEligible());
@@ -128,7 +117,6 @@
     @UiThreadTest
     @Test
     @SmallTest
-    @CommandLineFlags.Add({"force-fieldtrial-params=Study.Group:enable_price_tracking/true"})
     public void testIsPriceTrackingEligibleTestHook() {
         setMbbStatus(false);
         setSignedInStatus(false);
diff --git a/chrome/browser/download/bubble/download_bubble_ui_controller.cc b/chrome/browser/download/bubble/download_bubble_ui_controller.cc
index 116c0af0..801aaa5 100644
--- a/chrome/browser/download/bubble/download_bubble_ui_controller.cc
+++ b/chrome/browser/download/bubble/download_bubble_ui_controller.cc
@@ -121,9 +121,14 @@
 
 void DownloadBubbleUIController::OnOfflineItemUpdated(const OfflineItem& item) {
   OfflineItemModel model(offline_manager_, item);
-  display_controller_->OnUpdatedItem(
-      model.IsDone(), IsPendingDeepScanning(&model),
-      browser_ == chrome::FindLastActiveWithProfile(profile_.get()));
+  bool may_show_details =
+      model.ShouldShowInBubble() &&
+      (browser_ == chrome::FindLastActiveWithProfile(profile_.get()));
+  // Consider dangerous in-progress downloads to be completed.
+  bool is_done = model.IsDone() ||
+                 (model.GetState() == download::DownloadItem::IN_PROGRESS &&
+                  !IsModelInProgress(&model));
+  display_controller_->OnUpdatedItem(is_done, may_show_details);
 }
 
 void DownloadBubbleUIController::OnDownloadItemUpdated(
@@ -132,8 +137,11 @@
   bool may_show_details =
       model.ShouldShowInBubble() &&
       (browser_ == chrome::FindLastActiveWithProfile(profile_.get()));
-  display_controller_->OnUpdatedItem(
-      item->IsDone(), IsPendingDeepScanning(&model), may_show_details);
+  // Consider dangerous in-progress downloads to be completed.
+  bool is_done = item->IsDone() ||
+                 (item->GetState() == download::DownloadItem::IN_PROGRESS &&
+                  !IsItemInProgress(item));
+  display_controller_->OnUpdatedItem(is_done, may_show_details);
 }
 
 std::vector<DownloadUIModelPtr> DownloadBubbleUIController::GetDownloadUIModels(
diff --git a/chrome/browser/download/bubble/download_bubble_ui_controller_unittest.cc b/chrome/browser/download/bubble/download_bubble_ui_controller_unittest.cc
index 38fa78c..20442eb 100644
--- a/chrome/browser/download/bubble/download_bubble_ui_controller_unittest.cc
+++ b/chrome/browser/download/bubble/download_bubble_ui_controller_unittest.cc
@@ -69,7 +69,7 @@
   }
   void MaybeShowButtonWhenCreated() override {}
   MOCK_METHOD1(OnNewItem, void(bool));
-  MOCK_METHOD3(OnUpdatedItem, void(bool, bool, bool));
+  MOCK_METHOD2(OnUpdatedItem, void(bool, bool));
   MOCK_METHOD1(OnRemovedItem, void(const ContentId&));
 };
 
@@ -271,6 +271,9 @@
         .WillRepeatedly(ReturnRef(GURL::EmptyGURL()));
     EXPECT_CALL(item(index), GetReferrerUrl())
         .WillRepeatedly(ReturnRef(GURL::EmptyGURL()));
+    EXPECT_CALL(item(index), GetDangerType())
+        .WillRepeatedly(
+            Return(DownloadDangerType::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS));
     std::vector<download::DownloadItem*> items;
     for (size_t i = 0; i < items_.size(); ++i) {
       items.push_back(&item(i));
@@ -371,14 +374,14 @@
   EXPECT_CALL(display_controller(), OnNewItem(true)).Times(1);
   InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"),
                    download::DownloadItem::IN_PROGRESS, ids[0]);
-  EXPECT_CALL(display_controller(), OnUpdatedItem(false, false, true)).Times(1);
+  EXPECT_CALL(display_controller(), OnUpdatedItem(false, true)).Times(1);
   UpdateDownloadItem(/*item_index=*/0, DownloadState::IN_PROGRESS);
-  EXPECT_CALL(display_controller(), OnUpdatedItem(true, false, true)).Times(1);
+  EXPECT_CALL(display_controller(), OnUpdatedItem(true, true)).Times(1);
   UpdateDownloadItem(/*item_index=*/0, DownloadState::COMPLETE);
 
   EXPECT_CALL(display_controller(), OnNewItem(false)).Times(1);
   InitOfflineItem(OfflineItemState::IN_PROGRESS, ids[1]);
-  EXPECT_CALL(display_controller(), OnUpdatedItem(true, false, true)).Times(1);
+  EXPECT_CALL(display_controller(), OnUpdatedItem(true, true)).Times(1);
   UpdateOfflineItem(/*item_index=*/0, OfflineItemState::COMPLETE);
 }
 
@@ -386,7 +389,7 @@
   EXPECT_CALL(display_controller(), OnNewItem(true)).Times(1);
   InitDownloadItem(FILE_PATH_LITERAL("/foo/bar.pdf"),
                    download::DownloadItem::IN_PROGRESS, "Download 1");
-  EXPECT_CALL(display_controller(), OnUpdatedItem(false, true, true)).Times(1);
+  EXPECT_CALL(display_controller(), OnUpdatedItem(true, true)).Times(1);
   UpdateDownloadItem(
       /*item_index=*/0, DownloadState::IN_PROGRESS, false,
       DownloadDangerType::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING);
diff --git a/chrome/browser/download/bubble/download_bubble_utils.cc b/chrome/browser/download/bubble/download_bubble_utils.cc
index 2efd9541..d0578ce 100644
--- a/chrome/browser/download/bubble/download_bubble_utils.cc
+++ b/chrome/browser/download/bubble/download_bubble_utils.cc
@@ -80,7 +80,7 @@
 }
 
 bool IsItemInProgress(const download::DownloadItem* item) {
-  if (item->IsDangerous() && !IsPendingDeepScanning(item)) {
+  if (item->IsDangerous() || IsPendingDeepScanning(item)) {
     return false;
   }
   return item->GetState() == download::DownloadItem::IN_PROGRESS;
@@ -97,7 +97,7 @@
 }
 
 bool IsModelInProgress(const DownloadUIModel* model) {
-  if (model->IsDangerous() && !IsPendingDeepScanning(model)) {
+  if (model->IsDangerous() || IsPendingDeepScanning(model)) {
     return false;
   }
   return model->GetState() == download::DownloadItem::IN_PROGRESS;
diff --git a/chrome/browser/download/bubble/download_bubble_utils.h b/chrome/browser/download/bubble/download_bubble_utils.h
index d7fda60b..53d84c6 100644
--- a/chrome/browser/download/bubble/download_bubble_utils.h
+++ b/chrome/browser/download/bubble/download_bubble_utils.h
@@ -29,9 +29,7 @@
 
 // Whether the download is considered in-progress from the UI's point of view.
 // Consider dangerous downloads as completed, because we don't want to encourage
-// users to interact with them. However, consider downloads pending scanning as
-// in progress, because we do want users to scan potential dangerous downloads.
-// Items that are paused count as in-progress.
+// users to interact with them. Items that are paused count as in-progress.
 bool IsItemInProgress(const download::DownloadItem* item);
 bool IsItemInProgress(const offline_items_collection::OfflineItem& item);
 bool IsModelInProgress(const DownloadUIModel* model);
diff --git a/chrome/browser/download/bubble/download_display_controller.cc b/chrome/browser/download/bubble/download_display_controller.cc
index e20d2bd..df5aa901 100644
--- a/chrome/browser/download/bubble/download_display_controller.cc
+++ b/chrome/browser/download/bubble/download_display_controller.cc
@@ -54,16 +54,10 @@
   bool has_unactioned = false;
   // From the button UI's perspective, whether the download is considered in
   // progress. Consider dangerous downloads as completed, because we don't want
-  // to encourage users to interact with them. However, consider downloads
-  // pending scanning as in progress, because we do want users to scan potential
-  // dangerous downloads.
+  // to encourage users to interact with them.
   int in_progress_count = 0;
   // Count of in-progress downloads (by the above definition) that are paused.
   int paused_count = 0;
-  // Whether there are no more in-progress downloads (by the above definition)
-  // that are not paused or pending deep scanning, i.e., whether all actively
-  // downloading items are done.
-  bool all_done = true;
 };
 
 AllDownloadUIModelsInfo GetAllModelsInfo(
@@ -82,17 +76,18 @@
       ++info.in_progress_count;
       if (model->IsPaused()) {
         ++info.paused_count;
-      } else if (!IsPendingDeepScanning(model.get())) {
-        // An in-progress download (by the above definition) is exactly one of
-        // actively downloading, paused, or pending deep scanning. If we got
-        // here, it is actively downloading and hence we are not all done.
-        info.all_done = false;
       }
     }
   }
   return info;
 }
 
+// Whether there are no more in-progress downloads (by the above definition)
+// that are not paused, i.e., whether all actively downloading items are done.
+bool IsAllDone(const AllDownloadUIModelsInfo& info) {
+  return info.in_progress_count == info.paused_count;
+}
+
 }  // namespace
 
 DownloadDisplayController::DownloadDisplayController(
@@ -139,7 +134,6 @@
 }
 
 void DownloadDisplayController::OnUpdatedItem(bool is_done,
-                                              bool is_deep_scanning,
                                               bool may_show_details) {
   if (!download::ShouldShowDownloadBubble(browser_->profile())) {
     return;
@@ -147,8 +141,7 @@
   std::vector<DownloadUIModelPtr> all_models =
       UpdateButtonStateFromAllModels(true);
   AllDownloadUIModelsInfo info = GetAllModelsInfo(all_models);
-  bool will_show_details =
-      may_show_details && ((is_done && info.all_done) || is_deep_scanning);
+  bool will_show_details = may_show_details && is_done && IsAllDone(info);
   if (is_done) {
     ScheduleToolbarDisappearance(kToolbarIconVisibilityTimeInterval);
   }
diff --git a/chrome/browser/download/bubble/download_display_controller.h b/chrome/browser/download/bubble/download_display_controller.h
index 7bc72f7..91ab749 100644
--- a/chrome/browser/download/bubble/download_display_controller.h
+++ b/chrome/browser/download/bubble/download_display_controller.h
@@ -83,14 +83,10 @@
   // |show_animation| specifies whether a small animated arrow should be shown.
   virtual void OnNewItem(bool show_animation);
   // Called from bubble controller when an item is updated, with |is_done|
-  // indicating if it was marked done, |is_pending_deep_scanning| indicating
-  // whether it is dangerous and pending deep scanning, and with
-  // |may_show_details| indicating whether the partial view can be shown.
-  // (Whether the partial view is actually shown may depend on the state of the
-  // other downloads.)
-  virtual void OnUpdatedItem(bool is_done,
-                             bool is_pending_deep_scanning,
-                             bool may_show_details);
+  // indicating if it was marked done, and with |may_show_details| indicating
+  // whether the partial view can be shown. (Whether the partial view is
+  // actually shown may depend on the state of the other downloads.)
+  virtual void OnUpdatedItem(bool is_done, bool may_show_details);
   // Called from bubble controller when an item is deleted.
   virtual void OnRemovedItem(const ContentId& id);
 
diff --git a/chrome/browser/download/bubble/download_display_controller_unittest.cc b/chrome/browser/download/bubble/download_display_controller_unittest.cc
index c66334b..183512bc 100644
--- a/chrome/browser/download/bubble/download_display_controller_unittest.cc
+++ b/chrome/browser/download/bubble/download_display_controller_unittest.cc
@@ -350,12 +350,9 @@
     controller().OnNewItem(/*show_animation=*/false);
   }
 
-  void UpdateOfflineItem(int item_index,
-                         OfflineItemState state,
-                         bool is_pending_deep_scanning) {
+  void UpdateOfflineItem(int item_index, OfflineItemState state) {
     offline_items_[item_index].state = state;
     controller().OnUpdatedItem(state == OfflineItemState::COMPLETE,
-                               is_pending_deep_scanning,
                                /*may_show_details=*/true);
   }
 
@@ -366,22 +363,28 @@
                           bool may_show_details = true) {
     DCHECK_GT(items_.size(), static_cast<size_t>(item_index));
 
+    // In-progress but dangerous downloads are considered complete.
+    // TODO(crbug.com/1433102): Don't duplicate this logic.
+    bool in_progress_dangerous =
+        (state == DownloadState::IN_PROGRESS &&
+         danger_type != download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
     EXPECT_CALL(item(item_index), GetState()).WillRepeatedly(Return(state));
     EXPECT_CALL(item(item_index), GetDangerType())
         .WillRepeatedly(Return(danger_type));
     if (state == DownloadState::COMPLETE) {
       EXPECT_CALL(item(item_index), IsDone()).WillRepeatedly(Return(true));
-      in_progress_count_--;
-      EXPECT_CALL(manager(), InProgressCount())
-          .WillRepeatedly(Return(in_progress_count_));
       DownloadPrefs::FromDownloadManager(&manager())
           ->SetLastCompleteTime(base::Time::Now());
     } else {
       EXPECT_CALL(item(item_index), IsDone()).WillRepeatedly(Return(false));
     }
+    if (state == DownloadState::COMPLETE || in_progress_dangerous) {
+      in_progress_count_--;
+      EXPECT_CALL(manager(), InProgressCount())
+          .WillRepeatedly(Return(in_progress_count_));
+    }
     controller().OnUpdatedItem(
-        state == DownloadState::COMPLETE,
-        danger_type == download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING,
+        state == DownloadState::COMPLETE || in_progress_dangerous,
         may_show_details);
   }
 
@@ -606,8 +609,7 @@
                                  /*icon_state=*/DownloadIconState::kProgress,
                                  /*is_active=*/true));
 
-  UpdateOfflineItem(/*item_index=*/0, OfflineItemState::COMPLETE,
-                    /*is_pending_deep_scanning=*/false);
+  UpdateOfflineItem(/*item_index=*/0, OfflineItemState::COMPLETE);
   // Details are shown because all items are complete.
   EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true,
                                  /*icon_state=*/DownloadIconState::kComplete,
@@ -650,10 +652,11 @@
 
   UpdateDownloadItem(/*item_index=*/0, DownloadState::IN_PROGRESS,
                      download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING);
-  // Details are shown because the scan is pending.
+  // Details are shown because the pending deep scan download is considered
+  // complete.
   EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true,
-                                 /*icon_state=*/DownloadIconState::kProgress,
-                                 /*is_active=*/true));
+                                 /*icon_state=*/DownloadIconState::kComplete,
+                                 /*is_active=*/false));
 
   // Reset details_shown while the downloads are in progress. This can happen if
   // the user clicks somewhere else to dismiss the download bubble.
@@ -711,18 +714,17 @@
   EXPECT_CALL(item(0), IsDangerous()).WillRepeatedly(Return(true));
   UpdateDownloadItem(/*item_index=*/0, DownloadState::IN_PROGRESS,
                      download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST);
-  // Details are not shown for most dangerous reasons.
-  EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/false,
+  // Dangerous downloads should be considered completed and
+  // should display details if there are no other in-progress downloads.
+  EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true,
                                  /*icon_state=*/DownloadIconState::kComplete,
                                  /*is_active=*/false));
 
-  // Downloads prompted for deep scanning should be considered in progress and
-  // should display details.
   UpdateDownloadItem(/*item_index=*/0, DownloadState::IN_PROGRESS,
                      download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING);
   EXPECT_TRUE(VerifyDisplayState(/*shown=*/true, /*detail_shown=*/true,
-                                 /*icon_state=*/DownloadIconState::kProgress,
-                                 /*is_active=*/true));
+                                 /*icon_state=*/DownloadIconState::kComplete,
+                                 /*is_active=*/false));
 }
 
 TEST_F(DownloadDisplayControllerTest, UpdateToolbarButtonState_OnRemovedItem) {
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_impl.mm b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_impl.mm
index c338bded..41991ed 100644
--- a/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_impl.mm
+++ b/chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client_impl.mm
@@ -112,15 +112,15 @@
                                 &kCFTypeDictionaryValueCallBacks));
   CFDictionarySetValue(attributes, kSecPrivateKeyAttrs, private_key_params);
   CFDictionarySetValue(private_key_params, kSecAttrIsPermanent, @YES);
-  CFDictionarySetValue(
-      private_key_params, kSecAttrAccessControl,
-      base::ScopedCFTypeRef<SecAccessControlRef>(
-          SecAccessControlCreateWithFlags(
-              kCFAllocatorDefault,
-              // Private key can only be used when the device is unlocked.
-              kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
-              // Private key is available for signing.
-              kSecAccessControlPrivateKeyUsage, nullptr)));
+  base::ScopedCFTypeRef<SecAccessControlRef> access_control(
+      SecAccessControlCreateWithFlags(
+          kCFAllocatorDefault,
+          // Private key can only be used when the device is unlocked.
+          kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
+          // Private key is available for signing.
+          kSecAccessControlPrivateKeyUsage, /*error=*/nullptr));
+  CFDictionarySetValue(private_key_params, kSecAttrAccessControl,
+                       access_control);
   return attributes;
 }
 
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
index eeec5882..eb759afe 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
+++ b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
@@ -159,7 +159,7 @@
     autofill::PersonalDataManager* personal_data,
     const absl::optional<std::string>& country_code) {
   static const base::NoDestructor<base::flat_set<std::string>>
-      kSanctionedCountries({"CU", "IR", "KP", "SD", "SY"});
+      kSanctionedCountries{{"CU", "IR", "KP", "SD", "SY"}};
   autofill::AutofillProfile::Source source =
       personal_data->IsEligibleForAddressAccountStorage()
           ? autofill::AutofillProfile::Source::kAccount
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index b71a69e..b88bbfd 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -734,6 +734,8 @@
       settings_api::PrefType::PREF_TYPE_NUMBER;
   (*s_allowlist)[ash::ambient::prefs::kAmbientModeAnimationPlaybackSpeed] =
       settings_api::PrefType::PREF_TYPE_NUMBER;
+  (*s_allowlist)[ash::ambient::prefs::kAmbientModeRunningDurationMinutes] =
+      settings_api::PrefType::PREF_TYPE_NUMBER;
 
   // Google Assistant.
   (*s_allowlist)[ash::assistant::prefs::kAssistantConsentStatus] =
diff --git a/chrome/browser/extensions/extension_action_runner.cc b/chrome/browser/extensions/extension_action_runner.cc
index 7904aaf..e493b93 100644
--- a/chrome/browser/extensions/extension_action_runner.cc
+++ b/chrome/browser/extensions/extension_action_runner.cc
@@ -67,9 +67,6 @@
 
 namespace extensions {
 
-const int ExtensionActionRunner::kRefreshRequiredActionsMask =
-    BLOCKED_ACTION_WEB_REQUEST | BLOCKED_ACTION_SCRIPT_AT_START;
-
 ExtensionActionRunner::PendingScript::PendingScript(
     mojom::RunLocation run_location,
     ScriptInjectionCallback permit_script)
@@ -137,72 +134,49 @@
   return ExtensionAction::ACTION_NONE;
 }
 
+// TODO(crbug.com/1400812): Consider moving this to SitePermissionsHelper since
+// it's more about permissions than running an action.
 void ExtensionActionRunner::GrantTabPermissions(
     const std::vector<const Extension*>& extensions) {
-  bool refresh_required =
-      base::ranges::any_of(extensions, [this](const Extension* extension) {
-        return PageNeedsRefreshToRun(extension);
+  SitePermissionsHelper permissions_helper(
+      Profile::FromBrowserContext(browser_context_));
+  bool refresh_required = base::ranges::any_of(
+      extensions, [this, &permissions_helper](const Extension* extension) {
+        return permissions_helper.PageNeedsRefreshToRun(
+            GetBlockedActions(extension->id()));
       });
 
+  // If a refresh is required this prevents blocked actions (that wouldn't run
+  // at the right time) from running until the user refreshes the page.
+  base::AutoReset<bool> ignore_active_tab(&ignore_active_tab_granted_,
+                                          refresh_required);
+  // Immediately grant permissions to every extension.
+  for (auto* extension : extensions) {
+    TabHelper::FromWebContents(web_contents())
+        ->active_tab_permission_granter()
+        ->GrantIfRequested(extension);
+  }
+
   if (!refresh_required) {
-    // Immediately grant permissions to every extension.
-    for (auto* extension : extensions) {
-      TabHelper::FromWebContents(web_contents())
-          ->active_tab_permission_granter()
-          ->GrantIfRequested(extension);
-    }
     return;
   }
 
-  // Every extension that wants tab permission is currently blocked and must
-  // have "on click" access.
+  // Every extension that was granted tab permission should currently have
+  // "on click" site access, but extension actions are still blocked as page
+  // hasn't been refreshed yet.
   const GURL& url = web_contents()->GetLastCommittedURL();
-  auto* permissions = PermissionsManager::Get(browser_context_);
+  auto* permissions_manager = PermissionsManager::Get(browser_context_);
   DCHECK(base::ranges::all_of(
-      extensions, [url, &permissions](const Extension* extension) {
-        return permissions->GetUserSiteAccess(*extension, url) ==
+      extensions, [url, &permissions_manager](const Extension* extension) {
+        return permissions_manager->GetUserSiteAccess(*extension, url) ==
                PermissionsManager::UserSiteAccess::kOnClick;
       }));
 
   std::vector<ExtensionId> extension_ids = GetExtensionIds(extensions);
   ShowReloadPageBubble(
       extension_ids,
-      base::BindOnce(&ExtensionActionRunner::
-                         OnReloadPageBubbleAcceptedForGrantTabPermissions,
-                     weak_factory_.GetWeakPtr(), extension_ids, url));
-}
-
-void ExtensionActionRunner::HandlePageAccessModified(
-    const Extension* extension,
-    PermissionsManager::UserSiteAccess current_access,
-    PermissionsManager::UserSiteAccess new_access) {
-  DCHECK_NE(current_access, new_access);
-  bool revoking_permissions =
-      new_access == PermissionsManager::UserSiteAccess::kOnClick;
-  int blocked_actions = GetBlockedActions(extension->id());
-
-  // Show the reload page dialog if revoking permissions, or increasing
-  // permissions with pending actions that mandate a page refresh. While
-  // revoking permissions doesn't necessarily mandate a page refresh, it is
-  // complicated to determine when an extension has affected the page. Showing a
-  // reload page bubble after the user blocks the extension re enforces the user
-  // confidence on blocking the extension. Also, this scenario should not be
-  // that common and therefore hopefully is not too noisy.
-  if (revoking_permissions || PageNeedsRefreshToRun(extension)) {
-    std::vector<ExtensionId> extension_ids;
-    ShowReloadPageBubble(
-        extension_ids,
-        base::BindOnce(
-            &ExtensionActionRunner::
-                OnReloadPageBubbleAcceptedForExtensionSiteAccessChange,
-            weak_factory_.GetWeakPtr(), extension->id(),
-            web_contents()->GetLastCommittedURL(), current_access, new_access));
-    return;
-  }
-
-  UpdatePageAccessSettings(extension, current_access, new_access);
-  if (blocked_actions)
-    RunBlockedActions(extension);
+      base::BindOnce(&ExtensionActionRunner::OnReloadPageBubbleAccepted,
+                     weak_factory_.GetWeakPtr()));
 }
 
 void ExtensionActionRunner::HandleUserSiteSettingModified(
@@ -257,7 +231,8 @@
               return permissions_helper.GetSiteInteraction(*extension,
                                                            web_contents()) ==
                          SitePermissionsHelper::SiteInteraction::kWithheld &&
-                     PageNeedsRefreshToRun(extension);
+                     permissions_helper.PageNeedsRefreshToRun(
+                         GetBlockedActions(extension->id()));
             });
         break;
       }
@@ -344,7 +319,8 @@
     test_observer_->OnBlockedActionAdded();
 }
 
-int ExtensionActionRunner::GetBlockedActions(const ExtensionId& extension_id) {
+int ExtensionActionRunner::GetBlockedActions(
+    const ExtensionId& extension_id) const {
   int blocked_actions = BLOCKED_ACTION_NONE;
   if (web_request_blocked_.count(extension_id) != 0)
     blocked_actions |= BLOCKED_ACTION_WEB_REQUEST;
@@ -520,6 +496,9 @@
   }
 }
 
+// TODO(crbug.com/1400812): Move the reload bubble outside of
+// `ExtensionActionRunner` as it is no longer tied to running an action. See if
+// it can be merged with extensions dialogs utils `ShowReloadPageDialog`.
 void ExtensionActionRunner::ShowReloadPageBubble(
     const std::vector<ExtensionId>& extension_ids,
     base::OnceClosure callback) {
@@ -545,49 +524,15 @@
   ShowReloadPageDialog(browser, extension_ids, std::move(callback));
 }
 
-void ExtensionActionRunner::OnReloadPageBubbleAcceptedForGrantTabPermissions(
-    const std::vector<ExtensionId>& extension_ids,
-    const GURL& page_url) {
-  // If the web contents have navigated to a different origin, do nothing.
-  if (!url::IsSameOriginWith(page_url, web_contents()->GetLastCommittedURL()))
-    return;
-
-  auto* registry = ExtensionRegistry::Get(browser_context_);
-  for (const auto& extension_id : extension_ids) {
-    const Extension* extension =
-        registry->enabled_extensions().GetByID(extension_id);
-    if (!extension)
-      continue;
-
-    base::AutoReset<bool> ignore_active_tab(&ignore_active_tab_granted_, true);
-    TabHelper::FromWebContents(web_contents())
-        ->active_tab_permission_granter()
-        ->GrantIfRequested(extension);
-  }
-
-  web_contents()->GetController().Reload(content::ReloadType::NORMAL, false);
+void ExtensionActionRunner::ShowReloadPageBubbleWithReloadPageCallback(
+    const ExtensionId& extension_id) {
+  ShowReloadPageBubble(
+      {extension_id},
+      base::BindOnce(&ExtensionActionRunner::OnReloadPageBubbleAccepted,
+                     weak_factory_.GetWeakPtr()));
 }
 
-void ExtensionActionRunner::
-    OnReloadPageBubbleAcceptedForExtensionSiteAccessChange(
-        const ExtensionId& extension_id,
-        const GURL& page_url,
-        PermissionsManager::UserSiteAccess current_access,
-        PermissionsManager::UserSiteAccess new_access) {
-  DCHECK_NE(current_access, new_access);
-  // If the web contents have navigated to a different origin, do nothing.
-  if (!url::IsSameOriginWith(page_url, web_contents()->GetLastCommittedURL()))
-    return;
-
-  // Extension could have been removed while the reload page bubble was open.
-  const Extension* extension = ExtensionRegistry::Get(browser_context_)
-                                   ->enabled_extensions()
-                                   .GetByID(extension_id);
-  if (!extension)
-    return;
-
-  UpdatePageAccessSettings(extension, current_access, new_access);
-
+void ExtensionActionRunner::OnReloadPageBubbleAccepted() {
   web_contents()->GetController().Reload(content::ReloadType::NORMAL, false);
 }
 
@@ -609,43 +554,6 @@
   web_contents()->GetController().Reload(content::ReloadType::NORMAL, false);
 }
 
-void ExtensionActionRunner::UpdatePageAccessSettings(
-    const Extension* extension,
-    PermissionsManager::UserSiteAccess current_access,
-    PermissionsManager::UserSiteAccess new_access) {
-  DCHECK_NE(current_access, new_access);
-
-  const GURL& url = web_contents()->GetLastCommittedURL();
-  ScriptingPermissionsModifier modifier(browser_context_, extension);
-  PermissionsManager* permissions_manager =
-      PermissionsManager::Get(browser_context_);
-  DCHECK(permissions_manager->CanAffectExtension(*extension));
-
-  switch (new_access) {
-    case PermissionsManager::UserSiteAccess::kOnClick:
-      if (permissions_manager->HasBroadGrantedHostPermissions(*extension))
-        modifier.RemoveBroadGrantedHostPermissions();
-      // Note: SetWithholdHostPermissions() is a no-op if host permissions are
-      // already being withheld.
-      modifier.SetWithholdHostPermissions(true);
-      if (permissions_manager->HasGrantedHostPermission(*extension, url))
-        modifier.RemoveGrantedHostPermission(url);
-      break;
-    case PermissionsManager::UserSiteAccess::kOnSite:
-      if (permissions_manager->HasBroadGrantedHostPermissions(*extension))
-        modifier.RemoveBroadGrantedHostPermissions();
-      // Note: SetWithholdHostPermissions() is a no-op if host permissions are
-      // already being withheld.
-      modifier.SetWithholdHostPermissions(true);
-      if (!permissions_manager->HasGrantedHostPermission(*extension, url))
-        modifier.GrantHostPermission(url);
-      break;
-    case PermissionsManager::UserSiteAccess::kOnAllSites:
-      modifier.SetWithholdHostPermissions(false);
-      break;
-  }
-}
-
 void ExtensionActionRunner::RunBlockedActions(const Extension* extension) {
   DCHECK(base::Contains(pending_scripts_, extension->id()) ||
          web_request_blocked_.count(extension->id()) != 0);
@@ -666,10 +574,6 @@
   NotifyChange(extension);
 }
 
-bool ExtensionActionRunner::PageNeedsRefreshToRun(const Extension* extension) {
-  return GetBlockedActions(extension->id()) & kRefreshRequiredActionsMask;
-}
-
 void ExtensionActionRunner::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
   declarative_net_request::RulesMonitorService* rules_monitor_service =
diff --git a/chrome/browser/extensions/extension_action_runner.h b/chrome/browser/extensions/extension_action_runner.h
index d6d6fb1..c1e18a0 100644
--- a/chrome/browser/extensions/extension_action_runner.h
+++ b/chrome/browser/extensions/extension_action_runner.h
@@ -66,20 +66,23 @@
   ExtensionAction::ShowAction RunAction(const Extension* extension,
                                         bool grant_tab_permissions);
 
-  // Grants activeTab to |extensions| (this should only be done if this is
-  // through a direct user action). If any extension needs a page refresh to
-  // run, this will show a dialog instead of immediately granting permissions.
+  // Runs any actions that were blocked for the given `extension`. As a
+  // requirement, this will grant activeTab permission to the extension.
+  void RunBlockedActions(const Extension* extension);
+
+  // Grants activeTab to `extensions` (this should only be done if this is
+  // through a direct user action). The permission will be applied immediately.
+  // If any extension needs a page refresh to run, this will show a dialog as
+  // well.
   void GrantTabPermissions(const std::vector<const Extension*>& extensions);
 
-  // Notifies the ExtensionActionRunner that the page access for |extension| has
-  // changed.
-  void HandlePageAccessModified(
-      const Extension* extension,
-      PermissionsManager::UserSiteAccess current_access,
-      PermissionsManager::UserSiteAccess new_access);
+  // The same as ShowReloadPageBubble, but for only one extension and the
+  // callback will reload the page.
+  void ShowReloadPageBubbleWithReloadPageCallback(
+      const ExtensionId& extension_id);
 
-  // Notifies the ExtensionActionRunner that the user site setting for `origin`
-  // with `action_ids` has changed.
+  // Notifies the ExtensionActionRunner that the user site setting for
+  // `origin` with `action_ids` has changed.
   void HandleUserSiteSettingModified(
       const base::flat_set<ToolbarActionsModel::ActionId>& action_ids,
       const url::Origin& origin,
@@ -95,7 +98,7 @@
 
   // Returns a bitmask of BlockedActionType for the actions that have been
   // blocked for the given extension.
-  int GetBlockedActions(const ExtensionId& extension_id);
+  int GetBlockedActions(const ExtensionId& extension_id) const;
 
   // Returns true if the given |extension| has any blocked actions.
   bool WantsToRun(const Extension* extension);
@@ -141,9 +144,6 @@
   }
 #endif  // defined(UNIT_TEST)
 
-  // The blocked actions that require a page refresh to run.
-  static const int kRefreshRequiredActionsMask;
-
  private:
   FRIEND_TEST_ALL_PREFIXES(ExtensionActionRunnerFencedFrameBrowserTest,
                            DoNotResetExtensionActionRunner);
@@ -188,25 +188,17 @@
   // Log metrics.
   void LogUMA() const;
 
+  // TODO(crbug.com/1400812): Move this method and
+  // `ShowReloadPageBubbleWithReloadPageCallback` out of EAR and/or combine with
+  // `ShowReloadPageDialog`.
   // Shows the bubble to prompt the user to refresh the page to run or not the
-  // action for the given |extension_ids|. |callback| is invoked when the
-  // bubble is closed.
+  // action for the given `extension_ids`. `callback` is invoked when the bubble
+  // is closed.
   void ShowReloadPageBubble(const std::vector<ExtensionId>& extension_ids,
                             base::OnceClosure callback);
 
-  // Called when the reload page bubble is accepted. Grants one time site access
-  // to `page_url` for each extension in `extension_ids`.
-  void OnReloadPageBubbleAcceptedForGrantTabPermissions(
-      const std::vector<ExtensionId>& extension_ids,
-      const GURL& page_url);
-
-  // Called when the reload page bubble is accepted. Updates site access of
-  // `extension_id` from `current_access` to `new_access` for `page_url`.
-  void OnReloadPageBubbleAcceptedForExtensionSiteAccessChange(
-      const ExtensionId& extension_id,
-      const GURL& page_url,
-      PermissionsManager::UserSiteAccess current_access,
-      PermissionsManager::UserSiteAccess new_access);
+  // Reloads the current page.
+  void OnReloadPageBubbleAccepted();
 
   // Called when the reload page bubble is accepted. Updates user site setting
   // of `origin` to `site_settings`.
@@ -214,21 +206,6 @@
       const url::Origin& origin,
       extensions::PermissionsManager::UserSiteSetting site_settings);
 
-  // Handles permission changes necessary for page access modification of the
-  // |extension|.
-  void UpdatePageAccessSettings(
-      const Extension* extension,
-      PermissionsManager::UserSiteAccess current_access,
-      PermissionsManager::UserSiteAccess new_access);
-
-  // Runs any actions that were blocked for the given |extension|. As a
-  // requirement, this will grant activeTab permission to the extension.
-  void RunBlockedActions(const Extension* extension);
-
-  // Returns true if the given `extension` needs a page refresh to run a blocked
-  // action.
-  bool PageNeedsRefreshToRun(const Extension* extension);
-
   // content::WebContentsObserver implementation.
   void DidFinishNavigation(
       content::NavigationHandle* navigation_handle) override;
diff --git a/chrome/browser/extensions/extension_action_runner_browsertest.cc b/chrome/browser/extensions/extension_action_runner_browsertest.cc
index 9eaa9c6..687f2983 100644
--- a/chrome/browser/extensions/extension_action_runner_browsertest.cc
+++ b/chrome/browser/extensions/extension_action_runner_browsertest.cc
@@ -81,6 +81,10 @@
   return content::ExecuteScript(web_contents, "1 == 1;");
 }
 
+// Returns whether the extension injected a script by checking the document
+// title. This assumes the use of test extension
+// 'extensions/blocked_actions/content_scripts' for this check to work as
+// expected.
 bool DidInjectScript(content::WebContents& web_contents) {
   return browsertest_util::DidChangeTitle(web_contents,
                                           /*original_title=*/u"OK",
@@ -419,7 +423,28 @@
   EXPECT_FALSE(inject_success_listener.was_satisfied());
 }
 
-IN_PROC_BROWSER_TEST_F(ExtensionActionRunnerBrowserTest, RunAction) {
+class ExtensionActionRunnerRunActionBubbleBrowserTest
+    : public ExtensionActionRunnerBrowserTest,
+      public testing::WithParamInterface<bool> {};
+
+INSTANTIATE_TEST_SUITE_P(
+    ,
+    ExtensionActionRunnerRunActionBubbleBrowserTest,
+    testing::Bool(),  // Accept reload bubble.
+    [](const testing::TestParamInfo<
+        ExtensionActionRunnerRunActionBubbleBrowserTest::ParamType>& info) {
+      return info.param ? "AcceptReload" : "DismissReload";
+    });
+
+// TODO(crbug.com/1378775): Test an extension that can be granted tab permission
+// but without a reload. And also running an action without granting tab
+// permission.
+
+// Tests that when running an action and accepting the reload bubble blocked
+// actions are run (script injects), but when the user dismissed the bubble
+// blocked actions are not run.
+IN_PROC_BROWSER_TEST_P(ExtensionActionRunnerRunActionBubbleBrowserTest,
+                       RunAction) {
   // Load an extension that wants to run on every page at document start, and
   // load a test page.
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -439,7 +464,8 @@
   const int nav_id = web_controller.GetLastCommittedEntry()->GetUniqueID();
 
   // The extension should want to run on the page, should not have
-  // injected, and should have "on click" access.
+  // injected, should have user site access "on click", and page interaction
+  // witheld.
   ExtensionActionRunner* runner =
       ExtensionActionRunner::GetForWebContents(web_contents);
   ASSERT_TRUE(runner);
@@ -448,44 +474,51 @@
   auto* permissions = PermissionsManager::Get(browser()->profile());
   EXPECT_EQ(permissions->GetUserSiteAccess(*extension, url),
             UserSiteAccess::kOnClick);
+  SitePermissionsHelper permissions_helper(browser()->profile());
+  EXPECT_EQ(permissions_helper.GetSiteInteraction(*extension, web_contents),
+            SitePermissionsHelper::SiteInteraction::kWithheld);
 
-  // Run the action without changing permissions, and reject the bubble
-  // prompting for page reload.
-  runner->accept_bubble_for_testing(false);
-  runner->RunAction(extension, true);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(content::WaitForLoadStop(web_contents));
+  const bool kAcceptReload = GetParam();
+  // Run the action and (accept or dismiss) the reload bubble depending on
+  // `kAcceptReload`.
+  runner->accept_bubble_for_testing(kAcceptReload);
+  runner->RunAction(extension, /*grant_tab_permissions=*/true);
 
-  // Nothing should happen, because the user didn't agree to reload the page.
-  // The extension should still want to run.
-  EXPECT_EQ(web_controller.GetLastCommittedEntry()->GetUniqueID(), nav_id);
-  EXPECT_FALSE(DidInjectScript(*web_contents));
-  EXPECT_TRUE(runner->WantsToRun(extension));
-
-  // Run the action without changing permissions, and accept the bubble
-  // prompting for page reload.
-  runner->accept_bubble_for_testing(true);
-  runner->RunAction(extension, true);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(content::WaitForLoadStop(web_contents));
-
-  // Since we automatically accepted the bubble prompting us, the page should
-  // have reload, the extension should have injected at document start and
-  // the site access should still be "on click".
-  EXPECT_GE(web_controller.GetLastCommittedEntry()->GetUniqueID(), nav_id);
-  EXPECT_TRUE(DidInjectScript(*web_contents));
-  EXPECT_FALSE(runner->WantsToRun(extension));
+  // Verify extension has granted site interaction (since it's immediately
+  // granted when running an action, regardless of page refresh) and its user
+  // site access is still on click (since running an action doesn't change the
+  // site access the user selected).
+  EXPECT_EQ(permissions_helper.GetSiteInteraction(*extension, web_contents),
+            SitePermissionsHelper::SiteInteraction::kGranted);
   EXPECT_EQ(permissions->GetUserSiteAccess(*extension, url),
             UserSiteAccess::kOnClick);
+
+  if (kAcceptReload) {
+    base::RunLoop().RunUntilIdle();
+    ASSERT_TRUE(content::WaitForLoadStop(web_contents));
+    // Since we automatically accepted the bubble prompting us, the page should
+    // have reloaded, the extension should have injected at document start, and
+    // the site access should still be "on click".
+    EXPECT_GE(web_controller.GetLastCommittedEntry()->GetUniqueID(), nav_id);
+    EXPECT_TRUE(DidInjectScript(*web_contents));
+    EXPECT_FALSE(runner->WantsToRun(extension));
+  } else {
+    // The script should not inject because it needs to run at start and we
+    // haven't reloaded the page, and there should be blocked actions to run
+    // since we haven't reloaded to run them.
+    EXPECT_FALSE(DidInjectScript(*web_contents));
+    EXPECT_TRUE(runner->WantsToRun(extension));
+  }
 }
 
-IN_PROC_BROWSER_TEST_F(ExtensionActionRunnerBrowserTest,
-                       HandlePageAccessModified) {
-  // Load an extension that wants to run on every page at document start, and
+// Tests that the blocked actions of an extension are run (e.g. scripts
+// injected) when calling this method.
+IN_PROC_BROWSER_TEST_F(ExtensionActionRunnerBrowserTest, RunBlockedActions) {
+  // Load an extension that wants to run on every page at document idle, and
   // load a test page.
   ASSERT_TRUE(embedded_test_server()->Start());
   const Extension* extension = LoadExtension(
-      test_data_dir_.AppendASCII("blocked_actions/content_scripts"));
+      test_data_dir_.AppendASCII("blocked_actions/content_script_at_idle"));
   ASSERT_TRUE(extension);
   ScriptingPermissionsModifier(profile(), extension)
       .SetWithholdHostPermissions(true);
@@ -496,53 +529,23 @@
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_TRUE(content::WaitForLoadStop(web_contents));
-  content::NavigationController& web_controller = web_contents->GetController();
-  const int nav_id = web_controller.GetLastCommittedEntry()->GetUniqueID();
 
-  // The extension should want to run on the page, should not have
-  // injected, and should have "on click" access.
+  // The extension should want to run on the page at first.
   ExtensionActionRunner* runner =
       ExtensionActionRunner::GetForWebContents(web_contents);
   ASSERT_TRUE(runner);
-  EXPECT_TRUE(runner->WantsToRun(extension));
-  EXPECT_FALSE(DidInjectScript(*web_contents));
-  auto* permissions = PermissionsManager::Get(browser()->profile());
-  EXPECT_EQ(permissions->GetUserSiteAccess(*extension, url),
-            UserSiteAccess::kOnClick);
+  ASSERT_TRUE(runner->WantsToRun(extension));
+  ExtensionTestMessageListener script_injection_listener("injection succeeded");
 
-  // Request a permission increase, and accept the bubble prompting for page
-  // refresh.
-  runner->accept_bubble_for_testing(true);
-  runner->HandlePageAccessModified(extension, UserSiteAccess::kOnClick,
-                                   UserSiteAccess::kOnSite);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(content::WaitForLoadStop(web_contents));
-
-  // Since we automatically accepted the bubble prompting us, the page should
-  // have refreshed, the extension should have injected at document start and
-  // the site access should now be "on site".
-  EXPECT_GE(web_controller.GetLastCommittedEntry()->GetUniqueID(), nav_id);
-  EXPECT_TRUE(DidInjectScript(*web_contents));
+  // Confirm that running blocked actions clears out any blocked actions for the
+  // extension.
+  runner->RunBlockedActions(extension);
+  SitePermissionsHelper permissions_helper(browser()->profile());
+  EXPECT_EQ(permissions_helper.GetSiteInteraction(*extension, web_contents),
+            extensions::SitePermissionsHelper::SiteInteraction::kGranted);
   EXPECT_FALSE(runner->WantsToRun(extension));
-  EXPECT_EQ(permissions->GetUserSiteAccess(*extension, url),
-            UserSiteAccess::kOnSite);
-
-  // Request a permission decrease, and accept the blocked action bubble
-  // prompting for page refresh.
-  runner->accept_bubble_for_testing(true);
-  runner->HandlePageAccessModified(extension, UserSiteAccess::kOnSite,
-                                   UserSiteAccess::kOnClick);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(content::WaitForLoadStop(web_contents));
-
-  // Since we automatically accepted the bubble prompting us, the page should
-  // have refreshed, the extension should not have injected at document start
-  // and the site access should now be "on click".
-  EXPECT_GE(web_controller.GetLastCommittedEntry()->GetUniqueID(), nav_id);
-  EXPECT_FALSE(DidInjectScript(*web_contents));
-  EXPECT_TRUE(runner->WantsToRun(extension));
-  EXPECT_EQ(permissions->GetUserSiteAccess(*extension, url),
-            UserSiteAccess::kOnClick);
+  EXPECT_TRUE(script_injection_listener.WaitUntilSatisfied());
+  EXPECT_TRUE(DidInjectScript(*web_contents));
 }
 
 // If we don't withhold permissions, extensions should execute normally.
@@ -710,8 +713,7 @@
     runner->accept_bubble_for_testing(accept_bubble);
 
     if (accept_bubble) {
-      PermissionsManagerWaiter waiter(
-          extensions::PermissionsManager::Get(profile()));
+      PermissionsManagerWaiter waiter(PermissionsManager::Get(profile()));
       runner->HandleUserSiteSettingModified({extension_id}, url_origin,
                                             user_site_setting);
       waiter.WaitForUserPermissionsSettingsChange();
diff --git a/chrome/browser/extensions/extension_action_runner_unittest.cc b/chrome/browser/extensions/extension_action_runner_unittest.cc
index 3dda4dd..6956a60 100644
--- a/chrome/browser/extensions/extension_action_runner_unittest.cc
+++ b/chrome/browser/extensions/extension_action_runner_unittest.cc
@@ -22,6 +22,7 @@
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test_utils.h"
 #include "content/public/test/navigation_simulator.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
@@ -66,7 +67,7 @@
   // a script.
   bool RequiresUserConsent(const Extension* extension) const;
 
-  // Request an injection for the given |extension|.
+  // Request an injection for the given `extension` at idle.
   void RequestInjection(const Extension* extension);
   void RequestInjection(const Extension* extension,
                         mojom::RunLocation run_location);
@@ -187,6 +188,32 @@
   DCHECK(extension_action_runner_);
 }
 
+// TODO(crbug.com/1400812): Split the test by need for refresh or not to confirm
+// the blocked actions are running as expected.
+// Tests that when an extension is granted permissions (independent of page
+// reload) the extension is allowed to run.
+TEST_F(ExtensionActionRunnerUnitTest, GrantTabPermissions) {
+  ActiveTabPermissionGranter* active_tab_permission_granter =
+      TabHelper::FromWebContents(web_contents())
+          ->active_tab_permission_granter();
+  ASSERT_TRUE(active_tab_permission_granter);
+
+  const Extension* extension = AddExtension();
+  EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
+  NavigateAndCommit(GURL("https://www.google.com"));
+  RequestInjection(extension);
+  EXPECT_TRUE(RequiresUserConsent(extension));
+  EXPECT_TRUE(runner()->WantsToRun(extension));
+
+  runner()->GrantTabPermissions({extension});
+  EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
+  task_environment()->RunUntilIdle();
+
+  EXPECT_EQ(1u, GetExecutionCountForExtension(extension->id()));
+  EXPECT_FALSE(RequiresUserConsent(extension));
+  EXPECT_FALSE(runner()->WantsToRun(extension));
+}
+
 // Test that extensions with all_hosts require permission to execute, and, once
 // that permission is granted, do execute.
 TEST_F(ExtensionActionRunnerUnitTest, RequestPermissionAndExecute) {
diff --git a/chrome/browser/extensions/site_permissions_helper.cc b/chrome/browser/extensions/site_permissions_helper.cc
index 050f8ea..59fad6b 100644
--- a/chrome/browser/extensions/site_permissions_helper.cc
+++ b/chrome/browser/extensions/site_permissions_helper.cc
@@ -6,6 +6,7 @@
 
 #include "chrome/browser/extensions/extension_action_runner.h"
 #include "chrome/browser/extensions/extension_util.h"
+#include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/sessions/content/session_tab_helper.h"
 #include "content/public/browser/web_contents.h"
@@ -22,6 +23,10 @@
 constexpr const char kPrefShowAccessRequestsInToolbar[] =
     "show_access_requests_in_toolbar";
 
+// The blocked actions that require a page refresh to run.
+constexpr int kRefreshRequiredActionsMask =
+    BLOCKED_ACTION_WEB_REQUEST | BLOCKED_ACTION_SCRIPT_AT_START;
+
 }  // namespace
 
 SitePermissionsHelper::SitePermissionsHelper(Profile* profile)
@@ -79,19 +84,76 @@
     const Extension& extension,
     content::WebContents* web_contents,
     PermissionsManager::UserSiteAccess new_access) {
-  ExtensionActionRunner* runner =
-      ExtensionActionRunner::GetForWebContents(web_contents);
-  if (!runner) {
-    return;
-  }
-
   auto current_access = PermissionsManager::Get(profile_)->GetUserSiteAccess(
       extension, web_contents->GetLastCommittedURL());
   if (new_access == current_access) {
     return;
   }
 
-  runner->HandlePageAccessModified(&extension, current_access, new_access);
+  const GURL& current_url = web_contents->GetLastCommittedURL();
+  ScriptingPermissionsModifier modifier(profile_, &extension);
+  PermissionsManager* permissions_manager = PermissionsManager::Get(profile_);
+  DCHECK(permissions_manager->CanAffectExtension(extension));
+
+  switch (new_access) {
+    case PermissionsManager::UserSiteAccess::kOnClick:
+      if (permissions_manager->HasBroadGrantedHostPermissions(extension)) {
+        modifier.RemoveBroadGrantedHostPermissions();
+      }
+      // Note: SetWithholdHostPermissions() is a no-op if host permissions are
+      // already being withheld.
+      modifier.SetWithholdHostPermissions(true);
+      if (permissions_manager->HasGrantedHostPermission(extension,
+                                                        current_url)) {
+        modifier.RemoveGrantedHostPermission(current_url);
+      }
+      break;
+    case PermissionsManager::UserSiteAccess::kOnSite:
+      if (permissions_manager->HasBroadGrantedHostPermissions(extension)) {
+        modifier.RemoveBroadGrantedHostPermissions();
+      }
+      // Note: SetWithholdHostPermissions() is a no-op if host permissions are
+      // already being withheld.
+      modifier.SetWithholdHostPermissions(true);
+      if (!permissions_manager->HasGrantedHostPermission(extension,
+                                                         current_url)) {
+        modifier.GrantHostPermission(current_url);
+      }
+      break;
+    case PermissionsManager::UserSiteAccess::kOnAllSites:
+      modifier.SetWithholdHostPermissions(false);
+      break;
+  }
+
+  ExtensionActionRunner* runner =
+      ExtensionActionRunner::GetForWebContents(web_contents);
+  if (!runner) {
+    return;
+  }
+
+  // This is to determine when to show the reload page dialog if revoking
+  // permissions, or increasing permissions with pending actions that mandate a
+  // page refresh. While revoking permissions doesn't necessarily mandate a page
+  // refresh, it is complicated to determine when an extension has affected the
+  // page. Showing a reload page bubble after the user blocks the extension re
+  // enforces the user confidence on blocking the extension. Also, this
+  // scenario should not be that common and therefore hopefully is not too
+  // noisy.
+  bool revoking_current_site_permissions =
+      new_access == PermissionsManager::UserSiteAccess::kOnClick;
+  int blocked_actions = runner->GetBlockedActions(extension.id());
+  bool reload_needed = revoking_current_site_permissions ||
+                       PageNeedsRefreshToRun(blocked_actions);
+
+  if (reload_needed) {
+    runner->ShowReloadPageBubbleWithReloadPageCallback(extension.id());
+  } else if (blocked_actions != BLOCKED_ACTION_NONE) {
+    runner->RunBlockedActions(&extension);
+  }
+}
+
+bool SitePermissionsHelper::PageNeedsRefreshToRun(int blocked_actions) {
+  return blocked_actions & kRefreshRequiredActionsMask;
 }
 
 void SitePermissionsHelper::UpdateUserSiteSettings(
diff --git a/chrome/browser/extensions/site_permissions_helper.h b/chrome/browser/extensions/site_permissions_helper.h
index f518d7d..231bff8 100644
--- a/chrome/browser/extensions/site_permissions_helper.h
+++ b/chrome/browser/extensions/site_permissions_helper.h
@@ -70,6 +70,9 @@
   bool HasBeenBlocked(const Extension& extension,
                       content::WebContents* web_contents) const;
 
+  // Returns whether the `blocked_actions` need a page refresh to run.
+  bool PageNeedsRefreshToRun(int blocked_actions);
+
   // Returns true if `extension_id` can show site access requests in the
   // toolbar.
   bool ShowAccessRequestsInToolbar(const std::string& extension_id);
diff --git a/chrome/browser/extensions/site_permissions_helper_browsertest.cc b/chrome/browser/extensions/site_permissions_helper_browsertest.cc
new file mode 100644
index 0000000..426c1f7d
--- /dev/null
+++ b/chrome/browser/extensions/site_permissions_helper_browsertest.cc
@@ -0,0 +1,280 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/site_permissions_helper.h"
+
+#include "base/run_loop.h"
+#include "chrome/browser/extensions/browsertest_util.h"
+#include "chrome/browser/extensions/extension_action_runner.h"
+#include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/extensions/scripting_permissions_modifier.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/test/browser_test.h"
+#include "extensions/browser/permissions_manager.h"
+#include "extensions/common/manifest_handlers/content_scripts_handler.h"
+#include "extensions/common/mojom/run_location.mojom-shared.h"
+#include "extensions/test/extension_test_message_listener.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace {
+
+using UserSiteAccess = PermissionsManager::UserSiteAccess;
+
+}  // namespace
+
+class SitePermissionsHelperBrowserTest : public ExtensionBrowserTest {
+ public:
+  SitePermissionsHelperBrowserTest() = default;
+
+  void SetUpOnMainThread() override {
+    ExtensionBrowserTest::SetUpOnMainThread();
+
+    // Loads an extension that can run on every page at document start. Then
+    // loads a test page and confirm it is running on the page.
+    ASSERT_TRUE(embedded_test_server()->Start());
+    extension_ = LoadExtension(
+        test_data_dir_.AppendASCII("blocked_actions/content_scripts"));
+    ASSERT_TRUE(extension_);
+
+    // Navigate to a page where the extension wants to run.
+    original_url_ = embedded_test_server()->GetURL("/simple.html");
+    ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), original_url_));
+    ASSERT_TRUE(content::WaitForLoadStop(active_web_contents()));
+    original_nav_id_ =
+        active_nav_controller().GetLastCommittedEntry()->GetUniqueID();
+
+    // The extension should want to run on the page, script should have
+    // injected, and should have "on all sites" access.
+    ASSERT_TRUE(active_action_runner());
+    ASSERT_FALSE(active_action_runner()->WantsToRun(extension_));
+    ASSERT_EQ(
+        ContentScriptsInfo::GetContentScripts(extension_)[0]->run_location(),
+        mojom::RunLocation::kDocumentStart);
+    ASSERT_TRUE(active_web_contents());
+    ASSERT_TRUE(ContentScriptInjected());
+    permissions_helper_ = std::make_unique<SitePermissionsHelper>(profile());
+    permissions_manager_ = PermissionsManager::Get(profile());
+    ASSERT_EQ(
+        permissions_manager_->GetUserSiteAccess(*extension_, original_url_),
+        UserSiteAccess::kOnAllSites);
+  }
+
+  void TearDownOnMainThread() override {
+    ExtensionBrowserTest::TearDownOnMainThread();
+    // Extension is created as a scoped_refptr so no need to delete.
+    extension_ = nullptr;
+    // Avoid dangling pointer.
+    permissions_manager_ = nullptr;
+    // Avoid dangling pointer to profile.
+    permissions_helper_.reset(nullptr);
+  }
+
+  // The content script for the extension was successfully injected into the
+  // page.
+  bool ContentScriptInjected();
+  // Extension has blocked actions that are pending to run.
+  bool ExtensionWantsToRun();
+
+  bool ReloadPageAndWaitForLoad();
+  bool WaitForReloadToFinish();
+
+  content::WebContents* active_web_contents() {
+    return browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
+  content::NavigationController& active_nav_controller() {
+    return active_web_contents()->GetController();
+  }
+
+  ExtensionActionRunner* active_action_runner() {
+    return ExtensionActionRunner::GetForWebContents(active_web_contents());
+  }
+
+ protected:
+  int original_nav_id_{0};
+  GURL original_url_{};
+  raw_ptr<const Extension> extension_;
+  std::unique_ptr<SitePermissionsHelper> permissions_helper_;
+  raw_ptr<PermissionsManager> permissions_manager_;
+};
+
+bool SitePermissionsHelperBrowserTest::ContentScriptInjected() {
+  return browsertest_util::DidChangeTitle(*active_web_contents(),
+                                          /*original_title=*/u"OK",
+                                          /*changed_title=*/u"success");
+}
+
+bool SitePermissionsHelperBrowserTest::ExtensionWantsToRun() {
+  return active_action_runner()->WantsToRun(extension_);
+}
+
+bool SitePermissionsHelperBrowserTest::ReloadPageAndWaitForLoad() {
+  active_web_contents()->GetController().Reload(content::ReloadType::NORMAL,
+                                                false);
+  return WaitForReloadToFinish();
+}
+
+bool SitePermissionsHelperBrowserTest::WaitForReloadToFinish() {
+  // This is needed in the instance where on site -> on-click revokes
+  // permissions. This is because when testing we run
+  // `ExtensionActionRunner::accept_bubble_for_testing(true)` which causes
+  // `ExtensionActionRunner::ShowReloadPageBubble(...)` to run the reload with
+  // a `base::SingleThreadTaskRunner` so we must wait for that to complete.
+  base::RunLoop().RunUntilIdle();
+  return content::WaitForLoadStop(active_web_contents());
+}
+
+// TODO(crbug.com/1400812): Paramertize these test scenarios (and the setup as
+// well). This would allow us to concisely describe the multiple state changes
+// and expected end states without having an individual test case for each or
+// (as below) have two large tests that rely on previous tests steps creating
+// state to proceed successfully.
+
+// Tests the various states of permission changes that can occur. When changes
+// occur we automatically accept the reload bubble, confirm the content script
+// for the extension is running/not running, and that we are still on the same
+// page after changing permissions. User site access changes are expected to be
+// immediate. There are many ASSERTS here because each test case is relying on
+// the previous changes completing in order to properly test its scenario.
+// Scenarios tested (in order):
+//
+//  on all sites -> on site
+//  on site -> on-click (refresh needed due to revoking permissions)
+//  on click -> on site  (refresh needed due to script wanting to load at start)
+//  on site -> on all sites
+//  on all sites -> on-click (refresh needed due to revoking permissions)
+IN_PROC_BROWSER_TEST_F(SitePermissionsHelperBrowserTest,
+                       UpdateSiteAccess_AcceptReloadBubble) {
+  // By default, test setup should set site access to be on all sites.
+  ASSERT_EQ(permissions_manager_->GetUserSiteAccess(*extension_, original_url_),
+            UserSiteAccess::kOnAllSites);
+  active_action_runner()->accept_bubble_for_testing(true);
+
+  // on all sites -> on site
+  permissions_helper_->UpdateSiteAccess(*extension_, active_web_contents(),
+                                        UserSiteAccess::kOnSite);
+  EXPECT_EQ(permissions_manager_->GetUserSiteAccess(*extension_, original_url_),
+            UserSiteAccess::kOnSite);
+  // We assume that there is only ever one action that wants to run for the test
+  // extension used by these tests. Anything else is an unexpected change, bug,
+  // or a flaw in the test.
+  ASSERT_TRUE(ContentScriptInjected());
+  ASSERT_FALSE(ExtensionWantsToRun());
+
+  // on site -> on-click (refresh needed due to revoking permissions)
+  permissions_helper_->UpdateSiteAccess(*extension_, active_web_contents(),
+                                        UserSiteAccess::kOnClick);
+  EXPECT_EQ(permissions_manager_->GetUserSiteAccess(*extension_, original_url_),
+            UserSiteAccess::kOnClick);
+  ASSERT_TRUE(WaitForReloadToFinish());
+  ASSERT_FALSE(ContentScriptInjected());
+  ASSERT_TRUE(ExtensionWantsToRun());
+
+  // on click -> on site (refresh needed due to script wanting to load at
+  // start)
+  permissions_helper_->UpdateSiteAccess(*extension_, active_web_contents(),
+                                        UserSiteAccess::kOnSite);
+  EXPECT_EQ(permissions_manager_->GetUserSiteAccess(*extension_, original_url_),
+            UserSiteAccess::kOnSite);
+  ASSERT_TRUE(WaitForReloadToFinish());
+  ASSERT_TRUE(ContentScriptInjected());
+  ASSERT_FALSE(ExtensionWantsToRun());
+
+  // on site -> on all sites
+  permissions_helper_->UpdateSiteAccess(*extension_, active_web_contents(),
+                                        UserSiteAccess::kOnAllSites);
+  EXPECT_EQ(permissions_manager_->GetUserSiteAccess(*extension_, original_url_),
+            UserSiteAccess::kOnAllSites);
+  ASSERT_TRUE(ContentScriptInjected());
+  ASSERT_FALSE(ExtensionWantsToRun());
+
+  // on all sites -> on-click (refresh needed due to revoking permissions)
+  permissions_helper_->UpdateSiteAccess(*extension_, active_web_contents(),
+                                        UserSiteAccess::kOnClick);
+  EXPECT_EQ(permissions_manager_->GetUserSiteAccess(*extension_, original_url_),
+            UserSiteAccess::kOnClick);
+  EXPECT_TRUE(WaitForReloadToFinish());
+  EXPECT_FALSE(ContentScriptInjected());
+  EXPECT_TRUE(ExtensionWantsToRun());
+}
+
+// Tests the various states of permission changes that can occur. When changes
+// occur we automatically dismiss the reload bubble, confirm the content script
+// for the extension is running/not running, and that we are still on the same
+// page after changing permissions. User site access changes are expected to be
+// immediate, but a reload is expected so we instead simulate reloading via the
+// "Reload this page" button. There are many ASSERTS here because each test case
+// is relying on the previous changes completing in order to properly test its
+// scenario. Scenarios tested (in order):
+//
+//  on all sites -> on site
+//  on site -> on-click (refresh needed, and done manually, due to revoking
+//    permissions)
+//  on click -> on site (refresh needed, and done manually, due to
+//    script wanting to load at start)
+//  on site -> on all sites on all sites -> on-click (refresh needed, and done
+//    manually due to revoking permissions)
+IN_PROC_BROWSER_TEST_F(
+    SitePermissionsHelperBrowserTest,
+    UpdateSiteAccess_DismissReloadBubble_ReloadPageManually) {
+  // By default, test setup should set site access to be on all sites.
+  ASSERT_EQ(permissions_manager_->GetUserSiteAccess(*extension_, original_url_),
+            UserSiteAccess::kOnAllSites);
+  // Reload will not happen via the user reload bubble.
+  active_action_runner()->accept_bubble_for_testing(false);
+
+  // on all sites -> on site
+  permissions_helper_->UpdateSiteAccess(*extension_, active_web_contents(),
+                                        UserSiteAccess::kOnSite);
+  EXPECT_EQ(permissions_manager_->GetUserSiteAccess(*extension_, original_url_),
+            UserSiteAccess::kOnSite);
+  // We assume that there is only ever one action that wants to run for the test
+  // extension used by these tests. Anything else is an unexpected change, bug,
+  // or a flaw in the test.
+  ASSERT_TRUE(ContentScriptInjected());
+  ASSERT_FALSE(ExtensionWantsToRun());
+
+  // on site -> on-click (refresh needed due to revoking permissions)
+  permissions_helper_->UpdateSiteAccess(*extension_, active_web_contents(),
+                                        UserSiteAccess::kOnClick);
+  EXPECT_EQ(permissions_manager_->GetUserSiteAccess(*extension_, original_url_),
+            UserSiteAccess::kOnClick);
+  EXPECT_TRUE(ContentScriptInjected() && !ExtensionWantsToRun());
+  ASSERT_TRUE(ReloadPageAndWaitForLoad());
+  ASSERT_FALSE(ContentScriptInjected());
+  ASSERT_TRUE(ExtensionWantsToRun());
+
+  // on click -> on site (refresh needed due to script wanting to load at
+  // start)
+  permissions_helper_->UpdateSiteAccess(*extension_, active_web_contents(),
+                                        UserSiteAccess::kOnSite);
+  EXPECT_EQ(permissions_manager_->GetUserSiteAccess(*extension_, original_url_),
+            UserSiteAccess::kOnSite);
+  EXPECT_TRUE(!ContentScriptInjected() && ExtensionWantsToRun());
+  ASSERT_TRUE(ReloadPageAndWaitForLoad());
+  ASSERT_TRUE(ContentScriptInjected());
+  ASSERT_FALSE(ExtensionWantsToRun());
+
+  // on site -> on all sites
+  permissions_helper_->UpdateSiteAccess(*extension_, active_web_contents(),
+                                        UserSiteAccess::kOnAllSites);
+  EXPECT_EQ(permissions_manager_->GetUserSiteAccess(*extension_, original_url_),
+            UserSiteAccess::kOnAllSites);
+  ASSERT_TRUE(ContentScriptInjected());
+  ASSERT_FALSE(ExtensionWantsToRun());
+
+  // on all sites -> on-click (refresh needed due to revoking permissions)
+  permissions_helper_->UpdateSiteAccess(*extension_, active_web_contents(),
+                                        UserSiteAccess::kOnClick);
+  EXPECT_EQ(permissions_manager_->GetUserSiteAccess(*extension_, original_url_),
+            UserSiteAccess::kOnClick);
+  EXPECT_TRUE(ContentScriptInjected() && !ExtensionWantsToRun());
+  ASSERT_TRUE(ReloadPageAndWaitForLoad());
+  EXPECT_TRUE(!ContentScriptInjected() && ExtensionWantsToRun());
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/site_permissions_helper_unittest.cc b/chrome/browser/extensions/site_permissions_helper_unittest.cc
index f1537671..83de53b5 100644
--- a/chrome/browser/extensions/site_permissions_helper_unittest.cc
+++ b/chrome/browser/extensions/site_permissions_helper_unittest.cc
@@ -293,6 +293,40 @@
             SiteInteraction::kNone);
 }
 
+// Tests that updating permission only applies the permission to the upgraded
+// site and not others.
+TEST_F(SitePermissionsHelperUnitTest, UpdateSiteAccess_OnlySiteSelected) {
+  const GURL site("https://allowed.example");
+  auto extension = InstallExtensionWithPermissions(
+      "extension", /*host_permissions=*/{site.spec()});
+  const GURL site_without_permission("https://disallowed.com");
+  auto* site_contents = AddTab(site);
+
+  // Extension should only have on-click access to both sites.
+  ASSERT_EQ(PermissionsManager::UserSiteAccess::kOnSite,
+            permissions_manager()->GetUserSiteAccess(*extension, site));
+  EXPECT_EQ(PermissionsManager::UserSiteAccess::kOnClick,
+            permissions_manager()->GetUserSiteAccess(*extension,
+                                                     site_without_permission));
+
+  // Switch the extension from on-click to always on site.
+  ExtensionActionRunner* action_runner =
+      ExtensionActionRunner::GetForWebContents(site_contents);
+  ASSERT_TRUE(action_runner);
+  action_runner->accept_bubble_for_testing(false);
+  permissions_helper()->UpdateSiteAccess(
+      *extension, site_contents, PermissionsManager::UserSiteAccess::kOnClick);
+
+  // Confirm always on site permission applied.
+  EXPECT_EQ(PermissionsManager::UserSiteAccess::kOnClick,
+            permissions_manager()->GetUserSiteAccess(*extension, site));
+
+  // Site without permission should remain without access.
+  EXPECT_EQ(PermissionsManager::UserSiteAccess::kOnClick,
+            permissions_manager()->GetUserSiteAccess(*extension,
+                                                     site_without_permission));
+}
+
 class SitePermissionsHelperWithUserHostControlsUnitTest
     : public SitePermissionsHelperUnitTest {
  public:
@@ -357,7 +391,9 @@
     ExtensionActionRunner* action_runner =
         ExtensionActionRunner::GetForWebContents(non_user_permitted_contents);
     ASSERT_TRUE(action_runner);
-    action_runner->accept_bubble_for_testing(true);
+    // Permissions for the site are still updated even if the tab is not
+    // reloaded.
+    action_runner->accept_bubble_for_testing(false);
     PermissionsManagerWaiter waiter(permissions_manager());
     permissions_helper()->UpdateSiteAccess(
         *extension, non_user_permitted_contents, UserSiteAccess::kOnClick);
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSliceViewTracker.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSliceViewTracker.java
index b98b457..676e540 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSliceViewTracker.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSliceViewTracker.java
@@ -15,6 +15,8 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.recyclerview.widget.RecyclerView;
 
+import org.chromium.base.task.PostTask;
+import org.chromium.base.task.TaskTraits;
 import org.chromium.chrome.browser.xsurface.ListLayoutHelper;
 
 import java.util.ArrayList;
@@ -30,6 +32,7 @@
     private static final float DEFAULT_VIEW_LOG_THRESHOLD = .66f;
     private static final float GOOD_VISITS_EXPOSURE_THRESHOLD = 0.5f;
     private static final float GOOD_VISITS_COVERAGE_THRESHOLD = 0.25f;
+    private static final float VISIBLE_CHANGE_LOG_THRESHOLD = 0.05f;
 
     private class VisibilityObserver {
         final float mVisibilityThreshold;
@@ -42,13 +45,19 @@
     }
 
     private final Activity mActivity;
+    // Whether to watch a slice view to get notified for barely visible change.
+    private final boolean mWatchForBarelyVisibleChange;
     @Nullable
     private RecyclerView mRootView;
     @Nullable
     private FeedListContentManager mContentManager;
     private ListLayoutHelper mLayoutHelper;
-    // The set of content keys already reported as visible.
-    private HashSet<String> mContentKeysVisible = new HashSet<String>();
+    // The set of content keys already reported as mostly visible (66% threshold), which is used to
+    // determine if a slice has been viewed by the user.
+    private HashSet<String> mContentKeysMostlyVisible = new HashSet<String>();
+    // The set of content keys already reported as barely visible (5% threshold), which is used to
+    // determine if a slice has entered the view port.
+    private HashSet<String> mContentKeysBarelyVisible = new HashSet<>();
     private boolean mFeedContentVisible;
     @Nullable
     private Observer mObserver;
@@ -69,15 +78,23 @@
         // Invoked when feed content is first visible. This can happens as soon as an xsurface view
         // is partially visible.
         void feedContentVisible();
+
+        // For reporting to feed user interaction reliability log.
+        //
+        // Called the first time a slice view is 5% visible.
+        void reportViewFirstBarelyVisible(View view);
+        // Called the first time a slice view is rendered.
+        void reportViewFirstRendered(View view);
     }
 
     public FeedSliceViewTracker(@NonNull RecyclerView rootView, @NonNull Activity activity,
             @NonNull FeedListContentManager contentManager, @Nullable ListLayoutHelper layoutHelper,
-            @NonNull Observer observer) {
+            boolean watchForBarelyVisibleChange, @NonNull Observer observer) {
         mActivity = activity;
         mRootView = rootView;
         mContentManager = contentManager;
         mLayoutHelper = layoutHelper;
+        mWatchForBarelyVisibleChange = watchForBarelyVisibleChange;
         mObserver = observer;
     }
 
@@ -109,11 +126,12 @@
      * Clear tracking so that slices already seen can be reported as viewed again.
      */
     public void clear() {
-        mContentKeysVisible.clear();
+        mContentKeysMostlyVisible.clear();
         mFeedContentVisible = false;
         if (mWatchedSliceMap != null) {
             mWatchedSliceMap.clear();
         }
+        mContentKeysBarelyVisible.clear();
     }
 
     /**
@@ -210,13 +228,26 @@
                     || isViewVisible(childView, GOOD_VISITS_EXPOSURE_THRESHOLD)
                     || isViewCoveringViewport(childView, GOOD_VISITS_COVERAGE_THRESHOLD);
 
-            if (mContentKeysVisible.contains(contentKey)
-                    || !isViewVisible(childView, DEFAULT_VIEW_LOG_THRESHOLD)) {
-                continue;
+            if (!mContentKeysMostlyVisible.contains(contentKey)
+                    && isViewVisible(childView, DEFAULT_VIEW_LOG_THRESHOLD)) {
+                mContentKeysMostlyVisible.add(contentKey);
+                mObserver.sliceVisible(contentKey);
             }
 
-            mContentKeysVisible.add(contentKey);
-            mObserver.sliceVisible(contentKey);
+            if (mWatchForBarelyVisibleChange && !mContentKeysBarelyVisible.contains(contentKey)
+                    && isViewVisible(childView, VISIBLE_CHANGE_LOG_THRESHOLD)) {
+                mObserver.reportViewFirstBarelyVisible(childView);
+                // There is not a system way to measure the render latency. Here we mimic how
+                // Time To First Draw Done is measured, which is done by posting a runnable after
+                // onPreDraw.
+                Runnable renderedRunnable = () -> {
+                    if (mObserver != null) {
+                        mObserver.reportViewFirstRendered(childView);
+                    }
+                };
+                PostTask.postTask(TaskTraits.UI_DEFAULT, renderedRunnable);
+                mContentKeysBarelyVisible.add(contentKey);
+            }
         }
 
         reportTimeForGoodVisitsIfNeeded();
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSliceViewTrackerTest.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSliceViewTrackerTest.java
index ebebdf0..91ea3887 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSliceViewTrackerTest.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSliceViewTrackerTest.java
@@ -18,9 +18,11 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
 
 import android.app.Activity;
 import android.graphics.Rect;
+import android.os.Looper;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.Window;
@@ -95,8 +97,8 @@
         doReturn(mViewTreeObserver).when(mParentView).getViewTreeObserver();
         doReturn(mWindow).when(mActivity).getWindow();
         doReturn(mDecorView).when(mWindow).getDecorView();
-        mTracker = Mockito.spy(new FeedSliceViewTracker(
-                mParentView, mActivity, mContentManager, mLayoutHelper, mObserver));
+        mTracker = Mockito.spy(new FeedSliceViewTracker(mParentView, mActivity, mContentManager,
+                mLayoutHelper, /* watchForBarelyVisibleChange= */ true, mObserver));
     }
 
     @After
@@ -514,6 +516,28 @@
         verify(mObserver, times(1)).reportContentSliceVisibleTime(eq(1L));
     }
 
+    @Test
+    @SmallTest
+    public void testReportViewFirstVisibleAndRendered() {
+        mContentManager.addContents(0,
+                Arrays.asList(new FeedListContentManager.FeedContent[] {
+                        new FeedListContentManager.NativeViewContent(0, "c/key1", mChildA),
+                }));
+        doReturn(0).when(mLayoutHelper).findFirstVisibleItemPosition();
+        doReturn(0).when(mLayoutHelper).findLastVisibleItemPosition();
+        doReturn(mChildA).when(mLayoutManager).findViewByPosition(eq(0));
+
+        // View only covers 5% of the viewport.
+        mockViewportRect(0, 0, 100, 100);
+        mockViewDimensions(mChildA, 100, 5);
+        mockGetChildVisibleRect(mChildA, 0, 0, 100, 5);
+
+        mTracker.onPreDraw();
+        verify(mObserver, times(1)).reportViewFirstBarelyVisible(any());
+        shadowOf(Looper.getMainLooper()).idle();
+        verify(mObserver, times(1)).reportViewFirstRendered(any());
+    }
+
     void mockViewDimensions(View view, int width, int height) {
         when(view.getWidth()).thenReturn(width);
         when(view.getHeight()).thenReturn(height);
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
index 6efb6b8..bd61ea5 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
@@ -24,6 +24,7 @@
 import androidx.recyclerview.widget.RecyclerView.LayoutManager;
 
 import org.chromium.base.Callback;
+import org.chromium.base.FeatureList;
 import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
 import org.chromium.base.ThreadUtils;
@@ -50,6 +51,7 @@
 import org.chromium.chrome.browser.xsurface.FeedActionsHandler;
 import org.chromium.chrome.browser.xsurface.FeedLaunchReliabilityLogger;
 import org.chromium.chrome.browser.xsurface.FeedLaunchReliabilityLogger.StreamType;
+import org.chromium.chrome.browser.xsurface.FeedUserInteractionReliabilityLogger;
 import org.chromium.chrome.browser.xsurface.HybridListRenderer;
 import org.chromium.chrome.browser.xsurface.ListLayoutHelper;
 import org.chromium.chrome.browser.xsurface.LoggingParameters;
@@ -615,6 +617,7 @@
     private RotationObserver mRotationObserver;
     private FeedReliabilityLoggingBridge mReliabilityLoggingBridge;
     private FeedLaunchReliabilityLogger mLaunchReliabilityLogger;
+    private FeedUserInteractionReliabilityLogger mFeedUserInteractionReliabilityLogger;
 
     // Things valid only when bound.
     private @Nullable RecyclerView mRecyclerView;
@@ -768,10 +771,20 @@
         launchReliabilityLogger.logFeedReloading(System.nanoTime());
         mReliabilityLoggingBridge.setLogger(launchReliabilityLogger);
 
+        if (FeatureList.isInitialized()
+                && ChromeFeatureList.isEnabled(
+                        ChromeFeatureList.FEED_USER_INTERACTION_RELIABILITY_REPORT)
+                && surfaceScope != null) {
+            mFeedUserInteractionReliabilityLogger =
+                    surfaceScope.getFeedUserInteractionReliabilityLogger();
+        }
+
         mScrollStateToRestore = savedInstanceState;
         manager.setHandlers(mHandlersMap);
         mSliceViewTracker = new FeedSliceViewTracker(rootView, mActivity, manager,
-                renderer.getListLayoutHelper(), new FeedStream.ViewTrackerObserver());
+                renderer.getListLayoutHelper(), /* watchForBarelyVisibleChange= */
+                (mFeedUserInteractionReliabilityLogger != null),
+                new FeedStream.ViewTrackerObserver());
         mSliceViewTracker.bind();
 
         rootView.addOnScrollListener(mMainScrollListener);
@@ -792,6 +805,10 @@
         }
 
         FeedStreamJni.get().surfaceOpened(mNativeFeedStream, FeedStream.this);
+
+        if (mFeedUserInteractionReliabilityLogger != null) {
+            mFeedUserInteractionReliabilityLogger.onStreamOpened(getXSurfaceStreamType());
+        }
     }
 
     @Override
@@ -1188,6 +1205,20 @@
         }
     }
 
+    // TODO(jianli): Consolidate 2 StreamType defined in different places.
+    private @org.chromium.chrome.browser.xsurface.StreamType int getXSurfaceStreamType() {
+        switch (mStreamKind) {
+            case StreamKind.FOR_YOU:
+                return org.chromium.chrome.browser.xsurface.StreamType.FOR_YOU;
+            case StreamKind.FOLLOWING:
+                return org.chromium.chrome.browser.xsurface.StreamType.WEB_FEED;
+            case StreamKind.SINGLE_WEB_FEED:
+                return org.chromium.chrome.browser.xsurface.StreamType.SINGLE_WEB_FEED;
+            default:
+                return org.chromium.chrome.browser.xsurface.StreamType.UNSPECIFIED;
+        }
+    }
+
     /**
      * Restores the scroll state serialized to |savedInstanceState|.
      * @return true if the scroll state was restored, or if the state could never be restored.
@@ -1322,6 +1353,18 @@
         public void feedContentVisible() {
             FeedStreamJni.get().reportFeedViewed(mNativeFeedStream, FeedStream.this);
         }
+        @Override
+        public void reportViewFirstBarelyVisible(View view) {
+            if (mFeedUserInteractionReliabilityLogger != null) {
+                mFeedUserInteractionReliabilityLogger.onViewFirstVisible(view);
+            }
+        }
+        @Override
+        public void reportViewFirstRendered(View view) {
+            if (mFeedUserInteractionReliabilityLogger != null) {
+                mFeedUserInteractionReliabilityLogger.onViewFirstRendered(view);
+            }
+        }
     }
 
     /**
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStreamTest.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStreamTest.java
index afd6ef2..5a56d8c 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStreamTest.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStreamTest.java
@@ -70,6 +70,7 @@
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.xsurface.FeedActionsHandler;
 import org.chromium.chrome.browser.xsurface.FeedLaunchReliabilityLogger;
+import org.chromium.chrome.browser.xsurface.FeedUserInteractionReliabilityLogger;
 import org.chromium.chrome.browser.xsurface.HybridListRenderer;
 import org.chromium.chrome.browser.xsurface.SurfaceActionsHandler;
 import org.chromium.chrome.browser.xsurface.SurfaceActionsHandler.OpenMode;
@@ -145,6 +146,8 @@
     @Mock
     private FeedLaunchReliabilityLogger mLaunchReliabilityLogger;
     @Mock
+    private FeedUserInteractionReliabilityLogger mUserInteractionReliabilityLogger;
+    @Mock
     private FeedActionDelegate mActionDelegate;
     @Mock
     WebFeedBridge.Natives mWebFeedBridgeJni;
@@ -172,6 +175,7 @@
     private void setFeatureOverrides(boolean feedLoadingPlaceholderOn) {
         Map<String, Boolean> overrides = new ArrayMap<>();
         overrides.put(ChromeFeatureList.FEED_LOADING_PLACEHOLDER, feedLoadingPlaceholderOn);
+        overrides.put(ChromeFeatureList.FEED_USER_INTERACTION_RELIABILITY_REPORT, true);
         FeatureList.setTestFeatures(overrides);
     }
 
@@ -191,6 +195,8 @@
                 .thenReturn(LOAD_MORE_TRIGGER_LOOKAHEAD);
         when(mFeedServiceBridgeJniMock.getLoadMoreTriggerScrollDistanceDp())
                 .thenReturn(LOAD_MORE_TRIGGER_SCROLL_DISTANCE_DP);
+        when(mSurfaceScope.getFeedUserInteractionReliabilityLogger())
+                .thenReturn(mUserInteractionReliabilityLogger);
         mFeedStream = new FeedStream(mActivity, mSnackbarManager, mBottomSheetController,
                 /* isPlaceholderShown= */ false, mWindowAndroid, mShareDelegateSupplier,
                 /* isInterestFeed= */ StreamKind.FOR_YOU,
@@ -1173,6 +1179,14 @@
         assertTrue(stream.supportsOptions());
     }
 
+    @Test
+    @SmallTest
+    public void testReportStreamOpened() {
+        bindToView();
+        verify(mUserInteractionReliabilityLogger).onStreamOpened(anyInt());
+        mFeedStream.unbind(false);
+    }
+
     private int getLoadMoreTriggerScrollDistance() {
         return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                 LOAD_MORE_TRIGGER_SCROLL_DISTANCE_DP,
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/signinbottomsheet/SigninBottomSheetCoordinator.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/signinbottomsheet/SigninBottomSheetCoordinator.java
index 78f4c371..c0139f86 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/signinbottomsheet/SigninBottomSheetCoordinator.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/signinbottomsheet/SigninBottomSheetCoordinator.java
@@ -6,6 +6,7 @@
 import android.accounts.Account;
 import android.view.View;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
 import androidx.annotation.VisibleForTesting;
 
@@ -35,14 +36,17 @@
     private final SigninManager mSigninManager;
     private boolean mSetTestToast;
     private AccountPickerBottomSheetCoordinator mAccountPickerBottomSheetCoordinator;
+    private final Runnable mOnSigninSuccessCallback;
 
-    public SigninBottomSheetCoordinator(
-            WindowAndroid windowAndroid, BottomSheetController controller, Profile profile) {
+    public SigninBottomSheetCoordinator(WindowAndroid windowAndroid,
+            BottomSheetController controller, Profile profile,
+            @Nullable Runnable onSigninSuccessCallback) {
         mWindowAndroid = windowAndroid;
         mController = controller;
         mProfile = profile;
         mSigninManager = IdentityServicesProvider.get().getSigninManager(mProfile);
         mSetTestToast = false;
+        mOnSigninSuccessCallback = onSigninSuccessCallback;
     }
 
     @Override
@@ -58,6 +62,9 @@
                 RecordHistogram.recordBooleanHistogram(
                         "ContentSuggestions.Feed.SignInFromFeedAction.SignInSuccessful", true);
                 mController.hideContent(mController.getCurrentSheetContent(), true);
+                if (mOnSigninSuccessCallback != null) {
+                    mOnSigninSuccessCallback.run();
+                }
             }
 
             @Override
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/signinbottomsheet/SigninBottomSheetCoordinatorTest.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/signinbottomsheet/SigninBottomSheetCoordinatorTest.java
index 20a06dc..46e670d 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/signinbottomsheet/SigninBottomSheetCoordinatorTest.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/signinbottomsheet/SigninBottomSheetCoordinatorTest.java
@@ -10,6 +10,7 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -61,6 +62,9 @@
     @Mock
     private AccountPickerBottomSheetCoordinator mAccountPickerBottomSheetCoordinatorMock;
 
+    @Mock
+    private Runnable mOnSigninSuccessCallbackMock;
+
     private SigninBottomSheetCoordinator mSigninCoordinator;
 
     @Before
@@ -71,11 +75,11 @@
         when(mSigninManagerMock.isSigninAllowed()).thenReturn(true);
         mAccountManagerTestRule.addAccount(TEST_EMAIL);
         mSigninCoordinator = new SigninBottomSheetCoordinator(
-                mWindowAndroidMock, mBottomSheetControllerMock, mProfileMock);
+                mWindowAndroidMock, mBottomSheetControllerMock, mProfileMock, null);
     }
 
     @Test
-    public void testSignInCompleted() {
+    public void testSigninCompleted_callsSigninManagerAndUpdatesHistogram() {
         var histogramWatcher = HistogramWatcher.newSingleRecordWatcher(
                 "ContentSuggestions.Feed.SignInFromFeedAction.SignInSuccessful", true);
         doAnswer(invocation -> {
@@ -95,7 +99,7 @@
     }
 
     @Test
-    public void testSignInAborted() {
+    public void testSigninAborted_doesNotUpdateHistogram() {
         var histogramWatcher = HistogramWatcher.newSingleRecordWatcher(
                 "ContentSuggestions.Feed.SignInFromFeedAction.SignInSuccessful", false);
         doAnswer(invocation -> {
@@ -120,4 +124,40 @@
         verify(mSigninManagerMock, never())
                 .signin(eq(AccountUtils.createAccountFromName(TEST_EMAIL)), anyInt(), any());
     }
+
+    @Test
+    public void testSigninCompleted_callSigninSuccessCallback() {
+        SigninBottomSheetCoordinator coordinator =
+                new SigninBottomSheetCoordinator(mWindowAndroidMock, mBottomSheetControllerMock,
+                        mProfileMock, mOnSigninSuccessCallbackMock);
+        doAnswer(invocation -> {
+            SigninManager.SignInCallback callback = invocation.getArgument(2);
+            callback.onSignInComplete();
+            return null;
+        })
+                .when(mSigninManagerMock)
+                .signin(eq(AccountUtils.createAccountFromName(TEST_EMAIL)),
+                        eq(SigninAccessPoint.NTP_FEED_BOTTOM_PROMO), any());
+        coordinator.signIn(TEST_EMAIL, error -> {});
+        verify(mOnSigninSuccessCallbackMock, times(1)).run();
+    }
+
+    @Test
+    public void testSigninAborted_doesNotCallSigninSuccessCallback() {
+        SigninBottomSheetCoordinator coordinator =
+                new SigninBottomSheetCoordinator(mWindowAndroidMock, mBottomSheetControllerMock,
+                        mProfileMock, mOnSigninSuccessCallbackMock);
+        doAnswer(invocation -> {
+            SigninManager.SignInCallback callback = invocation.getArgument(2);
+            callback.onSignInAborted();
+            return null;
+        })
+                .when(mSigninManagerMock)
+                .signin(eq(AccountUtils.createAccountFromName(TEST_EMAIL)),
+                        eq(SigninAccessPoint.NTP_FEED_BOTTOM_PROMO), any());
+        coordinator.setAccountPickerBottomSheetCoordinator(
+                mAccountPickerBottomSheetCoordinatorMock);
+        coordinator.signIn(TEST_EMAIL, error -> {});
+        verify(mOnSigninSuccessCallbackMock, times(0)).run();
+    }
 }
diff --git a/chrome/browser/feedback/system_logs/log_sources/performance_log_source_unittest.cc b/chrome/browser/feedback/system_logs/log_sources/performance_log_source_unittest.cc
index d1c36a0..fba8f26 100644
--- a/chrome/browser/feedback/system_logs/log_sources/performance_log_source_unittest.cc
+++ b/chrome/browser/feedback/system_logs/log_sources/performance_log_source_unittest.cc
@@ -59,11 +59,6 @@
   ~PerformanceLogSourceTest() override = default;
 
   void SetUp() override {
-    feature_list_.InitWithFeaturesAndParameters(
-        {
-            {performance_manager::features::kBatterySaverModeAvailable, {}},
-        },
-        {});
     environment_.SetUp(local_state_);
     tuning_manager_ = performance_manager::user_tuning::
         UserPerformanceTuningManager::GetInstance();
@@ -114,7 +109,6 @@
     tuning_manager_->RemoveObserver(observer.get());
   }
 
-  base::test::ScopedFeatureList feature_list_;
   ScopedTestingLocalState testing_local_state_;
   performance_manager::user_tuning::TestUserPerformanceTuningManagerEnvironment
       environment_;
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 77245e8..0c41b89 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2355,6 +2355,11 @@
     "expiry_milestone": 116
   },
   {
+    "name": "enable-empty-states",
+    "owners": [ "zheliooo", "skavuluru", "nemco", "clank-app-team@google.com" ],
+    "expiry_milestone": 120
+  },
+  {
     "name": "enable-enhanced-safe-browsing-settings-improvements",
     "owners": [ "awado", "jacastro", "chrome-counter-abuse-alerts@google.com"],
     "expiry_milestone": 114
@@ -3928,6 +3933,11 @@
     "expiry_milestone": 112
   },
   {
+    "name": "feed-disable-hot-start-refresh-ios",
+    "owners": ["//ios/chrome/browser/discover_feed/OWNERS", "edchin@google.com"],
+    "expiry_milestone": 117
+  },
+  {
     "name": "feed-discofeed-endpoint",
     "owners": [ "//chrome/android/feed/OWNERS", "freedjm@chromium.org" ],
     "expiry_milestone": 115
@@ -4045,11 +4055,6 @@
     "expiry_milestone": 122
   },
   {
-    "name": "fix-pdf-snapshot",
-    "owners": [ "asamidoi" ],
-    "expiry_milestone": 117
-  },
-  {
     "name": "focus-follows-cursor",
     "owners": [ "dandersson", "tclaiborne" ],
     "expiry_milestone": 120
@@ -5406,6 +5411,13 @@
     "expiry_milestone": 120
   },
   {
+    "name": "omnibox-cr23-action-chips",
+    "owners": [
+      "yohanes", "manukh", "chrome-omnibox-team@google.com"
+    ],
+    "expiry_milestone": 120
+  },
+  {
     "name": "omnibox-cr23-expanded-state-colors",
     "owners": [ "khalidpeer", "manukh", "chrome-omnibox-team@google.com" ],
     "expiry_milestone": 120
@@ -5552,17 +5564,17 @@
   },
   {
     "name": "omnibox-ml-log-url-scoring-signals",
-    "owners": [ "junzou", "manukh", "yoangela", "chrome-omnibox-team@google.com" ],
+    "owners": [ "junzou", "yoangela", "chrome-omnibox-team@google.com" ],
     "expiry_milestone": 120
   },
   {
-    "name": "omnibox-ml-relevance-scoring",
+    "name": "omnibox-ml-url-scoring",
     "owners": ["yoangela", "junzou", "chrome-desktop-search@google.com"],
     "expiry_milestone": 120
   },
   {
     "name": "omnibox-ml-url-scoring-model",
-    "owners": [ "junzou", "manukh", "yoangela", "chrome-desktop-search@google.com" ],
+    "owners": [ "junzou", "yoangela", "chrome-desktop-search@google.com" ],
     "expiry_milestone": 120
   },
   {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index d102e6b..966190b 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2099,6 +2099,10 @@
     "When enabled, the Android Omnibox will directly handle IME (keyboard) "
     "inset changes while visible.";
 
+const char kOmniboxCR23ActionChipsName[] = "Omnibox CR 2023 Action Chips";
+const char kOmniboxCR23ActionChipsDescription[] =
+    "Updates Omnibox Action Chips to comply with CR23 guidelines.";
+
 const char kOmniboxCR23ExpandedStateColorsName[] =
     "Omnibox Expanded State Colors";
 const char kOmniboxCR23ExpandedStateColorsDescription[] =
@@ -2329,14 +2333,13 @@
 const char kOmniboxMlLogUrlScoringSignalsDescription[] =
     "Enables Omnibox to log scoring signals of URL suggestions.";
 
-const char kOmniboxMlRelevanceScoringName[] = "Omnibox ML Relevance Scoring";
-const char kOmniboxMlRelevanceScoringDescription[] =
-    "Enables ML-based relevance scoring of Omnibox URL Suggestions.";
+const char kOmniboxMlUrlScoringName[] = "Omnibox ML URL Scoring";
+const char kOmniboxMlUrlScoringDescription[] =
+    "Enables ML-based relevance scoring for Omnibox URL Suggestions.";
 
-const char kOmniboxMlUrlScoringModelName[] =
-    "Omnibox autocomplete URL scoring model.";
+const char kOmniboxMlUrlScoringModelName[] = "Omnibox URL Scoring Model";
 const char kOmniboxMlUrlScoringModelDescription[] =
-    "Enables machine learning scoring model for Omnibox URL sugestions.";
+    "Enables ML scoring model for Omnibox URL sugestions.";
 
 const char kOmniboxOnClobberFocusTypeOnContentName[] =
     "Omnibox On Clobber Focus Type On Content";
@@ -4231,6 +4234,12 @@
     "Enabled Tab Strip Redesign on Android - A visual redesign of Clank Tab "
     "Strip that is consistent with GM3.";
 
+const char kEmptyStatesAndroidName[] = "Empty States Android.";
+const char kEmptyStatesAndroidDescription[] =
+    "Enabled Clank Empty States on Android - Add illustrations to Clank empty "
+    "states to update tab switcher UI, recent tabs, bookmarks, reading list "
+    "and history zero states";
+
 const char kFoldableJankFixAndroidName[] = "Fix for jank seen on foldables.";
 const char kFoldableJankFixAndroidDescription[] =
     "Enables fix for jank seen during fold to unfold transition on foldables "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 21c9c86d..c7f9b679 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1181,6 +1181,9 @@
 extern const char kOmniboxConsumesImeInsetsName[];
 extern const char kOmniboxConsumesImeInsetsDescription[];
 
+extern const char kOmniboxCR23ActionChipsName[];
+extern const char kOmniboxCR23ActionChipsDescription[];
+
 extern const char kOmniboxCR23ExpandedStateColorsName[];
 extern const char kOmniboxCR23ExpandedStateColorsDescription[];
 
@@ -1238,8 +1241,8 @@
 extern const char kOmniboxMlLogUrlScoringSignalsName[];
 extern const char kOmniboxMlLogUrlScoringSignalsDescription[];
 
-extern const char kOmniboxMlRelevanceScoringName[];
-extern const char kOmniboxMlRelevanceScoringDescription[];
+extern const char kOmniboxMlUrlScoringName[];
+extern const char kOmniboxMlUrlScoringDescription[];
 
 extern const char kOmniboxMlUrlScoringModelName[];
 extern const char kOmniboxMlUrlScoringModelDescription[];
@@ -1770,6 +1773,9 @@
 extern const char kTabStripRedesignAndroidName[];
 extern const char kTabStripRedesignAndroidDescription[];
 
+extern const char kEmptyStatesAndroidName[];
+extern const char kEmptyStatesAndroidDescription[];
+
 extern const char kFoldableJankFixAndroidName[];
 extern const char kFoldableJankFixAndroidDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index be1acc7c..34a51893 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -69,6 +69,7 @@
 #include "content/public/common/content_features.h"
 #include "device/fido/features.h"
 #include "media/base/media_switches.h"
+#include "services/audio/public/cpp/audio_features.h"
 #include "services/device/public/cpp/device_features.h"
 #include "services/network/public/cpp/features.h"
 #include "third_party/blink/public/common/features.h"
@@ -117,6 +118,7 @@
     &features::kAsyncSensorCalls,
     &features::kBackForwardCache,
     &features::kBackForwardTransitions,
+    &features::kBlockMidiByDefault,
     &features::kHttpsOnlyMode,
     &features::kMetricsSettingsAndroid,
     &features::kNetworkServiceInProcess,
@@ -186,6 +188,7 @@
     &kCastDeviceFilter,
     &kClearOmniboxFocusAfterNavigation,
     &kCloseTabSuggestions,
+    &kCloseTabSaveTabList,
     &kCriticalPersistedTabData,
     &kCCTAllowCrossUidActivitySwitchFromBelow,
     &kCCTBackgroundTab,
@@ -237,6 +240,7 @@
     &kDeferNotifyInMotion,
     &kDelayTransitionsForAnimation,
     &kDrawEdgeToEdge,
+    &kEmptyStates,
     &kExperimentsForAgsa,
     &kExploreSites,
     &kFocusOmniboxInIncognitoTabIntents,
@@ -533,6 +537,10 @@
              "CloseTabSuggestions",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kCloseTabSaveTabList,
+             "CloseTabSaveTabList",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 BASE_FEATURE(kCriticalPersistedTabData,
              "CriticalPersistedTabData",
              base::FEATURE_DISABLED_BY_DEFAULT);
@@ -751,6 +759,8 @@
              "DrawEdgeToEdge",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kEmptyStates, "EmptyStates", base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kExperimentsForAgsa,
              "ExperimentsForAgsa",
              base::FEATURE_ENABLED_BY_DEFAULT);
@@ -967,7 +977,7 @@
 
 BASE_FEATURE(kShareSheetCustomActionsPolish,
              "ShareSheetCustomActionsPolish",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kShareSheetMigrationAndroid,
              "ShareSheetMigrationAndroid",
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index de67999d..90ca398 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -39,6 +39,7 @@
 BASE_DECLARE_FEATURE(kBottomSheetGtsSupport);
 BASE_DECLARE_FEATURE(kClearOmniboxFocusAfterNavigation);
 BASE_DECLARE_FEATURE(kCloseTabSuggestions);
+BASE_DECLARE_FEATURE(kCloseTabSaveTabList);
 BASE_DECLARE_FEATURE(kCriticalPersistedTabData);
 BASE_DECLARE_FEATURE(kCastDeviceFilter);
 BASE_DECLARE_FEATURE(kCCTAllowCrossUidActivitySwitchFromBelow);
@@ -95,6 +96,7 @@
 BASE_DECLARE_FEATURE(kDownloadAutoResumptionThrottling);
 BASE_DECLARE_FEATURE(kDownloadHomeForExternalApp);
 BASE_DECLARE_FEATURE(kDrawEdgeToEdge);
+BASE_DECLARE_FEATURE(kEmptyStates);
 BASE_DECLARE_FEATURE(kExperimentsForAgsa);
 BASE_DECLARE_FEATURE(kExploreSites);
 BASE_DECLARE_FEATURE(kFocusOmniboxInIncognitoTabIntents);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 6f6ab62..0d03c0e 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -266,6 +266,7 @@
     public static final String CLEAR_OMNIBOX_FOCUS_AFTER_NAVIGATION =
             "ClearOmniboxFocusAfterNavigation";
     public static final String CLOSE_TAB_SUGGESTIONS = "CloseTabSuggestions";
+    public static final String CLOSE_TAB_SAVE_TAB_LIST = "CloseTabSaveTabList";
     public static final String COMMAND_LINE_ON_NON_ROOTED = "CommandLineOnNonRooted";
     public static final String COMMERCE_MERCHANT_VIEWER = "CommerceMerchantViewer";
     public static final String COMMERCE_PRICE_TRACKING = "CommercePriceTracking";
@@ -322,7 +323,7 @@
     public static final String FEED_SHOW_SIGN_IN_COMMAND = "FeedShowSignInCommand";
     public static final String FEED_BOC_SIGN_IN_INTERSTITIAL = "FeedBoCSigninInterstitial";
     public static final String FEED_USER_INTERACTION_RELIABILITY_REPORT =
-            "kFeedUserInteractionReliabilityReport";
+            "FeedUserInteractionReliabilityReport";
     public static final String FILLING_PASSWORDS_FROM_ANY_ORIGIN = "FillingPasswordsFromAnyOrigin";
     public static final String FOCUS_OMNIBOX_IN_INCOGNITO_TAB_INTENTS =
             "FocusOmniboxInIncognitoTabIntents";
@@ -594,6 +595,8 @@
             new CachedFlag(CCT_TOOLBAR_CUSTOMIZATIONS, true);
     public static final CachedFlag sCloseTabSuggestions =
             new CachedFlag(CLOSE_TAB_SUGGESTIONS, false);
+    public static final CachedFlag sCloseTabSaveTabList =
+            new CachedFlag(CLOSE_TAB_SAVE_TAB_LIST, true);
     public static final CachedFlag sCommandLineOnNonRooted =
             new CachedFlag(COMMAND_LINE_ON_NON_ROOTED, false);
     public static final CachedFlag sCriticalPersistedTabData =
diff --git a/chrome/browser/google/google_brand_code_map_chromeos.cc b/chrome/browser/google/google_brand_code_map_chromeos.cc
index b2b133a..a653c5a 100644
--- a/chrome/browser/google/google_brand_code_map_chromeos.cc
+++ b/chrome/browser/google/google_brand_code_map_chromeos.cc
@@ -49,6 +49,7 @@
                      {"ADGK", {"PKUQ", "AEMI", "CUUL"}},
                      {"ADID", {"XDMY", "QHTP", "PBND"}},
                      {"AGVY", {"RNNC", "KYLA", "NJOS"}},
+                     {"AHBI", {"TSVD", "PIAU", "ZRSX"}},
                      {"AJIM", {"XQAQ", "WFLV", "AMBR"}},
                      {"ALRH", {"XDKE", "TDIH", "VLER"}},
                      {"ANAE", {"IWTJ", "CISE", "SLJZ"}},
@@ -127,6 +128,7 @@
                      {"DISZ", {"PPAR", "VCPW", "NJKK"}},
                      {"DJBB", {"ZLXN", "WQCE", "ASCQ"}},
                      {"DKJM", {"VRGL", "PZYF", "VBTW"}},
+                     {"DNHE", {"TXQH", "NAJK", "CRYX"}},
                      {"DRYI", {"LWTQ", "OLEY", "NWUA"}},
                      {"DSCL", {"OSET", "BPKO", "KRIN"}},
                      {"DSQH", {"MXFW", "HTPC", "YIUL"}},
@@ -152,6 +154,7 @@
                      {"FBTP", {"XLDO", "TLOM", "FYMS"}},
                      {"FCPG", {"WITB", "FOXJ", "YJQZ"}},
                      {"FCVS", {"HOBX", "YMDN", "GKTP"}},
+                     {"FENM", {"NTNB", "RIJA", "WEHG"}},
                      {"FHYR", {"YKUD", "XTKX", "QFMD"}},
                      {"FIGU", {"VMWP", "SBFY", "IYUS"}},
                      {"FNVY", {"DLEJ", "DCNV", "XALG"}},
@@ -394,6 +397,7 @@
                      {"OIXD", {"UNMJ", "EGQA", "GIAQ"}},
                      {"OKFL", {"KLQV", "NEOA", "HDPS"}},
                      {"OKWC", {"RGFB", "UPFP", "HUVK"}},
+                     {"ONJP", {"XIEX", "UAAR", "UMMB"}},
                      {"OPNA", {"JDSG", "BCNO", "THKI"}},
                      {"OYZI", {"WDBC", "NKZT", "QJZD"}},
                      {"PAZD", {"VARX", "KZSU", "WPLH"}},
@@ -442,6 +446,7 @@
                      {"RKRB", {"OPOY", "QMZZ", "FAGR"}},
                      {"RLGE", {"NTKV", "LOTA", "MJVG"}},
                      {"RNPH", {"TSIF", "ESCP", "GISR"}},
+                     {"RPOG", {"DFCF", "QCSW", "HVUW"}},
                      {"RUIL", {"BSMS", "GIWR", "XIOX"}},
                      {"RVAR", {"NLFF", "YJIJ", "UHJG"}},
                      {"RVKU", {"EVWH", "THXH", "GROS"}},
diff --git a/chrome/browser/hid/chrome_hid_delegate.cc b/chrome/browser/hid/chrome_hid_delegate.cc
index 37ec3fb..7d1deb93 100644
--- a/chrome/browser/hid/chrome_hid_delegate.cc
+++ b/chrome/browser/hid/chrome_hid_delegate.cc
@@ -250,8 +250,7 @@
   auto* hid_connection_tracker =
       GetConnectionTracker(browser_context, /*create=*/true);
   if (hid_connection_tracker) {
-    hid_connection_tracker->IncrementConnectionCount();
-    hid_connection_tracker->NotifyDeviceConnected(origin);
+    hid_connection_tracker->IncrementConnectionCount(origin);
   }
 }
 
@@ -268,6 +267,6 @@
   auto* hid_connection_tracker =
       GetConnectionTracker(browser_context, /*create=*/false);
   if (hid_connection_tracker) {
-    hid_connection_tracker->DecrementConnectionCount();
+    hid_connection_tracker->DecrementConnectionCount(origin);
   }
 }
diff --git a/chrome/browser/hid/chrome_hid_delegate_unittest.cc b/chrome/browser/hid/chrome_hid_delegate_unittest.cc
index 905b990..fd54d60 100644
--- a/chrome/browser/hid/chrome_hid_delegate_unittest.cc
+++ b/chrome/browser/hid/chrome_hid_delegate_unittest.cc
@@ -158,12 +158,8 @@
       : HidConnectionTracker(profile) {}
   ~MockHidConnectionTracker() override = default;
 
-  MOCK_METHOD(void, IncrementConnectionCount, (), (override));
-  MOCK_METHOD(void, DecrementConnectionCount, (), (override));
-  MOCK_METHOD(void,
-              NotifyDeviceConnected,
-              (const url::Origin& origin),
-              (override));
+  MOCK_METHOD(void, IncrementConnectionCount, (const url::Origin&), (override));
+  MOCK_METHOD(void, DecrementConnectionCount, (const url::Origin&), (override));
 };
 
 class ChromeHidTestHelper {
@@ -539,7 +535,7 @@
     TestFuture<mojo::PendingRemote<device::mojom::HidConnection>>
         pending_remote_future;
     if (supports_hid_connection_tracker_)
-      EXPECT_CALL(hid_connection_tracker(), IncrementConnectionCount);
+      EXPECT_CALL(hid_connection_tracker(), IncrementConnectionCount(origin));
     hid_service->Connect(device->guid, std::move(hid_connection_client),
                          pending_remote_future.GetCallback());
     mojo::Remote<device::mojom::HidConnection> connection;
@@ -552,7 +548,7 @@
 
     base::RunLoop decrement_connection_count_loop;
     if (supports_hid_connection_tracker_) {
-      EXPECT_CALL(hid_connection_tracker(), DecrementConnectionCount)
+      EXPECT_CALL(hid_connection_tracker(), DecrementConnectionCount(origin))
           .WillOnce(RunClosure(decrement_connection_count_loop.QuitClosure()));
     }
 
@@ -595,7 +591,7 @@
     TestFuture<mojo::PendingRemote<device::mojom::HidConnection>>
         pending_remote_future;
     if (supports_hid_connection_tracker_)
-      EXPECT_CALL(hid_connection_tracker(), IncrementConnectionCount);
+      EXPECT_CALL(hid_connection_tracker(), IncrementConnectionCount(origin));
     hid_service->Connect(device->guid, std::move(hid_connection_client),
                          pending_remote_future.GetCallback());
     mojo::Remote<device::mojom::HidConnection> connection;
@@ -608,7 +604,7 @@
 
     base::RunLoop decrement_connection_count_loop;
     if (supports_hid_connection_tracker_) {
-      EXPECT_CALL(hid_connection_tracker(), DecrementConnectionCount)
+      EXPECT_CALL(hid_connection_tracker(), DecrementConnectionCount(origin))
           .WillOnce(RunClosure(decrement_connection_count_loop.QuitClosure()));
     }
 
@@ -652,7 +648,7 @@
     TestFuture<mojo::PendingRemote<device::mojom::HidConnection>>
         pending_remote_future;
     if (supports_hid_connection_tracker_)
-      EXPECT_CALL(hid_connection_tracker(), IncrementConnectionCount);
+      EXPECT_CALL(hid_connection_tracker(), IncrementConnectionCount(origin));
     hid_service->Connect(device->guid, std::move(hid_connection_client),
                          pending_remote_future.GetCallback());
     mojo::Remote<device::mojom::HidConnection> connection;
@@ -671,7 +667,7 @@
     // as it will be called in the disconnect path.
     if (supports_hid_connection_tracker_) {
       base::RunLoop decrement_connection_count_loop;
-      EXPECT_CALL(hid_connection_tracker(), DecrementConnectionCount)
+      EXPECT_CALL(hid_connection_tracker(), DecrementConnectionCount(origin))
           .WillOnce(RunClosure(decrement_connection_count_loop.QuitClosure()));
       connection.reset();
       decrement_connection_count_loop.Run();
@@ -718,7 +714,7 @@
     TestFuture<mojo::PendingRemote<device::mojom::HidConnection>>
         pending_remote_future;
     if (supports_hid_connection_tracker_)
-      EXPECT_CALL(hid_connection_tracker(), IncrementConnectionCount);
+      EXPECT_CALL(hid_connection_tracker(), IncrementConnectionCount(origin));
     hid_service->Connect(device->guid, std::move(hid_connection_client),
                          pending_remote_future.GetCallback());
     mojo::Remote<device::mojom::HidConnection> connection;
@@ -737,7 +733,7 @@
     // as it will be called in the remove device path.
     if (supports_hid_connection_tracker_) {
       base::RunLoop decrement_connection_count_loop;
-      EXPECT_CALL(hid_connection_tracker(), DecrementConnectionCount)
+      EXPECT_CALL(hid_connection_tracker(), DecrementConnectionCount(origin))
           .WillOnce(RunClosure(decrement_connection_count_loop.QuitClosure()));
       RemoveDevice(device);
       decrement_connection_count_loop.Run();
@@ -810,8 +806,7 @@
     hid_service->GetDevices(devices_future.GetCallback());
     EXPECT_THAT(devices_future.Take(), ElementsAre(HasGuid(device->guid)));
 
-    EXPECT_CALL(hid_connection_tracker(), IncrementConnectionCount).Times(0);
-    EXPECT_CALL(hid_connection_tracker(), NotifyDeviceConnected(origin))
+    EXPECT_CALL(hid_connection_tracker(), IncrementConnectionCount(origin))
         .Times(0);
     // Open a connection to `device`.
     FakeHidConnectionClient connection_client;
diff --git a/chrome/browser/hid/hid_browsertest.cc b/chrome/browser/hid/hid_browsertest.cc
index d977732..92576a7 100644
--- a/chrome/browser/hid/hid_browsertest.cc
+++ b/chrome/browser/hid/hid_browsertest.cc
@@ -135,9 +135,6 @@
         std::move(fake_user_manager));
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-    display_service_for_profile_notification_ =
-        std::make_unique<NotificationDisplayServiceTester>(profile());
-
 #if BUILDFLAG(IS_CHROMEOS)
     display_service_for_system_notification_ =
         std::make_unique<NotificationDisplayServiceTester>(
@@ -195,33 +192,6 @@
 
   device::FakeHidManager* hid_manager() { return &hid_manager_; }
 
-  void SimulateClickOnDeviceOpenedNotification(Browser* browser,
-                                               const Extension* extension) {
-    std::string expected_link_destination(chrome::kChromeUIContentSettingsURL);
-    std::string origin_string = extension->origin().Serialize();
-    url::RawCanonOutputT<char> percent_encoded_origin;
-    url::EncodeURIComponent(origin_string.c_str(), origin_string.length(),
-                            &percent_encoded_origin);
-    expected_link_destination = chrome::kChromeUISiteDetailsPrefixURL +
-                                std::string(percent_encoded_origin.data(),
-                                            percent_encoded_origin.length());
-
-    auto* profile = browser->profile();
-    auto expected_notification_id =
-        base::StringPrintf("webhid.opened.%s.%s", profile->UniqueId().c_str(),
-                           extension->origin().host().c_str());
-    auto maybe_notification =
-        display_service_for_profile_notification_->GetNotification(
-            expected_notification_id);
-    EXPECT_TRUE(maybe_notification);
-    display_service_for_profile_notification_->SimulateClick(
-        NotificationHandler::Type::TRANSIENT, expected_notification_id,
-        /*action_index=*/0,
-        /*reply=*/absl::nullopt);
-    auto* web_contents = browser->tab_strip_model()->GetActiveWebContents();
-    EXPECT_EQ(web_contents->GetURL(), expected_link_destination);
-  }
-
   void SimulateClickOnSystemTrayIconButton(Browser* browser) {
 #if BUILDFLAG(IS_CHROMEOS)
     auto expected_pinned_notification_id =
@@ -248,8 +218,6 @@
 
  protected:
   base::test::ScopedFeatureList scoped_feature_list_;
-  std::unique_ptr<NotificationDisplayServiceTester>
-      display_service_for_profile_notification_;
 #if BUILDFLAG(IS_CHROMEOS)
   std::unique_ptr<NotificationDisplayServiceTester>
       display_service_for_system_notification_;
@@ -379,8 +347,7 @@
       }
     });
   )";
-  const auto* extension = LoadExtensionAndRunTest(kBackgroundJs);
-  SimulateClickOnDeviceOpenedNotification(browser(), extension);
+  LoadExtensionAndRunTest(kBackgroundJs);
   SimulateClickOnSystemTrayIconButton(browser());
 }
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/hid/hid_connection_tracker.cc b/chrome/browser/hid/hid_connection_tracker.cc
index 3304d8c..5b37fce 100644
--- a/chrome/browser/hid/hid_connection_tracker.cc
+++ b/chrome/browser/hid/hid_connection_tracker.cc
@@ -29,36 +29,6 @@
 #include "extensions/common/constants.h"
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
-namespace {
-
-std::u16string GetDeviceConnectedNotificationMessage(
-    Profile* profile,
-    const url::Origin& origin) {
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-  if (origin.scheme() == extensions::kExtensionScheme) {
-    const auto* extension_registry =
-        extensions::ExtensionRegistry::Get(profile);
-    DCHECK(extension_registry);
-    const extensions::Extension* extension =
-        extension_registry->GetExtensionById(
-            origin.host(), extensions::ExtensionRegistry::EVERYTHING);
-    return l10n_util::GetStringFUTF16(
-        IDS_WEBHID_DEVICE_CONNECTED_BY_EXTENSION_NOTIFICATION_MESSAGE,
-        base::UTF8ToUTF16(extension->name()));
-  }
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
-  NOTREACHED();
-  return u"";
-}
-
-std::string GetDeviceOpenedNotificationId(Profile* profile,
-                                          const url::Origin& origin) {
-  return base::StrCat(
-      {"webhid.opened.", profile->UniqueId(), ".", origin.host()});
-}
-
-}  // namespace
-
 HidConnectionTracker::HidConnectionTracker(Profile* profile)
     : profile_(profile) {}
 
@@ -66,71 +36,46 @@
   CleanUp();
 }
 
-void HidConnectionTracker::IncrementConnectionCount() {
-  ++connection_count_;
+void HidConnectionTracker::IncrementConnectionCount(const url::Origin& origin) {
+  CHECK_GE(origins_[origin], 0);
+  origins_[origin]++;
+  total_connection_count_++;
+
   auto* hid_system_tray_icon = g_browser_process->hid_system_tray_icon();
   if (!hid_system_tray_icon) {
     return;
   }
-
-  if (connection_count_ == 1) {
+  if (total_connection_count_ == 1) {
     hid_system_tray_icon->StageProfile(profile_);
   } else {
     hid_system_tray_icon->NotifyConnectionCountUpdated(profile_);
   }
 }
 
-void HidConnectionTracker::DecrementConnectionCount() {
-  --connection_count_;
+void HidConnectionTracker::DecrementConnectionCount(const url::Origin& origin) {
+  auto it = origins_.find(origin);
+  CHECK(it != origins_.end());
+  auto& connection_count = it->second;
+  CHECK_GT(connection_count, 0);
+
+  connection_count--;
+  total_connection_count_--;
+  if (connection_count == 0) {
+    origins_.erase(it);
+  }
+
   auto* hid_system_tray_icon = g_browser_process->hid_system_tray_icon();
   if (!hid_system_tray_icon) {
     return;
   }
-
-  if (connection_count_ == 0) {
+  if (total_connection_count_ == 0) {
     hid_system_tray_icon->UnstageProfile(profile_, /*immediate=*/false);
   } else {
     hid_system_tray_icon->NotifyConnectionCountUpdated(profile_);
   }
 }
 
-void HidConnectionTracker::NotifyDeviceConnected(const url::Origin& origin) {
-  auto delegate =
-      base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
-          base::BindRepeating(
-              [](HidConnectionTracker* hid_connection_tracker,
-                 const url::Origin& origin, absl::optional<int> button_index) {
-                // |hid_connection_tracker| will always be valid here because an
-                // active notification prevents the Profile (which owns the
-                // HidConnectionTracker as a KeyedService) from being destroyed.
-                hid_connection_tracker->ShowSiteSettings(origin);
-              },
-              this, origin));
-
-  auto notification_id = GetDeviceOpenedNotificationId(profile_, origin);
-  message_center::Notification notification(
-      message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
-      l10n_util::GetStringUTF16(
-          IDS_WEBHID_DEVICE_CONNECTED_BY_EXTENSION_NOTIFICATION_TITLE),
-      GetDeviceConnectedNotificationMessage(profile_, origin),
-      ui::ImageModel::FromVectorIcon(vector_icons::kVideogameAssetIcon,
-                                     ui::kColorIcon, 64),
-      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), /*origin_url=*/{},
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-      message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
-                                 notification_id,
-                                 ash::NotificationCatalogName::kWebHid),
-#else
-      message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
-                                 notification_id),
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-      message_center::RichNotificationData(), std::move(delegate));
-  NotificationDisplayService::GetForProfile(profile_)->Display(
-      NotificationHandler::Type::TRANSIENT, notification,
-      /*metadata=*/nullptr);
-}
-
-void HidConnectionTracker::ShowHidContentSettingsExceptions() {
+void HidConnectionTracker::ShowContentSettingsExceptions() {
   chrome::ShowContentSettingsExceptionsForProfile(
       profile_, ContentSettingsType::HID_CHOOSER_DATA);
 }
@@ -140,10 +85,12 @@
 }
 
 void HidConnectionTracker::CleanUp() {
-  if (connection_count_ > 0) {
-    connection_count_ = 0;
+  if (!origins_.empty()) {
+    origins_.clear();
+    total_connection_count_ = 0;
     auto* hid_system_tray_icon = g_browser_process->hid_system_tray_icon();
-    if (hid_system_tray_icon)
+    if (hid_system_tray_icon) {
       hid_system_tray_icon->UnstageProfile(profile_, /*immediate=*/true);
+    }
   }
 }
diff --git a/chrome/browser/hid/hid_connection_tracker.h b/chrome/browser/hid/hid_connection_tracker.h
index 11a24c7..369da7f 100644
--- a/chrome/browser/hid/hid_connection_tracker.h
+++ b/chrome/browser/hid/hid_connection_tracker.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_HID_HID_CONNECTION_TRACKER_H_
 #define CHROME_BROWSER_HID_HID_CONNECTION_TRACKER_H_
 
+#include "base/containers/flat_map.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "url/origin.h"
@@ -17,13 +18,10 @@
   HidConnectionTracker& operator=(HidConnectionTracker&) = delete;
   ~HidConnectionTracker() override;
 
-  virtual void IncrementConnectionCount();
-  virtual void DecrementConnectionCount();
+  virtual void IncrementConnectionCount(const url::Origin& origin);
+  virtual void DecrementConnectionCount(const url::Origin& origin);
 
-  // Generate a notification about a connection created for |origin|.
-  virtual void NotifyDeviceConnected(const url::Origin& origin);
-
-  virtual void ShowHidContentSettingsExceptions();
+  virtual void ShowContentSettingsExceptions();
   virtual void ShowSiteSettings(const url::Origin& origin);
 
   // This is used by either the destructor or
@@ -31,12 +29,20 @@
   // from HidSystemTrayIcon.
   void CleanUp();
 
-  int connection_count() { return connection_count_; }
+  int total_connection_count() { return total_connection_count_; }
   Profile* profile() { return profile_; }
 
+  const base::flat_map<url::Origin, int>& GetOriginsForTesting() {
+    return origins_;
+  }
+
  private:
-  int connection_count_ = 0;
+  int total_connection_count_ = 0;
   raw_ptr<Profile> profile_;
+
+  // The structure that tracks the connection count for each origin that has
+  // active connection(s).
+  base::flat_map<url::Origin, int> origins_;
 };
 
 #endif  // CHROME_BROWSER_HID_HID_CONNECTION_TRACKER_H_
diff --git a/chrome/browser/hid/hid_connection_tracker_unittest.cc b/chrome/browser/hid/hid_connection_tracker_unittest.cc
index e39d4e8..ebf9e53a 100644
--- a/chrome/browser/hid/hid_connection_tracker_unittest.cc
+++ b/chrome/browser/hid/hid_connection_tracker_unittest.cc
@@ -12,7 +12,6 @@
 #include "chrome/browser/hid/hid_connection_tracker.h"
 #include "chrome/browser/hid/hid_connection_tracker_factory.h"
 #include "chrome/browser/hid/hid_system_tray_icon.h"
-#include "chrome/browser/notifications/notification_display_service_tester.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
@@ -34,26 +33,11 @@
 
 namespace {
 
-constexpr char kExtensionName[] = "Fake extension";
+using testing::Pair;
+using testing::UnorderedElementsAre;
+
 constexpr char kTestProfileName[] = "user@gmail.com";
 
-class MockHidConnectionTracker : public HidConnectionTracker {
- public:
-  explicit MockHidConnectionTracker(Profile* profile)
-      : HidConnectionTracker(profile) {}
-  ~MockHidConnectionTracker() override = default;
-  MOCK_METHOD(void, ShowSiteSettings, (const url::Origin& origin), (override));
-};
-
-BrowserContextKeyedServiceFactory::TestingFactory
-GetHidConnectionTrackerTestingFactory() {
-  return base::BindRepeating([](content::BrowserContext* browser_context) {
-    return static_cast<std::unique_ptr<KeyedService>>(
-        std::make_unique<MockHidConnectionTracker>(
-            Profile::FromBrowserContext(browser_context)));
-  });
-}
-
 class MockHidSystemTrayIcon : public HidSystemTrayIcon {
  public:
   MOCK_METHOD(void, StageProfile, (Profile*), (override));
@@ -63,6 +47,8 @@
   MOCK_METHOD(void, NotifyConnectionCountUpdated, (Profile*), (override));
 };
 
+}  // namespace
+
 class HidConnectionTrackerTest : public BrowserWithTestWindowTest {
  public:
   HidConnectionTrackerTest() = default;
@@ -74,77 +60,16 @@
     BrowserWithTestWindowTest::SetUp();
     BrowserList::SetLastActive(browser());
 
-    // TODO(crbug.com/1399310): Pass testing factory when creating profile.
-    // Ideally, we should inject MockHidConnectionTracker by overriding
-    // BrowserWithTestWindowTest::GetTestingFactories(). However, due to the
-    // fact that:
-    // 1) TestingProfile::TestingProfile(...) will call BrowserContextShutdown
-    //    as part of setting testing factory.
-    // 2) HidConnectionTrackerFactory::BrowserContextShutdown() at some point
-    //    need valid profile_metrics::GetBrowserProfileType() as part of
-    //    HidConnectionTrackerFactory::GetForProfile().
-    // It will hit failure in profile_metrics::GetBrowserProfileType() because
-    // the profile is not initialized properly before setting testing factory.
-    // As a result, here set the testing factory for MockHidConnectionTracker
-    // after profile() is properly initialized.
-    HidConnectionTrackerFactory::GetInstance()->SetTestingFactory(
-        profile(), GetHidConnectionTrackerTestingFactory());
-
-    display_service_ =
-        std::make_unique<NotificationDisplayServiceTester>(profile());
     auto hid_system_tray_icon = std::make_unique<MockHidSystemTrayIcon>();
     hid_system_tray_icon_ = hid_system_tray_icon.get();
     TestingBrowserProcess::GetGlobal()->SetHidSystemTrayIcon(
         std::move(hid_system_tray_icon));
 
-    hid_connection_tracker_ = static_cast<MockHidConnectionTracker*>(
-        HidConnectionTrackerFactory::GetForProfile(profile(), /*create=*/true));
-  }
-
-  std::u16string GetExpectedDeviceConnectedByExtensionNotificationTitle() {
-    return u"An extension is using a HID device";
-  }
-
-  std::string GetExpectedNotificationId(const url::Origin& origin) {
-    return base::StringPrintf("webhid.opened.%s.%s",
-                              profile()->UniqueId().c_str(),
-                              origin.host().c_str());
-  }
-
-  void CheckDeviceConnectedNotification(
-      const url::Origin& origin,
-      const std::string& name_in_notification_title) {
-    auto expected_notification_id = GetExpectedNotificationId(origin);
-    EXPECT_EQ(display_service_
-                  ->GetDisplayedNotificationsForType(
-                      NotificationHandler::Type::TRANSIENT)
-                  .size(),
-              1u);
-    auto maybe_notification =
-        display_service_->GetNotification(expected_notification_id);
-    ASSERT_TRUE(maybe_notification);
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-    EXPECT_EQ(maybe_notification->title(),
-              GetExpectedDeviceConnectedByExtensionNotificationTitle());
-    EXPECT_EQ(maybe_notification->message(),
-              GetExpectedDeviceConnectedByExtensionNotificationMessage(
-                  name_in_notification_title));
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
-    EXPECT_TRUE(maybe_notification->delegate());
-    EXPECT_CALL(*hid_connection_tracker_, ShowSiteSettings(origin));
-    display_service_->SimulateClick(NotificationHandler::Type::TRANSIENT,
-                                    expected_notification_id,
-                                    /*action_index=*/absl::nullopt,
-                                    /*reply=*/absl::nullopt);
+    hid_connection_tracker_ =
+        HidConnectionTrackerFactory::GetForProfile(profile(), /*create=*/true);
   }
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
-  std::u16string GetExpectedDeviceConnectedByExtensionNotificationMessage(
-      const std::string& name) {
-    return base::UTF8ToUTF16(base::StringPrintf(
-        "Click to manage permissions for \"%s\"", name.c_str()));
-  }
-
   scoped_refptr<const extensions::Extension> CreateExtensionWithName(
       const std::string& extension_name) {
     extensions::DictionaryBuilder manifest;
@@ -180,69 +105,93 @@
   }
 
   Profile* CreateTestingProfile(const std::string& profile_name) {
-    // Ideally, we should be able to pass testing factory when calling profile
-    // manager's CreateTestingProfile. However, due to the fact that:
-    // 1) TestingProfile::TestingProfile(...) will call BrowserContextShutdown
-    //    as part of setting testing factory.
-    // 2) HidConnectionTrackerFactory::BrowserContextShutdown() at some point
-    //    need valid profile_metrics::GetBrowserProfileType() as part of
-    //    HidConnectionTrackerFactory::GetForProfile().
-    // It will hit failure in profile_metrics::GetBrowserProfileType() because
-    // the profile is not initialized properly before setting testing factory.
-    // As a result, here create a profile then call SetTestingFactory to inject
-    // MockHidConnectionTracker.
     Profile* profile = profile_manager()->CreateTestingProfile(profile_name);
-    HidConnectionTrackerFactory::GetInstance()->SetTestingFactory(
-        profile, GetHidConnectionTrackerTestingFactory());
     return profile;
   }
 
+  void TestDeviceConnection(bool has_system_tray_icon) {
+    auto origin1 = url::Origin::Create(GURL("https://www.example1.com"));
+    auto origin2 = url::Origin::Create(GURL("https://www.example2.com"));
+
+    // First connection that stages the profile.
+    if (has_system_tray_icon) {
+      EXPECT_CALL(hid_system_tray_icon(), StageProfile(profile()));
+    }
+    hid_connection_tracker().IncrementConnectionCount(origin1);
+    EXPECT_EQ(hid_connection_tracker().total_connection_count(), 1);
+    EXPECT_THAT(hid_connection_tracker().GetOriginsForTesting(),
+                UnorderedElementsAre(Pair(origin1, 1)));
+
+    // Connections from two origins come and go.
+    if (has_system_tray_icon) {
+      EXPECT_CALL(hid_system_tray_icon(),
+                  NotifyConnectionCountUpdated(profile()))
+          .Times(4);
+    }
+    hid_connection_tracker().IncrementConnectionCount(origin1);
+    EXPECT_EQ(hid_connection_tracker().total_connection_count(), 2);
+    EXPECT_THAT(hid_connection_tracker().GetOriginsForTesting(),
+                UnorderedElementsAre(Pair(origin1, 2)));
+    hid_connection_tracker().IncrementConnectionCount(origin2);
+    EXPECT_EQ(hid_connection_tracker().total_connection_count(), 3);
+    EXPECT_THAT(hid_connection_tracker().GetOriginsForTesting(),
+                UnorderedElementsAre(Pair(origin1, 2), Pair(origin2, 1)));
+    hid_connection_tracker().DecrementConnectionCount(origin1);
+    EXPECT_EQ(hid_connection_tracker().total_connection_count(), 2);
+    EXPECT_THAT(hid_connection_tracker().GetOriginsForTesting(),
+                UnorderedElementsAre(Pair(origin1, 1), Pair(origin2, 1)));
+    hid_connection_tracker().DecrementConnectionCount(origin1);
+    EXPECT_EQ(hid_connection_tracker().total_connection_count(), 1);
+    EXPECT_THAT(hid_connection_tracker().GetOriginsForTesting(),
+                UnorderedElementsAre(Pair(origin2, 1)));
+
+    // The last connection that will unstage the profile.
+    if (has_system_tray_icon) {
+      EXPECT_CALL(hid_system_tray_icon(),
+                  UnstageProfile(profile(), /*immediate=*/false));
+    }
+    hid_connection_tracker().DecrementConnectionCount(origin2);
+    EXPECT_EQ(hid_connection_tracker().total_connection_count(), 0);
+    EXPECT_TRUE(hid_connection_tracker().GetOriginsForTesting().empty());
+  }
+
  private:
-  std::unique_ptr<NotificationDisplayServiceTester> display_service_;
-  raw_ptr<MockHidConnectionTracker> hid_connection_tracker_;
+  raw_ptr<HidConnectionTracker> hid_connection_tracker_;
   raw_ptr<MockHidSystemTrayIcon> hid_system_tray_icon_;
 };
 
-}  // namespace
-
 TEST_F(HidConnectionTrackerTest, DeviceConnection) {
-  EXPECT_CALL(hid_system_tray_icon(), StageProfile(profile()));
-  hid_connection_tracker().IncrementConnectionCount();
-  EXPECT_CALL(hid_system_tray_icon(), NotifyConnectionCountUpdated(profile()));
-  hid_connection_tracker().IncrementConnectionCount();
-  EXPECT_CALL(hid_system_tray_icon(), NotifyConnectionCountUpdated(profile()));
-  hid_connection_tracker().DecrementConnectionCount();
-  EXPECT_CALL(hid_system_tray_icon(),
-              UnstageProfile(profile(), /*immediate*/ false));
-  hid_connection_tracker().DecrementConnectionCount();
+  TestDeviceConnection(/*has_system_tray_icon=*/true);
 }
 
+// Test the scenario with null HID system tray icon and it doesn't cause crash.
 TEST_F(HidConnectionTrackerTest, DeviceConnectionWithNullSystemTrayIcon) {
-  // Test the scenario with null HID system tray icon and it doesn't cause
-  // crash.
   TestingBrowserProcess::GetGlobal()->SetHidSystemTrayIcon(nullptr);
-  hid_connection_tracker().IncrementConnectionCount();
-  hid_connection_tracker().IncrementConnectionCount();
-  hid_connection_tracker().DecrementConnectionCount();
-  hid_connection_tracker().DecrementConnectionCount();
+  TestDeviceConnection(/*has_system_tray_icon=*/false);
 }
 
 TEST_F(HidConnectionTrackerTest, ProfileDestroyed) {
-  CreateTestingProfile(kTestProfileName);
-  EXPECT_CALL(hid_system_tray_icon(), StageProfile(profile()));
-  hid_connection_tracker().IncrementConnectionCount();
-  EXPECT_CALL(hid_system_tray_icon(), NotifyConnectionCountUpdated(profile()));
-  hid_connection_tracker().IncrementConnectionCount();
+  auto origin = url::Origin::Create(GURL("https://www.example.com"));
+  auto* profile_to_be_destroyed = CreateTestingProfile(kTestProfileName);
+
+  auto* connection_tracker =
+      HidConnectionTrackerFactory::GetForProfile(profile_to_be_destroyed,
+                                                 /*create=*/true);
+
+  EXPECT_CALL(hid_system_tray_icon(), StageProfile(profile_to_be_destroyed));
+  connection_tracker->IncrementConnectionCount(origin);
+  EXPECT_EQ(connection_tracker->total_connection_count(), 1);
+  EXPECT_THAT(connection_tracker->GetOriginsForTesting(),
+              UnorderedElementsAre(Pair(origin, 1)));
+
   EXPECT_CALL(hid_system_tray_icon(),
-              UnstageProfile(profile(), /*immediate*/ true));
+              NotifyConnectionCountUpdated(profile_to_be_destroyed));
+  connection_tracker->IncrementConnectionCount(origin);
+  EXPECT_EQ(connection_tracker->total_connection_count(), 2);
+  EXPECT_THAT(connection_tracker->GetOriginsForTesting(),
+              UnorderedElementsAre(Pair(origin, 2)));
+
+  EXPECT_CALL(hid_system_tray_icon(),
+              UnstageProfile(profile_to_be_destroyed, /*immediate=*/true));
   profile_manager()->DeleteTestingProfile(kTestProfileName);
 }
-
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-TEST_F(HidConnectionTrackerTest, DeviceConnectedNotificationByExtension) {
-  std::string extension_name(kExtensionName);
-  auto extension = CreateExtensionWithName(extension_name);
-  hid_connection_tracker().NotifyDeviceConnected(extension->origin());
-  CheckDeviceConnectedNotification(extension->origin(), extension_name);
-}
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/hid/hid_pinned_notification.cc b/chrome/browser/hid/hid_pinned_notification.cc
index 2dd6112..04c0a0d9 100644
--- a/chrome/browser/hid/hid_pinned_notification.cc
+++ b/chrome/browser/hid/hid_pinned_notification.cc
@@ -45,7 +45,7 @@
                     HidConnectionTrackerFactory::GetForProfile(
                         profile, /*create=*/false);
                 DCHECK(hid_connection_tracker);
-                hid_connection_tracker->ShowHidContentSettingsExceptions();
+                hid_connection_tracker->ShowContentSettingsExceptions();
               },
               profile));
   auto notification_id = GetNotificationId(profile);
@@ -54,7 +54,7 @@
   DCHECK(hid_connection_tracker);
   auto notification = std::make_unique<message_center::Notification>(
       message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
-      GetTooltipLabel(hid_connection_tracker->connection_count()),
+      GetTooltipLabel(hid_connection_tracker->total_connection_count()),
       /*message=*/std::u16string(), /*icon=*/ui::ImageModel(),
       /*display_source=*/std::u16string(), /*origin_url=*/GURL(),
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/hid/hid_pinned_notification_unittest.cc b/chrome/browser/hid/hid_pinned_notification_unittest.cc
index 0ac245938..6339c244 100644
--- a/chrome/browser/hid/hid_pinned_notification_unittest.cc
+++ b/chrome/browser/hid/hid_pinned_notification_unittest.cc
@@ -53,7 +53,7 @@
                 GetExpectedButtonTitleForProfile(pair.first));
       EXPECT_TRUE(maybe_notification->delegate());
 
-      EXPECT_CALL(*hid_connection_tracker, ShowHidContentSettingsExceptions());
+      EXPECT_CALL(*hid_connection_tracker, ShowContentSettingsExceptions());
       SimulateButtonClick(pair.first);
     }
   }
diff --git a/chrome/browser/hid/hid_status_icon.cc b/chrome/browser/hid/hid_status_icon.cc
index 589e034..41c979b6 100644
--- a/chrome/browser/hid/hid_status_icon.cc
+++ b/chrome/browser/hid/hid_status_icon.cc
@@ -58,7 +58,7 @@
     auto* hid_connection_tracker = HidConnectionTrackerFactory::GetForProfile(
         profiles_[profile_idx], /*create=*/false);
     DCHECK(hid_connection_tracker);
-    hid_connection_tracker->ShowHidContentSettingsExceptions();
+    hid_connection_tracker->ShowContentSettingsExceptions();
   }
 }
 
@@ -68,7 +68,7 @@
     auto* hid_connection_tracker =
         HidConnectionTrackerFactory::GetForProfile(profile, /*create=*/false);
     DCHECK(hid_connection_tracker);
-    total_connection_count += hid_connection_tracker->connection_count();
+    total_connection_count += hid_connection_tracker->total_connection_count();
   }
   return total_connection_count;
 }
diff --git a/chrome/browser/hid/hid_status_icon_unittest.cc b/chrome/browser/hid/hid_status_icon_unittest.cc
index 543bd32a..7993267a 100644
--- a/chrome/browser/hid/hid_status_icon_unittest.cc
+++ b/chrome/browser/hid/hid_status_icon_unittest.cc
@@ -102,8 +102,7 @@
         EXPECT_EQ(menu_item->GetLabelAt(idx),
                   GetExpectedButtonTitleForProfile(
                       profile_connection_counts[idx].first));
-        EXPECT_CALL(*hid_connection_tracker,
-                    ShowHidContentSettingsExceptions());
+        EXPECT_CALL(*hid_connection_tracker, ShowContentSettingsExceptions());
         SimulateButtonClick(idx);
       }
       total_connection_count += profile_connection_counts[idx].second;
@@ -162,6 +161,7 @@
 }
 
 TEST_F(HidStatusIconTest, NumProfilesOverLimit) {
+  auto origin = url::Origin::Create(GURL("https://www.example.com"));
   // Set to 10 more profiles than the max limit.
   size_t num_profiles = kMenuMaxItemCount + 10;
   std::vector<std::pair<Profile*, size_t>> profile_connection_counts;
@@ -172,7 +172,7 @@
     hid_connection_trackers.emplace_back(
         HidConnectionTrackerFactory::GetForProfile(profile,
                                                    /*create=*/true));
-    hid_connection_trackers[idx]->IncrementConnectionCount();
+    hid_connection_trackers[idx]->IncrementConnectionCount(origin);
     profile_connection_counts.push_back({profile, 1});
   }
   // CheckIcon has the logic to expect the icon button size is
diff --git a/chrome/browser/hid/hid_system_tray_icon_unittest.cc b/chrome/browser/hid/hid_system_tray_icon_unittest.cc
index 0fb2e8c..b7e7658 100644
--- a/chrome/browser/hid/hid_system_tray_icon_unittest.cc
+++ b/chrome/browser/hid/hid_system_tray_icon_unittest.cc
@@ -88,32 +88,34 @@
 }
 
 void HidSystemTrayIconTestBase::TestSingleProfile() {
+  auto origin = url::Origin::Create(GURL("https://www.example.com"));
   Profile* profile = CreateTestingProfile("user");
   HidConnectionTracker* hid_connection_tracker =
       HidConnectionTrackerFactory::GetForProfile(profile, /*create=*/true);
   CheckIconHidden();
 
-  hid_connection_tracker->IncrementConnectionCount();
+  hid_connection_tracker->IncrementConnectionCount(origin);
   CheckIcon({{profile, 1}});
 
-  hid_connection_tracker->IncrementConnectionCount();
+  hid_connection_tracker->IncrementConnectionCount(origin);
   CheckIcon({{profile, 2}});
 
-  hid_connection_tracker->IncrementConnectionCount();
+  hid_connection_tracker->IncrementConnectionCount(origin);
   CheckIcon({{profile, 3}});
 
-  hid_connection_tracker->DecrementConnectionCount();
+  hid_connection_tracker->DecrementConnectionCount(origin);
   CheckIcon({{profile, 2}});
 
-  hid_connection_tracker->DecrementConnectionCount();
+  hid_connection_tracker->DecrementConnectionCount(origin);
   CheckIcon({{profile, 1}});
 
-  hid_connection_tracker->DecrementConnectionCount();
+  hid_connection_tracker->DecrementConnectionCount(origin);
   task_environment()->FastForwardBy(HidSystemTrayIcon::kProfileUnstagingTime);
   CheckIconHidden();
 }
 
 void HidSystemTrayIconTestBase::TestProfileShownWhileUnstaging() {
+  auto origin = url::Origin::Create(GURL("https://www.example.com"));
   Profile* profile = CreateTestingProfile("user");
   HidConnectionTracker* hid_connection_tracker =
       HidConnectionTrackerFactory::GetForProfile(profile, /*create=*/true);
@@ -122,10 +124,10 @@
   // Check the profile is visible while unstaging during 1000ms interval and
   // removed after that.
   {
-    hid_connection_tracker->IncrementConnectionCount();
+    hid_connection_tracker->IncrementConnectionCount(origin);
     CheckIcon({{profile, 1}});
 
-    hid_connection_tracker->DecrementConnectionCount();
+    hid_connection_tracker->DecrementConnectionCount(origin);
     task_environment()->FastForwardBy(base::Seconds(6));
     // Connection count is updated immediately while the profile is scheduled
     // to be removed later.
@@ -137,17 +139,17 @@
   // Simulate bouncing the device connection and make sure the profile exist
   // during 1000ms interval and removed eventually.
   {
-    hid_connection_tracker->IncrementConnectionCount();
+    hid_connection_tracker->IncrementConnectionCount(origin);
     CheckIcon({{profile, 1}});
-    hid_connection_tracker->DecrementConnectionCount();
+    hid_connection_tracker->DecrementConnectionCount(origin);
     CheckIcon({{profile, 0}});
-    hid_connection_tracker->IncrementConnectionCount();
+    hid_connection_tracker->IncrementConnectionCount(origin);
     CheckIcon({{profile, 1}});
-    hid_connection_tracker->DecrementConnectionCount();
+    hid_connection_tracker->DecrementConnectionCount(origin);
     CheckIcon({{profile, 0}});
-    hid_connection_tracker->IncrementConnectionCount();
+    hid_connection_tracker->IncrementConnectionCount(origin);
     CheckIcon({{profile, 1}});
-    hid_connection_tracker->DecrementConnectionCount();
+    hid_connection_tracker->DecrementConnectionCount(origin);
     CheckIcon({{profile, 0}});
     task_environment()->FastForwardBy(HidSystemTrayIcon::kProfileUnstagingTime);
     CheckIconHidden();
@@ -155,6 +157,7 @@
 }
 
 void HidSystemTrayIconTestBase::TestMultipleProfiles() {
+  auto origin = url::Origin::Create(GURL("https://www.example.com"));
   size_t num_profiles = 3;
   std::vector<Profile*> profiles;
   std::vector<HidConnectionTracker*> hid_connection_trackers;
@@ -167,13 +170,13 @@
   }
   CheckIconHidden();
 
-  hid_connection_trackers[0]->IncrementConnectionCount();
+  hid_connection_trackers[0]->IncrementConnectionCount(origin);
   CheckIcon({{profiles[0], 1}});
 
-  hid_connection_trackers[1]->IncrementConnectionCount();
+  hid_connection_trackers[1]->IncrementConnectionCount(origin);
   CheckIcon({{profiles[0], 1}, {profiles[1], 1}});
 
-  hid_connection_trackers[2]->IncrementConnectionCount();
+  hid_connection_trackers[2]->IncrementConnectionCount(origin);
   CheckIcon({{profiles[0], 1}, {profiles[1], 1}, {profiles[2], 1}});
 
   // Destroyed a profile will remove it from being tracked in the hid system
@@ -182,13 +185,13 @@
   CheckIcon({{profiles[1], 1}, {profiles[2], 1}});
 
   // The remaining two profiles are removed 5 seconds apart.
-  hid_connection_trackers[2]->DecrementConnectionCount();
+  hid_connection_trackers[2]->DecrementConnectionCount(origin);
   // Connection count is updated immediately while the profile is scheduled
   // to be removed later.
   CheckIcon({{profiles[1], 1}, {profiles[2], 0}});
 
   task_environment()->FastForwardBy(base::Seconds(5));
-  hid_connection_trackers[1]->DecrementConnectionCount();
+  hid_connection_trackers[1]->DecrementConnectionCount(origin);
   CheckIcon({{profiles[1], 0}, {profiles[2], 0}});
 
   task_environment()->FastForwardBy(base::Seconds(5));
diff --git a/chrome/browser/hid/hid_system_tray_icon_unittest.h b/chrome/browser/hid/hid_system_tray_icon_unittest.h
index af07d78..67275d2 100644
--- a/chrome/browser/hid/hid_system_tray_icon_unittest.h
+++ b/chrome/browser/hid/hid_system_tray_icon_unittest.h
@@ -17,7 +17,7 @@
  public:
   explicit MockHidConnectionTracker(Profile* profile);
   ~MockHidConnectionTracker() override;
-  MOCK_METHOD(void, ShowHidContentSettingsExceptions, (), (override));
+  MOCK_METHOD(void, ShowContentSettingsExceptions, (), (override));
 };
 
 class HidSystemTrayIconTestBase : public BrowserWithTestWindowTest {
diff --git a/chrome/browser/image_editor/event_capture_mac.h b/chrome/browser/image_editor/event_capture_mac.h
index 21e4d9f..fbe75abd 100644
--- a/chrome/browser/image_editor/event_capture_mac.h
+++ b/chrome/browser/image_editor/event_capture_mac.h
@@ -8,10 +8,7 @@
 #include <memory>
 
 #include "base/functional/callback.h"
-#include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "components/remote_cocoa/app_shim/mouse_capture.h"
-#include "components/remote_cocoa/app_shim/mouse_capture_delegate.h"
 #include "ui/events/event_handler.h"
 #include "ui/gfx/native_widget_types.h"
 
@@ -21,13 +18,13 @@
 // For other platforms we attach a pre-target handler to the main WebContents's
 // NativeWindow and can catch and consume events there, but some events over
 // the main window do not reach that approach on Mac.
-class EventCaptureMac : public remote_cocoa::CocoaMouseCaptureDelegate {
+class EventCaptureMac {
  public:
   EventCaptureMac(ui::EventHandler* event_handler,
                   base::OnceClosure capture_lost_callback,
                   gfx::NativeView web_contents_view,
                   gfx::NativeWindow target_window);
-  ~EventCaptureMac() override;
+  ~EventCaptureMac();
   EventCaptureMac(const EventCaptureMac&) = delete;
   EventCaptureMac& operator=(const EventCaptureMac&) = delete;
 
@@ -35,11 +32,6 @@
   // cursor, using a native method.
   static void SetCrossCursor();
 
-  // remote_cocoa::CocoaMouseCaptureDelegate
-  bool PostCapturedEvent(NSEvent* event) override;
-  void OnMouseCaptureLost() override;
-  NSWindow* GetWindow() const override;
-
  private:
   // Mouse capture uses CocoaMouseCapture. We create a narrow
   // local event monitor with NSEventMaskKeyDown, to only listen
@@ -47,12 +39,8 @@
   void CreateKeyDownLocalMonitor(ui::EventHandler* event_handler,
                                  gfx::NativeWindow target_native_window);
 
-  base::OnceClosure capture_lost_callback_;
-  raw_ptr<ui::EventHandler> event_handler_;
-  std::unique_ptr<remote_cocoa::CocoaMouseCapture> mouse_capture_;
-
-  struct ObjCStorage;
-  std::unique_ptr<ObjCStorage> objc_storage_;
+  class ObjCImpl;
+  std::unique_ptr<ObjCImpl> objc_impl_;
 
   base::WeakPtrFactory<EventCaptureMac> factory_{this};
 };
diff --git a/chrome/browser/image_editor/event_capture_mac.mm b/chrome/browser/image_editor/event_capture_mac.mm
index b2279db..f4e969b 100644
--- a/chrome/browser/image_editor/event_capture_mac.mm
+++ b/chrome/browser/image_editor/event_capture_mac.mm
@@ -11,15 +11,86 @@
 #include "base/check.h"
 #include "base/functional/callback.h"
 #include "base/memory/ptr_util.h"
+#include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
+#import "components/remote_cocoa/app_shim/mouse_capture.h"
+#import "components/remote_cocoa/app_shim/mouse_capture_delegate.h"
 #include "ui/events/event.h"
 #include "ui/events/event_utils.h"
 
 namespace image_editor {
 
-struct EventCaptureMac::ObjCStorage {
+class EventCaptureMac::ObjCImpl
+    : public remote_cocoa::CocoaMouseCaptureDelegate {
+ public:
+  ObjCImpl(ui::EventHandler* event_handler,
+           base::OnceClosure capture_lost_callback,
+           gfx::NativeView web_contents_view,
+           gfx::NativeWindow target_native_window)
+      : event_handler_(event_handler),
+        capture_lost_callback_(std::move(capture_lost_callback)),
+        web_contents_view_(web_contents_view.GetNativeNSView()),
+        window_(target_native_window.GetNativeNSWindow()),
+        mouse_capture_(
+            std::make_unique<remote_cocoa::CocoaMouseCapture>(this)) {}
+
+  void SetKeyboardMonitor(id local_keyboard_monitor) {
+    local_keyboard_monitor_ = local_keyboard_monitor;
+  }
+
+  void Reset() {
+    // We do not want our callback to run if mouse capture loss was caused by
+    // reset of event capture.
+    std::move(capture_lost_callback_).Reset();
+
+    // Remove the key down monitor.
+    [NSEvent removeMonitor:local_keyboard_monitor_];
+  }
+
+ private:
+  // remote_cocoa::CocoaMouseCaptureDelegate:
+  bool PostCapturedEvent(NSEvent* event) override {
+    std::unique_ptr<ui::Event> ui_event = ui::EventFromNative(event);
+    if (!ui_event) {
+      return false;
+    }
+
+    // The window from where the event is sourced. If it is outside of the
+    // browser, this window will not be equal to GetWindow().
+    NSView* view = [event.window.contentView hitTest:event.locationInWindow];
+
+    ui::EventType type = ui_event->type();
+    if (type == ui::ET_MOUSE_DRAGGED || type == ui::ET_MOUSE_RELEASED) {
+      event_handler_->OnMouseEvent(ui_event->AsMouseEvent());
+    } else if ((type == ui::ET_MOUSE_PRESSED || type == ui::ET_MOUSE_MOVED) &&
+               web_contents_view_ == view) {
+      // We do not need to record mouse clicks outside of the web contents.
+      event_handler_->OnMouseEvent(ui_event->AsMouseEvent());
+    } else if (type == ui::ET_MOUSE_MOVED && web_contents_view_ != view) {
+      // Manually set arrow cursor when region search UI is open and cursor is
+      // moved from web contents.
+      [NSCursor.arrowCursor set];
+    } else if (type == ui::ET_SCROLL) {
+      event_handler_->OnScrollEvent(ui_event->AsScrollEvent());
+    }
+
+    // If we set the ui event as handled, then we want to swallow the event.
+    return ui_event->handled();
+  }
+
+  void OnMouseCaptureLost() override {
+    if (!capture_lost_callback_.is_null()) {
+      std::move(capture_lost_callback_).Run();
+    }
+  }
+
+  NSWindow* GetWindow() const override { return window_; }
+
+  raw_ptr<ui::EventHandler> event_handler_;
+  base::OnceClosure capture_lost_callback_;
   NSView* web_contents_view_ = nil;
   NSWindow* window_ = nil;
+  std::unique_ptr<remote_cocoa::CocoaMouseCapture> mouse_capture_;
   id local_keyboard_monitor_ = nil;
 };
 
@@ -27,13 +98,10 @@
                                  base::OnceClosure capture_lost_callback,
                                  gfx::NativeView web_contents_view,
                                  gfx::NativeWindow target_native_window)
-    : capture_lost_callback_(std::move(capture_lost_callback)),
-      objc_storage_(std::make_unique<ObjCStorage>()) {
-  event_handler_ = event_handler;
-  objc_storage_->web_contents_view_ = web_contents_view.GetNativeNSView();
-  objc_storage_->window_ = target_native_window.GetNativeNSWindow();
-  mouse_capture_ = std::make_unique<remote_cocoa::CocoaMouseCapture>(this);
-
+    : objc_impl_(std::make_unique<ObjCImpl>(event_handler,
+                                            std::move(capture_lost_callback),
+                                            web_contents_view,
+                                            target_native_window)) {
   CreateKeyDownLocalMonitor(event_handler, target_native_window);
 }
 
@@ -70,62 +138,17 @@
     return event;
   };
 
-  NSEventMask event_mask = NSEventMaskKeyDown;
-  objc_storage_->local_keyboard_monitor_ =
-      [NSEvent addLocalMonitorForEventsMatchingMask:event_mask handler:block];
+  objc_impl_->SetKeyboardMonitor([NSEvent
+      addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown
+                                   handler:block]);
 }
 
 EventCaptureMac::~EventCaptureMac() {
-  // We do not want our callback to run if mouse capture loss was caused by
-  // reset of event capture.
-  std::move(capture_lost_callback_).Reset();
-  mouse_capture_.reset();
-  // Remove keydown monitor
-  [NSEvent removeMonitor:objc_storage_->local_keyboard_monitor_];
-}
-
-bool EventCaptureMac::PostCapturedEvent(NSEvent* event) {
-  std::unique_ptr<ui::Event> ui_event = ui::EventFromNative(event);
-  if (!ui_event)
-    return false;
-
-  // The window from where the event is sourced. If it is outside of the
-  // browser, this window will not be equal to GetWindow().
-  NSWindow* source = [event window];
-  NSView* contentView = [source contentView];
-  NSView* view = [contentView hitTest:[event locationInWindow]];
-
-  ui::EventType type = ui_event->type();
-  if (type == ui::ET_MOUSE_DRAGGED || type == ui::ET_MOUSE_RELEASED) {
-    event_handler_->OnMouseEvent(ui_event->AsMouseEvent());
-  } else if ((type == ui::ET_MOUSE_PRESSED || type == ui::ET_MOUSE_MOVED) &&
-             objc_storage_->web_contents_view_ == view) {
-    // We do not need to record mouse clicks outside of the web contents.
-    event_handler_->OnMouseEvent(ui_event->AsMouseEvent());
-  } else if (type == ui::ET_MOUSE_MOVED &&
-             objc_storage_->web_contents_view_ != view) {
-    // Manually set arrow cursor when region search UI is open and cursor is
-    // moved from web contents.
-    [[NSCursor arrowCursor] set];
-  } else if (type == ui::ET_SCROLL) {
-    event_handler_->OnScrollEvent(ui_event->AsScrollEvent());
-  }
-
-  // If we set the ui event as handled, then we want to swallow the event.
-  return ui_event->handled();
-}
-
-void EventCaptureMac::OnMouseCaptureLost() {
-  if (!capture_lost_callback_.is_null())
-    std::move(capture_lost_callback_).Run();
-}
-
-NSWindow* EventCaptureMac::GetWindow() const {
-  return objc_storage_->window_;
+  objc_impl_->Reset();
 }
 
 void EventCaptureMac::SetCrossCursor() {
-  [[NSCursor crosshairCursor] set];
+  [NSCursor.crosshairCursor set];
 }
 
 }  // namespace image_editor
diff --git a/chrome/browser/lacros/lacros_extension_apps_publisher.cc b/chrome/browser/lacros/lacros_extension_apps_publisher.cc
index ebe5ec52..6907b79 100644
--- a/chrome/browser/lacros/lacros_extension_apps_publisher.cc
+++ b/chrome/browser/lacros/lacros_extension_apps_publisher.cc
@@ -194,7 +194,7 @@
       return;
     apps::AppPtr app =
         MakeApp(extension, reason == extensions::UNINSTALL_REASON_MIGRATED
-                               ? Readiness::kUninstalledByMigration
+                               ? Readiness::kUninstalledByNonUser
                                : Readiness::kUninstalledByUser);
     Publish(std::move(app));
   }
diff --git a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer_unittest.cc
index 43524fc8..3943d9c 100644
--- a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer_unittest.cc
@@ -3001,10 +3001,6 @@
 #if !BUILDFLAG(IS_ANDROID)
 // Power saver mode only exists on desktop.
 TEST_F(UkmPageLoadMetricsObserverTest, TestRefreshRateThrottled) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(
-      performance_manager::features::kBatterySaverModeAvailable);
-
   TestingPrefServiceSimple local_state;
   performance_manager::user_tuning::prefs::RegisterLocalStatePrefs(
       local_state.registry());
diff --git a/chrome/browser/performance_manager/metrics/metrics_provider_unittest.cc b/chrome/browser/performance_manager/metrics/metrics_provider_unittest.cc
index 9b257ae6..fc56232 100644
--- a/chrome/browser/performance_manager/metrics/metrics_provider_unittest.cc
+++ b/chrome/browser/performance_manager/metrics/metrics_provider_unittest.cc
@@ -62,9 +62,6 @@
 
  private:
   void SetUp() override {
-    feature_list_.InitWithFeatures(
-        {performance_manager::features::kBatterySaverModeAvailable}, {});
-
     performance_manager::user_tuning::prefs::RegisterLocalStatePrefs(
         local_state_.registry());
 
@@ -87,7 +84,6 @@
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
 
   TestingPrefServiceSimple local_state_;
-  base::test::ScopedFeatureList feature_list_;
 
   std::unique_ptr<performance_manager::user_tuning::
                       TestUserPerformanceTuningManagerEnvironment>
diff --git a/chrome/browser/performance_manager/policies/page_discarding_helper_unittest.cc b/chrome/browser/performance_manager/policies/page_discarding_helper_unittest.cc
index 24666503..896d58a7 100644
--- a/chrome/browser/performance_manager/policies/page_discarding_helper_unittest.cc
+++ b/chrome/browser/performance_manager/policies/page_discarding_helper_unittest.cc
@@ -291,8 +291,6 @@
 }
 
 TEST_F(PageDiscardingHelperTest, TestCannotDiscardPageOnNoDiscardList) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures({features::kBatterySaverModeAvailable}, {});
   // static_cast page_node because it's declared as a PageNodeImpl which hides
   // the members it overrides from PageNode.
   PageDiscardingHelper::GetFromGraph(graph())->SetNoDiscardPatternsForProfile(
diff --git a/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc b/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc
index c2b3d17e..1fc0754 100644
--- a/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc
+++ b/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc
@@ -254,6 +254,11 @@
                                                          std::move(notifier));
   }
 
+  // TODO(crbug.com/1430068): call
+  // performance_manager::user_tuning::prefs::MigrateHighEfficiencyModePref
+  // here in the same patch as the UI and enterprise policy are migrated to
+  // the enum pref.
+
   pref_change_registrar_.Init(local_state);
 }
 
diff --git a/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager_unittest.cc b/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager_unittest.cc
index 8bb46c3a..fdbe17d 100644
--- a/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager_unittest.cc
+++ b/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager_unittest.cc
@@ -91,10 +91,7 @@
         local_state_.registry());
   }
 
-  void StartManager(
-      std::vector<base::test::FeatureRefAndParams> features_and_params = {
-          {performance_manager::features::kBatterySaverModeAvailable, {}},
-      }) {
+  void StartManager() {
     auto test_sampling_event_source =
         std::make_unique<base::test::TestSamplingEventSource>();
     auto test_battery_level_provider =
@@ -107,7 +104,6 @@
         std::move(test_sampling_event_source),
         std::move(test_battery_level_provider));
 
-    feature_list_.InitWithFeaturesAndParameters(features_and_params, {});
     manager_.reset(new UserPerformanceTuningManager(
         &local_state_, nullptr,
         std::make_unique<FakeFrameThrottlingDelegate>(&throttling_enabled_),
@@ -126,7 +122,6 @@
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
 
   TestingPrefServiceSimple local_state_;
-  base::test::ScopedFeatureList feature_list_;
 
   raw_ptr<base::test::TestSamplingEventSource> sampling_source_;
   raw_ptr<base::test::TestBatteryLevelProvider> battery_level_provider_;
diff --git a/chrome/browser/printing/print_backend_service_manager.cc b/chrome/browser/printing/print_backend_service_manager.cc
index 69d1eae..6e30596 100644
--- a/chrome/browser/printing/print_backend_service_manager.cc
+++ b/chrome/browser/printing/print_backend_service_manager.cc
@@ -181,8 +181,9 @@
              << ", is client being unregistered multiple times?";
     return;
   }
-  VLOG(1) << "Unregistering client with ID " << id
-          << " from print backend service.";
+  VLOG(1) << "Unregistering client with ID " << id << " (client type "
+          << ClientTypeToString(client_type.value())
+          << ") from print backend service.";
 
   absl::optional<base::TimeDelta> new_timeout =
       DetermineIdleTimeoutUpdateOnUnregisteredClient(client_type.value(),
@@ -209,6 +210,8 @@
                std::move(callback));
 
   LogCallToRemote("EnumeratePrinters", context);
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
   service->EnumeratePrinters(
       base::BindOnce(&PrintBackendServiceManager::OnDidEnumeratePrinters,
                      base::Unretained(this), std::move(context)));
@@ -227,6 +230,8 @@
   SetCrashKeys(printer_name);
 
   LogCallToRemote("FetchCapabilities", context);
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
   service->FetchCapabilities(
       printer_name,
       base::BindOnce(&PrintBackendServiceManager::OnDidFetchCapabilities,
@@ -244,6 +249,8 @@
       context.remote_id, context.saved_callback_id, std::move(callback));
 
   LogCallToRemote("GetDefaultPrinterName", context);
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
   service->GetDefaultPrinterName(
       base::BindOnce(&PrintBackendServiceManager::OnDidGetDefaultPrinterName,
                      base::Unretained(this), std::move(context)));
@@ -265,6 +272,8 @@
   SetCrashKeys(printer_name);
 
   LogCallToRemote("GetPrinterSemanticCapsAndDefaults", context);
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
   service->GetPrinterSemanticCapsAndDefaults(
       printer_name,
       base::BindOnce(
@@ -326,6 +335,8 @@
                std::move(callback));
 
   LogCallToRemote("UseDefaultSettings", context);
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
   service->UseDefaultSettings(
       *context_id,
       base::BindOnce(&PrintBackendServiceManager::OnDidUseDefaultSettings,
@@ -349,6 +360,8 @@
                std::move(callback));
 
   LogCallToRemote("AskUserForSettings", context);
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
   service->AskUserForSettings(
       *context_id, max_pages, has_selection, is_scripted,
       base::BindOnce(&PrintBackendServiceManager::OnDidAskUserForSettings,
@@ -379,6 +392,8 @@
   SetCrashKeys(printer_name);
 
   LogCallToRemote("UpdatePrintSettings", context);
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
   service->UpdatePrintSettings(
       *context_id, std::move(job_settings),
       base::BindOnce(&PrintBackendServiceManager::OnDidUpdatePrintSettings,
@@ -406,6 +421,8 @@
   SetCrashKeys(printer_name);
 
   LogCallToRemote("StartPrinting", context);
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
   service->StartPrinting(
       *context_id, document_cookie, document_name,
 #if !BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
@@ -438,6 +455,8 @@
   const uint32_t page_index = page.page_number() - 1;
 
   LogCallToRemote("RenderPrintedPage", context);
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
   service->RenderPrintedPage(
       document_cookie, page_index, page_data_type,
       std::move(serialized_page_data), page.page_size(),
@@ -466,6 +485,8 @@
   SetCrashKeys(printer_name);
 
   LogCallToRemote("RenderPrintedDocument", context);
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
   service->RenderPrintedDocument(
       document_cookie, page_count, data_type, std::move(serialized_data),
       base::BindOnce(&PrintBackendServiceManager::OnDidRenderPrintedDocument,
@@ -488,6 +509,8 @@
   SetCrashKeys(printer_name);
 
   LogCallToRemote("DocumentDone", context);
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
   service->DocumentDone(
       document_cookie,
       base::BindOnce(&PrintBackendServiceManager::OnDidDocumentDone,
@@ -510,6 +533,8 @@
   SetCrashKeys(printer_name);
 
   LogCallToRemote("Cancel", context);
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
   service->Cancel(document_cookie,
                   base::BindOnce(&PrintBackendServiceManager::OnDidCancel,
                                  base::Unretained(this), std::move(context)));
@@ -537,6 +562,8 @@
 void PrintBackendServiceManager::SetServiceForTesting(
     mojo::Remote<mojom::PrintBackendService>* remote) {
   sandboxed_service_remote_for_test_ = remote;
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
   sandboxed_service_remote_for_test_->set_disconnect_handler(base::BindOnce(
       &PrintBackendServiceManager::OnRemoteDisconnected, base::Unretained(this),
       /*sandboxed=*/true,
@@ -546,6 +573,8 @@
 void PrintBackendServiceManager::SetServiceForFallbackTesting(
     mojo::Remote<mojom::PrintBackendService>* remote) {
   unsandboxed_service_remote_for_test_ = remote;
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
   unsandboxed_service_remote_for_test_->set_disconnect_handler(base::BindOnce(
       &PrintBackendServiceManager::OnRemoteDisconnected, base::Unretained(this),
       /*sandboxed=*/false,
@@ -1007,8 +1036,10 @@
   DVLOG(1) << "Updating idle timeout for "
            << (sandboxed ? "sandboxed" : "unsandboxed")
            << " print backend service id `" << remote_id << "` to " << timeout;
+  // Safe to use base::Unretained(this) since `this` is a global singleton
+  // which never goes away.
   service.set_idle_handler(
-      kNoClientsRegisteredResetOnIdleTimeout,
+      timeout,
       base::BindRepeating(&PrintBackendServiceManager::OnIdleTimeout,
                           base::Unretained(this), sandboxed, remote_id));
 
diff --git a/chrome/browser/resources/password_manager/passwords_section.html b/chrome/browser/resources/password_manager/passwords_section.html
index c46b7845..edc454ecc 100644
--- a/chrome/browser/resources/password_manager/passwords_section.html
+++ b/chrome/browser/resources/password_manager/passwords_section.html
@@ -47,8 +47,8 @@
     $i18n{addPassword}
   </cr-button>
 </div>
-<div class="cr-secondary-text"
-    hidden="[[showImportPasswordsOption_(groups_, passwordManagerDisabled_)]]"
+<div id="descriptionLabel" class="cr-secondary-text"
+    hidden="[[!showPasswordsDescription_]]"
     inner-h-t-m-l="[[i18nAdvanced('passwordsSectionDescription')]]">
 </div>
 <div id="movePasswords" class="cr-secondary-text"
@@ -60,6 +60,10 @@
     inner-h-t-m-l="[[getImportPasswordsText_()]]"
     on-click="onImportPasswordsClicked_">
 </div>
+<div id="noPasswordsFound" class="cr-secondary-text"
+    hidden="[[!showNoPasswordsFound_(groups_, searchTerm_)]]">
+  $i18n{noPasswordsFound}
+</div>
 <div class="card" id="passwords" role="list"
     hidden$="[[hideGroupsList_(groups_, searchTerm_)]]">
   <template id="passwordsList" is="dom-repeat" initial-count="50"
diff --git a/chrome/browser/resources/password_manager/passwords_section.ts b/chrome/browser/resources/password_manager/passwords_section.ts
index 94c6adb..62bc1fdb 100644
--- a/chrome/browser/resources/password_manager/passwords_section.ts
+++ b/chrome/browser/resources/password_manager/passwords_section.ts
@@ -39,7 +39,9 @@
 export interface PasswordsSectionElement {
   $: {
     addPasswordButton: CrButtonElement,
+    descriptionLabel: HTMLElement,
     passwordsList: IronListElement,
+    noPasswordsFound: HTMLElement,
     movePasswords: HTMLElement,
     importPasswords: HTMLElement,
   };
@@ -94,7 +96,12 @@
       showMovePasswords_: {
         type: Boolean,
         computed: 'computeShowMovePasswords_(isAccountStoreUser, ' +
-            'passwordsOnDevice_)',
+            'passwordsOnDevice_, searchTerm_)',
+      },
+
+      showPasswordsDescription_: {
+        type: Boolean,
+        computed: 'computeShowPasswordsDescription_(groups_, searchTerm_)',
       },
 
       // <if expr="_google_chrome">
@@ -234,7 +241,7 @@
   private computeShowMovePasswords_(): boolean {
     // TODO(crbug.com/1420548): Check for conflicts if needed.
     return this.computePasswordsOnDevice_().length > 0 &&
-        this.isAccountStoreUser;
+        this.isAccountStoreUser && !this.searchTerm_;
   }
 
   private async onGroupsChanged_() {
@@ -284,6 +291,14 @@
     return pref.enforcement === chrome.settingsPrivate.Enforcement.ENFORCED &&
         !pref.value;
   }
+
+  private computeShowPasswordsDescription_(): boolean {
+    return !this.searchTerm_ && this.groups_.length > 0;
+  }
+
+  private showNoPasswordsFound_(): boolean {
+    return this.hideGroupsList_() && this.groups_.length > 0;
+  }
 }
 
 declare global {
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index 8e6fd1b..9fefe083 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -89,6 +89,7 @@
     "autofill_page/password_check.ts",
     "autofill_page/password_edit_dialog.ts",
     "autofill_page/password_list_item.ts",
+    "autofill_page/password_preview_item.ts",
     "autofill_page/password_move_multiple_passwords_to_account_dialog.ts",
     "autofill_page/password_move_to_account_dialog.ts",
     "autofill_page/password_remove_confirmation_dialog.ts",
@@ -274,10 +275,8 @@
   # -----------------non_web_component_files start ----------------------------
 
   non_web_component_files = [
-    "a11y_page/captions_browser_proxy.ts",
     "about_page/about_page_browser_proxy.ts",
     "appearance_page/appearance_browser_proxy.ts",
-    "appearance_page/fonts_browser_proxy.ts",
     "autofill_page/address_edit_dialog_components.ts",
     "autofill_page/autofill_manager_proxy.ts",
     "autofill_page/merge_passwords_store_copies_mixin.ts",
@@ -296,7 +295,6 @@
     "controls/settings_idle_load.ts",
     "downloads_page/downloads_browser_proxy.ts",
     "ensure_lazy_loaded.ts",
-    "extension_control_browser_proxy.ts",
     "focus_config.ts",
     "global_scroll_target_mixin.ts",
     "hats_browser_proxy.ts",
@@ -306,14 +304,11 @@
     "on_startup_page/on_startup_browser_proxy.ts",
     "on_startup_page/startup_urls_page_browser_proxy.ts",
     "page_visibility.ts",
-    "people_page/sync_browser_proxy.ts",
-    "people_page/profile_info_browser_proxy.ts",
     "performance_page/performance_browser_proxy.ts",
     "performance_page/performance_metrics_proxy.ts",
     "privacy_page/privacy_guide/constants.ts",
     "privacy_page/privacy_guide/privacy_guide_availability_mixin.ts",
     "privacy_page/privacy_guide/privacy_guide_browser_proxy.ts",
-    "privacy_page/privacy_page_browser_proxy.ts",
     "privacy_page/privacy_sandbox/privacy_sandbox_browser_proxy.ts",
     "privacy_page/security_keys_browser_proxy.ts",
     "privacy_sandbox/icons.html.ts",
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.ts b/chrome/browser/resources/settings/a11y_page/a11y_page.ts
index 7bc34d89..f9fe06c 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.ts
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.ts
@@ -12,6 +12,7 @@
 import '../controls/settings_toggle_button.js';
 import '../settings_page/settings_animated_pages.js';
 import '../settings_shared.css.js';
+// clang-format off
 // <if expr="not is_macosx and not is_chromeos">
 import './captions_subpage.js';
 import '../settings_page/settings_subpage.js';
@@ -20,7 +21,9 @@
 // <if expr="is_win or is_macosx">
 import './live_caption_section.js';
 
+import {CaptionsBrowserProxyImpl} from '/shared/settings/a11y_page/captions_browser_proxy.js';
 // </if>
+// clang-format on
 
 import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -32,10 +35,6 @@
 import {Router} from '../router.js';
 
 import {getTemplate} from './a11y_page.html.js';
-// <if expr="is_win or is_macosx">
-import {CaptionsBrowserProxyImpl} from './captions_browser_proxy.js';
-
-// </if>
 
 // clang-format off
 // <if expr="not is_chromeos">
@@ -43,6 +42,7 @@
 // </if>
 // clang-format on
 
+
 const SettingsA11yPageElementBase =
     WebUiListenerMixin(BaseMixin(PolymerElement));
 
diff --git a/chrome/browser/resources/settings/a11y_page/captions_subpage.ts b/chrome/browser/resources/settings/a11y_page/captions_subpage.ts
index f49dcf9..5c16088 100644
--- a/chrome/browser/resources/settings/a11y_page/captions_subpage.ts
+++ b/chrome/browser/resources/settings/a11y_page/captions_subpage.ts
@@ -11,15 +11,16 @@
 import '//resources/cr_elements/cr_shared_style.css.js';
 import '../controls/settings_slider.js';
 import '../settings_shared.css.js';
+import '../strings.m.js';
 import './live_caption_section.js';
 
+import {loadTimeData} from '//resources/js/load_time_data.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {FontsBrowserProxyImpl, FontsData} from '/shared/settings/appearance_page/fonts_browser_proxy.js';
 import {PrefsMixin} from 'chrome://resources/cr_components/settings_prefs/prefs_mixin.js';
 
-import {FontsBrowserProxyImpl, FontsData} from '../appearance_page/fonts_browser_proxy.js';
 import {DropdownMenuOptionList} from '../controls/settings_dropdown_menu.js';
 import {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js';
-import {loadTimeData} from '../i18n_setup.js';
 
 import {getTemplate} from './captions_subpage.html.js';
 
@@ -29,6 +30,7 @@
 // </if>
 // clang-format on
 
+
 const SettingsCaptionsElementBase = PrefsMixin(PolymerElement);
 
 export class SettingsCaptionsElement extends SettingsCaptionsElementBase {
diff --git a/chrome/browser/resources/settings/a11y_page/live_caption_section.ts b/chrome/browser/resources/settings/a11y_page/live_caption_section.ts
index bbad500..603a77e 100644
--- a/chrome/browser/resources/settings/a11y_page/live_caption_section.ts
+++ b/chrome/browser/resources/settings/a11y_page/live_caption_section.ts
@@ -13,15 +13,16 @@
 import '//resources/cr_elements/cr_shared_style.css.js';
 import '../controls/settings_toggle_button.js';
 import '../settings_shared.css.js';
+import '../strings.m.js';
 
 import {WebUiListenerMixin} from '//resources/cr_elements/web_ui_listener_mixin.js';
+import {loadTimeData} from '//resources/js/load_time_data.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {CaptionsBrowserProxy, CaptionsBrowserProxyImpl, LiveCaptionLanguage, LiveCaptionLanguageList} from '/shared/settings/a11y_page/captions_browser_proxy.js';
 import {PrefsMixin} from 'chrome://resources/cr_components/settings_prefs/prefs_mixin.js';
 
 import {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js';
-import {loadTimeData} from '../i18n_setup.js';
 
-import {CaptionsBrowserProxy, CaptionsBrowserProxyImpl, LiveCaptionLanguage, LiveCaptionLanguageList} from './captions_browser_proxy.js';
 import {getTemplate} from './live_caption_section.html.js';
 
 // clang-format off
diff --git a/chrome/browser/resources/settings/about_page/about_page.ts b/chrome/browser/resources/settings/about_page/about_page.ts
index 52c24ff3..04918f4 100644
--- a/chrome/browser/resources/settings/about_page/about_page.ts
+++ b/chrome/browser/resources/settings/about_page/about_page.ts
@@ -349,7 +349,7 @@
     this.aboutBrowserProxy_.openFeedbackDialog();
   }
 
-  private onGetTheMostOutOfChromeTap_() {
+  private onGetTheMostOutOfChromeClick_() {
     Router.getInstance().navigateTo(routes.GET_MOST_CHROME);
   }
   // </if>
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.ts b/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.ts
index a7f969a..74a047cf 100644
--- a/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.ts
+++ b/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.ts
@@ -8,6 +8,7 @@
 import '../settings_shared.css.js';
 import '../controls/settings_dropdown_menu.js';
 
+import {FontsBrowserProxy, FontsBrowserProxyImpl, FontsData} from '/shared/settings/appearance_page/fonts_browser_proxy.js';
 import {SliderTick} from 'chrome://resources/cr_elements/cr_slider/cr_slider.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -15,7 +16,6 @@
 import {DropdownMenuOptionList} from '../controls/settings_dropdown_menu.js';
 
 import {getTemplate} from './appearance_fonts_page.html.js';
-import {FontsBrowserProxy, FontsBrowserProxyImpl, FontsData} from './fonts_browser_proxy.js';
 
 
 const FONT_SIZE_RANGE: number[] = [
diff --git a/chrome/browser/resources/settings/autofill_page/avatar_icon.ts b/chrome/browser/resources/settings/autofill_page/avatar_icon.ts
index 483d2cc..6022938 100644
--- a/chrome/browser/resources/settings/autofill_page/avatar_icon.ts
+++ b/chrome/browser/resources/settings/autofill_page/avatar_icon.ts
@@ -7,11 +7,10 @@
  * the placeholder avatar if the user is not signed-in.
  */
 
+import {StoredAccount, SyncBrowserProxyImpl} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {StoredAccount, SyncBrowserProxyImpl} from '../people_page/sync_browser_proxy.js';
-
 import {getTemplate} from './avatar_icon.html.js';
 
 const SettingsAvatarIconElementBase = WebUiListenerMixin(PolymerElement);
diff --git a/chrome/browser/resources/settings/autofill_page/password_preview_item.html b/chrome/browser/resources/settings/autofill_page/password_preview_item.html
new file mode 100644
index 0000000..48a093a
--- /dev/null
+++ b/chrome/browser/resources/settings/autofill_page/password_preview_item.html
@@ -0,0 +1,72 @@
+<style include="settings-shared passwords-shared">
+  .flex {
+    align-items: center;
+    display: flex;
+  }
+
+  #checkbox {
+    --cr-checkbox-label-padding-start: 8px;
+    flex-grow: 0;
+  }
+
+  site-favicon {
+    margin-inline-end: 8px;
+  }
+
+  #container {
+    display: grid;
+    flex-grow: 1;
+    grid-template-columns: auto 125px;
+    width: 100%;
+  }
+
+  .url-username-group {
+    column-gap: 16px;
+    display: grid;
+    grid-template-columns: fit-content(50%) 1fr;
+    padding-inline-end: 16px;
+    width: 100%;
+  }
+
+  #website {
+    font-weight: 500;
+  }
+
+  #password:disabled {
+    flex: none;
+    font-family: inherit;
+    margin-inline-start: auto;
+    text-overflow: clip;
+    width: 50px;
+  }
+
+  cr-icon-button {
+    --cr-icon-button-margin-start: 8px;
+  }
+
+</style>
+<div class="flex">
+  <div id="checkbox">
+    <slot name="checkbox"></slot>
+  </div>
+  <div id="container" class$="[[computeElementClass_(first)]]">
+    <div class="flex">
+      <site-favicon url="[[url]]" aria-hidden="true">
+      </site-favicon>
+      <div class="url-username-group">
+        <div id="website" class="text-elide">[[url]]</div>
+        <div id="username" class="text-elide">[[username]]</div>
+      </div>
+    </div>
+    <div class="flex">
+      <input id="password" type="text" readonly
+          class="password-field password-input text-elide"
+          disabled$="[[passwordHidden_]]"
+          value="[[getPassword_(passwordHidden_)]]">
+      <cr-icon-button
+          class$="[[getIconClass_(passwordHidden_)]]"
+          on-click="onShowPasswordButtonClick_">
+      </cr-icon-button>
+    </div>
+  </div>
+</div>
diff --git a/chrome/browser/resources/settings/autofill_page/password_preview_item.ts b/chrome/browser/resources/settings/autofill_page/password_preview_item.ts
new file mode 100644
index 0000000..b0a8baa3
--- /dev/null
+++ b/chrome/browser/resources/settings/autofill_page/password_preview_item.ts
@@ -0,0 +1,73 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview PasswordPreviewItem represents one row in a list of passwords.
+ * It needs to be its own component because FocusRowBehavior provides good a11y.
+ */
+
+import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
+import 'chrome://resources/cr_elements/cr_icons.css.js';
+import '../settings_shared.css.js';
+import '../site_favicon.js';
+import './passwords_shared.css.js';
+
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {getTemplate} from './password_preview_item.html.js';
+
+export class PasswordPreviewItemElement extends PolymerElement {
+  static get is() {
+    return 'password-preview-item';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  static get properties() {
+    return {
+      url: String,
+      username: String,
+      password: String,
+      first: Boolean,
+
+      passwordHidden_: {
+        type: Boolean,
+        value: true,
+      },
+    };
+  }
+
+  url: string;
+  username: string;
+  password: string;
+  first: boolean;
+  private passwordHidden_: boolean;
+
+  private computeElementClass_(): string {
+    return this.first ? '' : 'hr';
+  }
+
+  private getIconClass_(): string {
+    return !this.passwordHidden_ ? 'icon-visibility-off' : 'icon-visibility';
+  }
+
+  private getPassword_(): string {
+    return !this.passwordHidden_ ? this.password : '•••••••••••';
+  }
+
+  private onShowPasswordButtonClick_(): void {
+    this.passwordHidden_ = !this.passwordHidden_;
+  }
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'password-preview-item': PasswordPreviewItemElement;
+  }
+}
+
+customElements.define(
+    PasswordPreviewItemElement.is, PasswordPreviewItemElement);
diff --git a/chrome/browser/resources/settings/autofill_page/password_remove_dialog.ts b/chrome/browser/resources/settings/autofill_page/password_remove_dialog.ts
index 26c1019..e87d0866 100644
--- a/chrome/browser/resources/settings/autofill_page/password_remove_dialog.ts
+++ b/chrome/browser/resources/settings/autofill_page/password_remove_dialog.ts
@@ -17,14 +17,13 @@
 import './avatar_icon.js';
 import './passwords_shared.css.js';
 
+import {SyncBrowserProxyImpl} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js';
 import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
-import {assert} from 'chrome://resources/js/assert_ts.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
+import {assert} from 'chrome://resources/js/assert_ts.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {SyncBrowserProxyImpl} from '../people_page/sync_browser_proxy.js';
-
 import {PasswordManagerImpl} from './password_manager_proxy.js';
 import {getTemplate} from './password_remove_dialog.html.js';
 
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts b/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts
index 04e98ea..bf84fbf 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts
+++ b/chrome/browser/resources/settings/autofill_page/passwords_device_section.ts
@@ -22,6 +22,7 @@
 import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js';
 import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
 
+import {StoredAccount, SyncBrowserProxyImpl, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {CrToastElement} from 'chrome://resources/cr_elements/cr_toast/cr_toast.js';
 import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {OpenWindowProxyImpl} from 'chrome://resources/js/open_window_proxy.js';
@@ -32,7 +33,6 @@
 
 import {GlobalScrollTargetMixin} from '../global_scroll_target_mixin.js';
 import {loadTimeData} from '../i18n_setup.js';
-import {StoredAccount, SyncBrowserProxyImpl, SyncStatus} from '../people_page/sync_browser_proxy.js';
 import {routes} from '../route.js';
 import {Route, RouteObserverMixin, Router} from '../router.js';
 
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.html b/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.html
index 117ef1e..a47942a 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.html
+++ b/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.html
@@ -64,6 +64,14 @@
     padding: 8px;
   }
 
+  #conflictsList {
+    margin-top: 16px;
+  }
+
+  .disabled-conflicts-list {
+    opacity: 50%;
+  }
+
   #deleteFileOption {
     margin-top: 16px;
     --cr-checkbox-label-padding-start: 15px;
@@ -169,10 +177,16 @@
         hidden="[[shouldHideDeleteFileOption_(dialogState, results_)]]"
         inner-h-t-m-l="[[getCheckboxLabelHtml_(results_)]]">
     </cr-checkbox>
-    <div id="conflictsList"
+    <div id="conflictsList" class$="[[computeConflictsListClass_(inProgress_)]]"
          hidden="[[!isState_(importDialogStateEnum_.CONFLICTS, dialogState)]]">
-      <!-- TODO(crbug/1417650): Implement new password-list-item according to
-                                the Passwords Import M2 mocks. -->
+      <template is="dom-repeat" items="[[conflicts_]]">
+        <password-preview-item url="[[item.url]]" username="[[item.username]]"
+            password="[[item.password]]" first="[[!index]]">
+          <cr-checkbox slot="checkbox" on-change="onPasswordSelectedChange_"
+              data-id$="[[item.id]]" disabled="[[inProgress_]]">
+          </cr-checkbox>
+        </password-preview-item>
+      </template>
     </div>
     <div hidden="[[shouldHideFailuresSummary_(dialogState, results_)]]">
       <div id="failuresTitleRow" class="flex">
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.ts b/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.ts
index d2aea5bb..1d82dfc 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.ts
+++ b/chrome/browser/resources/settings/autofill_page/passwords_import_dialog.ts
@@ -15,6 +15,7 @@
 import '../settings_shared.css.js';
 import '../site_favicon.js';
 import './passwords_shared.css.js';
+import './password_preview_item.js';
 
 import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js';
 import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js';
@@ -135,9 +136,16 @@
         type: Boolean,
         value: false,
       },
+
+      conflictsSelectedForReplace_: {
+        type: Array,
+        value: [],
+      },
+
       shouldDisableReplaceButton_: {
         type: Boolean,
-        value: true,
+        computed: 'computeShouldDisableReplaceButton_(' +
+            'conflictsSelectedForReplace_, inProgress_)',
       },
     };
   }
@@ -149,7 +157,9 @@
   private results_: chrome.passwordsPrivate.ImportResults|null;
   private descriptionText_: TrustedHTML;
   private failedImportsWithKnownErrors_: chrome.passwordsPrivate.ImportEntry[];
+  private conflicts_: chrome.passwordsPrivate.ImportEntry[];
   private shouldDisableReplaceButton_: boolean;
+  private conflictsSelectedForReplace_: number[];
   private failedImportsSummary_: string;
   private conflictsTitle_: string;
   private enablePasswordsImportM2_: boolean;
@@ -188,6 +198,10 @@
     this.dialogState = ImportDialogState.START;
   }
 
+  private computeConflictsListClass_(): string {
+    return this.inProgress_ ? 'disabled-conflicts-list' : '';
+  }
+
   private isState_(state: ImportDialogState): boolean {
     return this.dialogState === state;
   }
@@ -235,6 +249,28 @@
     return this.isState_(ImportDialogState.START) && this.isAccountStoreUser;
   }
 
+  private getSelectedIds_(): number[] {
+    const checkboxes = this.$.conflictsList.querySelectorAll('cr-checkbox');
+    const selectedPasswords: number[] = [];
+    checkboxes.forEach((checkbox: CrCheckboxElement) => {
+      if (checkbox.checked) {
+        selectedPasswords.push(Number(checkbox.dataset['id']));
+      }
+    });
+    return selectedPasswords;
+  }
+
+  /**
+   * Handler for ticking conflicting password checkbox.
+   */
+  private onPasswordSelectedChange_(): void {
+    this.conflictsSelectedForReplace_ = this.getSelectedIds_();
+  }
+
+  private computeShouldDisableReplaceButton_(): boolean {
+    return this.inProgress_ || !this.conflictsSelectedForReplace_.length;
+  }
+
   /**
    * Handler for clicking the 'chooseFile' button. It triggers import flow.
    */
@@ -266,9 +302,8 @@
   private async onReplaceClick_() {
     assert(this.isState_(ImportDialogState.CONFLICTS));
     this.inProgress_ = true;
-    // TODO(crbug/1417650): Compute selectedIds based on the ticked checkboxes.
-    const selectedIds: number[] = [];
-    this.results_ = await this.passwordManager_.continueImport(selectedIds);
+    this.results_ = await this.passwordManager_.continueImport(
+        this.conflictsSelectedForReplace_);
     this.processResults_();
   }
 
@@ -288,6 +323,7 @@
             await PluralStringProxyImpl.getInstance().getPluralString(
                 'importPasswordsConflictsTitle',
                 this.results_.displayedEntries.length);
+        this.conflicts_ = this.results_.displayedEntries;
         this.dialogState = ImportDialogState.CONFLICTS;
         return;
       case chrome.passwordsPrivate.ImportResultsStatus.MAX_FILE_SIZE:
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_list_handler.ts b/chrome/browser/resources/settings/autofill_page/passwords_list_handler.ts
index 83546588..0b2e85d 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_list_handler.ts
+++ b/chrome/browser/resources/settings/autofill_page/passwords_list_handler.ts
@@ -22,6 +22,7 @@
 import 'chrome://resources/cr_elements/cr_button/cr_button.js';
 import 'chrome://resources/cr_elements/cr_toast/cr_toast.js';
 
+import {StoredAccount, SyncBrowserProxyImpl} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
 import {CrActionMenuElement} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
 import {CrToastElement} from 'chrome://resources/cr_elements/cr_toast/cr_toast.js';
@@ -32,7 +33,6 @@
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {loadTimeData} from '../i18n_setup.js';
-import {StoredAccount, SyncBrowserProxyImpl} from '../people_page/sync_browser_proxy.js';
 import {routes} from '../route.js';
 import {Route, RouteObserverMixin, Router} from '../router.js';
 
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_section.ts b/chrome/browser/resources/settings/autofill_page/passwords_section.ts
index 3aa2ded..330bb2d8 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_section.ts
+++ b/chrome/browser/resources/settings/autofill_page/passwords_section.ts
@@ -32,6 +32,7 @@
 import './passwords_shared.css.js';
 import './avatar_icon.js';
 
+import {SyncBrowserProxyImpl, TrustedVaultBannerState} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {PrefsMixin} from 'chrome://resources/cr_components/settings_prefs/prefs_mixin.js';
 import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
 import {CrActionMenuElement} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
@@ -50,7 +51,6 @@
 import {GlobalScrollTargetMixin} from '../global_scroll_target_mixin.js';
 import {HatsBrowserProxyImpl, TrustSafetyInteraction} from '../hats_browser_proxy.js';
 import {loadTimeData} from '../i18n_setup.js';
-import {SyncBrowserProxyImpl, TrustedVaultBannerState} from '../people_page/sync_browser_proxy.js';
 import {routes} from '../route.js';
 import {Route, RouteObserverMixin, Router} from '../router.js';
 
diff --git a/chrome/browser/resources/settings/autofill_page/user_util_mixin.ts b/chrome/browser/resources/settings/autofill_page/user_util_mixin.ts
index 6650985d..ca86a8a3 100644
--- a/chrome/browser/resources/settings/autofill_page/user_util_mixin.ts
+++ b/chrome/browser/resources/settings/autofill_page/user_util_mixin.ts
@@ -2,12 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {StoredAccount, SyncBrowserProxyImpl, SyncPrefs, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {WebUiListenerMixin, WebUiListenerMixinInterface} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {assert} from 'chrome://resources/js/assert_ts.js';
 import {dedupingMixin, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {StoredAccount, SyncBrowserProxyImpl, SyncPrefs, SyncStatus} from '../people_page/sync_browser_proxy.js';
-
 import {PasswordManagerImpl, PasswordManagerProxy} from './password_manager_proxy.js';
 
 type Constructor<T> = new (...args: any[]) => T;
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html
index 2c9d775..bed0197c 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.html
+++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -210,7 +210,7 @@
                 if="[[showGetMostChrome_(pageVisibility.getMostChrome)]]"
                 restamp>
               <settings-section page-title="$i18n{getTheMostOutOfChrome}"
-                  section="getMostChrome">
+                  section="getMostChrome" no-search>
                 <settings-get-most-chrome-page></settings-get-most-chrome-page>
               </settings-section>
             </template>
diff --git a/chrome/browser/resources/settings/chromeos/device_page/storage.ts b/chrome/browser/resources/settings/chromeos/device_page/storage.ts
index 5b01196..91d2491 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/storage.ts
+++ b/chrome/browser/resources/settings/chromeos/device_page/storage.ts
@@ -267,8 +267,10 @@
    *     Google Drive.
    */
   private handleDriveOfflineSizeChanged_(size: string): void {
-    this.shadowRoot!.querySelector<CrLinkRowElement>(
-                        '#driveOfflineSize')!.subLabel = size;
+    if (this.showDriveOfflineStorage_) {
+      this.shadowRoot!.querySelector<CrLinkRowElement>(
+                          '#driveOfflineSize')!.subLabel = size;
+    }
   }
 
   /**
diff --git a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_task_continuation_item.ts b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_task_continuation_item.ts
index 0f45945092..c42091b 100644
--- a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_task_continuation_item.ts
+++ b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_task_continuation_item.ts
@@ -22,11 +22,10 @@
 import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.js';
 import '../../settings_shared.css.js';
 
+import {SyncBrowserProxy, SyncBrowserProxyImpl, SyncPrefs} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {SyncBrowserProxy, SyncBrowserProxyImpl, SyncPrefs} from '../../people_page/sync_browser_proxy.js';
-
 import {SettingsMultideviceFeatureItemElement} from './multidevice_feature_item.js';
 import {MultiDeviceFeatureMixin} from './multidevice_feature_mixin.js';
 import {getTemplate} from './multidevice_task_continuation_item.html.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/os_apps_page.ts b/chrome/browser/resources/settings/chromeos/os_apps_page/os_apps_page.ts
index 07a70921..97d4f72 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/os_apps_page.ts
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/os_apps_page.ts
@@ -56,7 +56,7 @@
     case Readiness.kTerminated:
       return true;
     case Readiness.kUninstalledByUser:
-    case Readiness.kUninstalledByMigration:
+    case Readiness.kUninstalledByNonUser:
     case Readiness.kRemoved:
     case Readiness.kUnknown:
       return false;
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.ts b/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.ts
index c271f52..9ff14e3 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.ts
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.ts
@@ -18,14 +18,14 @@
 import '../os_settings_page/os_settings_subpage.js';
 import '../parental_controls_page/parental_controls_page.js';
 
+import {ProfileInfo, ProfileInfoBrowserProxyImpl} from '/shared/settings/people_page/profile_info_browser_proxy.js';
+import {SyncBrowserProxy, SyncBrowserProxyImpl, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {convertImageSequenceToPng} from 'chrome://resources/ash/common/cr_picture/png.js';
 import {sendWithPromise} from 'chrome://resources/js/cr.js';
 import {getImage} from 'chrome://resources/js/icon.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {afterNextRender, flush, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {ProfileInfo, ProfileInfoBrowserProxyImpl} from '../../people_page/profile_info_browser_proxy.js';
-import {SyncBrowserProxy, SyncBrowserProxyImpl, SyncStatus} from '../../people_page/sync_browser_proxy.js';
 import {DeepLinkingMixin} from '../deep_linking_mixin.js';
 import {LockStateMixin} from '../lock_state_mixin.js';
 import {Setting} from '../mojom-webui/setting.mojom-webui.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/os_sync_encryption_options.ts b/chrome/browser/resources/settings/chromeos/os_people_page/os_sync_encryption_options.ts
index 46f8ed6..bc927938 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/os_sync_encryption_options.ts
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/os_sync_encryption_options.ts
@@ -12,11 +12,10 @@
 
 import {CrInputElement} from '//resources/cr_elements/cr_input/cr_input.js';
 import {CrRadioGroupElement} from '//resources/cr_elements/cr_radio_group/cr_radio_group.js';
-
 import {assert} from '//resources/js/assert_ts.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {SyncBrowserProxyImpl, SyncPrefs, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
 
-import {SyncBrowserProxyImpl, SyncPrefs, SyncStatus} from '../../people_page/sync_browser_proxy.js';
 import {getTemplate} from './os_sync_encryption_options.html.js';
 
 /**
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/os_sync_subpage.ts b/chrome/browser/resources/settings/chromeos/os_people_page/os_sync_subpage.ts
index 6a09bfe8..b8a1e3d 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/os_sync_subpage.ts
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/os_sync_subpage.ts
@@ -32,10 +32,10 @@
 import {focusWithoutInk} from '//resources/js/focus_without_ink.js';
 import {IronCollapseElement} from '//resources/polymer/v3_0/iron-collapse/iron-collapse.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {PageStatus, StatusAction, SyncBrowserProxy, SyncBrowserProxyImpl, SyncPrefs, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 
-import {PageStatus, StatusAction, SyncBrowserProxy, SyncBrowserProxyImpl, SyncPrefs, SyncStatus} from '../../people_page/sync_browser_proxy.js';
 import {FocusConfig} from '../focus_config.js';
 import {RouteObserverMixin} from '../route_observer_mixin.js';
 import {Router} from '../router.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.gni b/chrome/browser/resources/settings/chromeos/os_settings.gni
index 6043e89a..84e4bd75 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings.gni
+++ b/chrome/browser/resources/settings/chromeos/os_settings.gni
@@ -411,16 +411,9 @@
   "chromeos/setting_id_param_util.ts",
 
   # Files below are from Browser Settings and shared with ChromeOS Settings
-  "a11y_page/captions_browser_proxy.ts",
-  "appearance_page/fonts_browser_proxy.ts",
   "controls/cr_policy_pref_mixin.ts",
   "controls/pref_control_mixin.ts",
   "controls/settings_boolean_control_mixin.ts",
-  "extension_control_browser_proxy.ts",
-  "i18n_setup.ts",
-  "people_page/profile_info_browser_proxy.ts",
-  "people_page/sync_browser_proxy.ts",
-  "privacy_page/privacy_page_browser_proxy.ts",
 ]
 
 mojom_webui_files = [
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.ts b/chrome/browser/resources/settings/chromeos/os_settings.ts
index 8f0194d..5992db5 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings.ts
+++ b/chrome/browser/resources/settings/chromeos/os_settings.ts
@@ -100,6 +100,9 @@
 export {getNearbyShareSettings, observeNearbyShareSettings, setNearbyShareSettingsForTesting} from '/shared/nearby_share_settings.js';
 export {NearbySettings, NearbyShareSettingsMixin} from '/shared/nearby_share_settings_mixin.js';
 export {LifetimeBrowserProxyImpl} from '/shared/settings/lifetime_browser_proxy.js';
+export {ProfileInfoBrowserProxyImpl} from '/shared/settings/people_page/profile_info_browser_proxy.js';
+export {PageStatus, StatusAction, StoredAccount, SyncBrowserProxy, SyncBrowserProxyImpl, SyncPrefs, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
+export {PrivacyPageBrowserProxyImpl, SecureDnsMode, SecureDnsUiManagementMode} from '/shared/settings/privacy_page/privacy_page_browser_proxy.js';
 export {SettingsPrefsElement} from 'chrome://resources/cr_components/settings_prefs/prefs.js';
 export {CrSettingsPrefs} from 'chrome://resources/cr_components/settings_prefs/prefs_types.js';
 export {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js';
@@ -108,9 +111,6 @@
 export {SettingsDropdownMenuElement} from '../controls/settings_dropdown_menu.js';
 export {SettingsSliderElement} from '../controls/settings_slider.js';
 export {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js';
-export {ProfileInfoBrowserProxyImpl} from '../people_page/profile_info_browser_proxy.js';
-export {PageStatus, StatusAction, StoredAccount, SyncBrowserProxy, SyncBrowserProxyImpl, SyncPrefs, SyncStatus} from '../people_page/sync_browser_proxy.js';
-export {PrivacyPageBrowserProxyImpl, SecureDnsMode, SecureDnsUiManagementMode} from '../privacy_page/privacy_page_browser_proxy.js';
 export {setCrosAudioConfigForTesting} from './device_page/cros_audio_config.js';
 export {DevicePageBrowserProxy, DevicePageBrowserProxyImpl, IdleBehavior, LidClosedBehavior, NoteAppInfo, NoteAppLockScreenSupport, setDisplayApiForTesting, StorageSpaceState} from './device_page/device_page_browser_proxy.js';
 export * as fakeCrosAudioConfig from './device_page/fake_cros_audio_config.js';
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.ts b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.ts
index 3fcf6a8..446b9a4b 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.ts
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.ts
@@ -19,6 +19,7 @@
 import '../icons.html.js';
 import '../settings_shared.css.js';
 
+import {StatusAction, SyncBrowserProxy, SyncBrowserProxyImpl, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
 import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
@@ -33,7 +34,6 @@
 import {SettingsCheckboxElement} from '../controls/settings_checkbox.js';
 import {DropdownMenuOptionList} from '../controls/settings_dropdown_menu.js';
 import {loadTimeData} from '../i18n_setup.js';
-import {StatusAction, SyncBrowserProxy, SyncBrowserProxyImpl, SyncStatus} from '../people_page/sync_browser_proxy.js';
 import {routes} from '../route.js';
 import {Route, RouteObserverMixin, Router} from '../router.js';
 
diff --git a/chrome/browser/resources/settings/controls/extension_controlled_indicator.ts b/chrome/browser/resources/settings/controls/extension_controlled_indicator.ts
index ebf2ad9..d5b4224 100644
--- a/chrome/browser/resources/settings/controls/extension_controlled_indicator.ts
+++ b/chrome/browser/resources/settings/controls/extension_controlled_indicator.ts
@@ -3,16 +3,15 @@
 // found in the LICENSE file.
 
 import '//resources/cr_elements/cr_button/cr_button.js';
-import '../i18n_setup.js';
+import '../strings.m.js';
 import '../settings_shared.css.js';
 
 import {assert} from '//resources/js/assert_ts.js';
 import {loadTimeData} from '//resources/js/load_time_data.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {ExtensionControlBrowserProxyImpl} from '/shared/settings/extension_control_browser_proxy.js';
 import {OpenWindowProxyImpl} from 'chrome://resources/js/open_window_proxy.js';
 
-import {ExtensionControlBrowserProxyImpl} from '../extension_control_browser_proxy.js';
-
 import {getTemplate} from './extension_controlled_indicator.html.js';
 
 export class ExtensionControlledIndicatorElement extends PolymerElement {
diff --git a/chrome/browser/resources/settings/controls/settings_slider.ts b/chrome/browser/resources/settings/controls/settings_slider.ts
index 5d0fcb9..eb11978 100644
--- a/chrome/browser/resources/settings/controls/settings_slider.ts
+++ b/chrome/browser/resources/settings/controls/settings_slider.ts
@@ -9,6 +9,7 @@
  * to a tick mark, it interpolates to the nearest tick.
  */
 import '../settings_vars.css.js';
+import '../strings.m.js';
 import '//resources/cr_elements/cr_slider/cr_slider.js';
 // <if expr='chromeos_ash'>
 import 'chrome://resources/cr_elements/chromeos/cros_color_overrides.css.js';
@@ -17,10 +18,9 @@
 
 import {CrSliderElement, SliderTick} from '//resources/cr_elements/cr_slider/cr_slider.js';
 import {assert} from '//resources/js/assert_ts.js';
+import {loadTimeData} from '//resources/js/load_time_data.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {loadTimeData} from '../i18n_setup.js';
-
 import {CrPolicyPrefMixin} from './cr_policy_pref_mixin.js';
 import {getTemplate} from './settings_slider.html.js';
 
diff --git a/chrome/browser/resources/settings/get_most_chrome_page/get_most_chrome_page.html b/chrome/browser/resources/settings/get_most_chrome_page/get_most_chrome_page.html
index 7c89b54..d917b83 100644
--- a/chrome/browser/resources/settings/get_most_chrome_page/get_most_chrome_page.html
+++ b/chrome/browser/resources/settings/get_most_chrome_page/get_most_chrome_page.html
@@ -1 +1,29 @@
-<div></div>
+<style include="cr-shared-style settings-shared">
+</style>
+<div class="cr-row">
+  <div class="cr-padded-text">$i18n{getTheMostOutOfChromeIntro}</div>
+</div>
+<cr-expand-button class="cr-row hr" expanded="{{expandedMoreThanABrowser_}}">
+  <div>$i18n{getTheMostOutOfChromeMoreThanABrowser}</div>
+</cr-expand-button>
+<iron-collapse opened="[[expandedMoreThanABrowser_]]">
+  <div class="cr-row">
+    <div class="cr-padded-text">&nbsp;</div>
+  </div>
+</iron-collapse>
+<cr-expand-button class="cr-row hr" expanded="{{expandedYourDataInChrome_}}">
+  <div>$i18n{getTheMostOutOfChromeYourDataInChrome}</div>
+</cr-expand-button>
+<iron-collapse opened="[[expandedYourDataInChrome_]]">
+  <div class="cr-row">
+    <div class="cr-padded-text">&nbsp;</div>
+  </div>
+</iron-collapse>
+<cr-expand-button class="cr-row hr" expanded="{{expandedBeyondCookies_}}">
+  <div>$i18n{getTheMostOutOfChromeBeyondCookies}</div>
+</cr-expand-button>
+<iron-collapse opened="[[expandedBeyondCookies_]]">
+  <div class="cr-row">
+    <div class="cr-padded-text">&nbsp;</div>
+  </div>
+</iron-collapse>
diff --git a/chrome/browser/resources/settings/get_most_chrome_page/get_most_chrome_page.ts b/chrome/browser/resources/settings/get_most_chrome_page/get_most_chrome_page.ts
index 029614ab..b0d8929 100644
--- a/chrome/browser/resources/settings/get_most_chrome_page/get_most_chrome_page.ts
+++ b/chrome/browser/resources/settings/get_most_chrome_page/get_most_chrome_page.ts
@@ -8,6 +8,11 @@
  * to get the most out of Chrome.
  */
 
+import '../settings_shared.css.js';
+import 'chrome://resources/cr_elements/cr_expand_button/cr_expand_button.js';
+import 'chrome://resources/cr_elements/cr_shared_style.css.js';
+import 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js';
+
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {getTemplate} from './get_most_chrome_page.html.js';
@@ -20,6 +25,18 @@
   static get template() {
     return getTemplate();
   }
+
+  static get properties() {
+    return {
+      expandedMoreThanABrowser_: Boolean,
+      expandedYourDataInChrome_: Boolean,
+      expandedBeyondCookies_: Boolean,
+    };
+  }
+
+  private expandedMoreThanABrowser_: boolean;
+  private expandedYourDataInChrome_: boolean;
+  private expandedBeyondCookies_: boolean;
 }
 
 declare global {
diff --git a/chrome/browser/resources/settings/lazy_load.ts b/chrome/browser/resources/settings/lazy_load.ts
index 04d16b8..c489205 100644
--- a/chrome/browser/resources/settings/lazy_load.ts
+++ b/chrome/browser/resources/settings/lazy_load.ts
@@ -84,6 +84,11 @@
 
 // </if>
 
+// <if expr="not is_chromeos">
+export {CaptionsBrowserProxy, CaptionsBrowserProxyImpl, LiveCaptionLanguageList} from '/shared/settings/a11y_page/captions_browser_proxy.js';
+// </if>
+
+export {FontsBrowserProxy, FontsBrowserProxyImpl, FontsData} from '/shared/settings/appearance_page/fonts_browser_proxy.js';
 export {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js';
 export {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
 export {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
@@ -91,16 +96,15 @@
 export {CrSliderElement} from 'chrome://resources/cr_elements/cr_slider/cr_slider.js';
 export {CrTextareaElement} from 'chrome://resources/cr_elements/cr_textarea/cr_textarea.js';
 export {getToastManager} from 'chrome://resources/cr_elements/cr_toast/cr_toast_manager.js';
+export {IronCollapseElement} from 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js';
 export {IronListElement} from 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
 export {PaperTooltipElement} from 'chrome://resources/polymer/v3_0/paper-tooltip/paper-tooltip.js';
 // <if expr="not is_chromeos">
-export {CaptionsBrowserProxy, CaptionsBrowserProxyImpl, LiveCaptionLanguageList} from './a11y_page/captions_browser_proxy.js';
 export {SettingsLiveCaptionElement} from './a11y_page/live_caption_section.js';
 export {SettingsLiveTranslateElement} from './a11y_page/live_translate_section.js';
 // </if>
 
 export {SettingsAppearanceFontsPageElement} from './appearance_page/appearance_fonts_page.js';
-export {FontsBrowserProxy, FontsBrowserProxyImpl, FontsData} from './appearance_page/fonts_browser_proxy.js';
 export {CountryDetailManager, CountryDetailManagerImpl, SettingsAddressEditDialogElement} from './autofill_page/address_edit_dialog.js';
 export {SettingsAddressRemoveConfirmationDialogElement} from './autofill_page/address_remove_confirmation_dialog.js';
 export {AutofillManagerImpl, AutofillManagerProxy, PersonalDataChangedListener} from './autofill_page/autofill_manager_proxy.js';
diff --git a/chrome/browser/resources/settings/people_page/manage_profile.ts b/chrome/browser/resources/settings/people_page/manage_profile.ts
index e0d3946..a976560 100644
--- a/chrome/browser/resources/settings/people_page/manage_profile.ts
+++ b/chrome/browser/resources/settings/people_page/manage_profile.ts
@@ -16,6 +16,7 @@
 import '../settings_shared.css.js';
 import 'chrome://resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js';
 
+import {SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.js';
 import {AvatarIcon} from 'chrome://resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js';
 import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
@@ -27,7 +28,6 @@
 
 import {getTemplate} from './manage_profile.html.js';
 import {ManageProfileBrowserProxy, ManageProfileBrowserProxyImpl, ProfileShortcutStatus} from './manage_profile_browser_proxy.js';
-import {SyncStatus} from './sync_browser_proxy.js';
 
 const SettingsManageProfileElementBase =
     RouteObserverMixin(WebUiListenerMixin(PolymerElement));
diff --git a/chrome/browser/resources/settings/people_page/people_page.ts b/chrome/browser/resources/settings/people_page/people_page.ts
index face78cf..9352d1d 100644
--- a/chrome/browser/resources/settings/people_page/people_page.ts
+++ b/chrome/browser/resources/settings/people_page/people_page.ts
@@ -22,6 +22,8 @@
 import '../settings_page/settings_subpage.js';
 import '../settings_shared.css.js';
 
+import {ProfileInfo, ProfileInfoBrowserProxyImpl} from '/shared/settings/people_page/profile_info_browser_proxy.js';
+import {StoredAccount, SyncBrowserProxy, SyncBrowserProxyImpl, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
 // <if expr="chromeos_ash">
 import {convertImageSequenceToPng} from 'chrome://resources/ash/common/cr_picture/png.js';
 // </if>
@@ -45,8 +47,6 @@
 // </if>
 
 import {getTemplate} from './people_page.html.js';
-import {ProfileInfo, ProfileInfoBrowserProxyImpl} from './profile_info_browser_proxy.js';
-import {StoredAccount, SyncBrowserProxy, SyncBrowserProxyImpl, SyncStatus} from './sync_browser_proxy.js';
 
 export interface SettingsPeoplePageElement {
   $: {
diff --git a/chrome/browser/resources/settings/people_page/signout_dialog.ts b/chrome/browser/resources/settings/people_page/signout_dialog.ts
index 5f59cdf..7cbeb397 100644
--- a/chrome/browser/resources/settings/people_page/signout_dialog.ts
+++ b/chrome/browser/resources/settings/people_page/signout_dialog.ts
@@ -20,12 +20,12 @@
 import {WebUiListenerMixin} from '//resources/cr_elements/web_ui_listener_mixin.js';
 import {sanitizeInnerHtml} from '//resources/js/parse_html_subset.js';
 import {microTask, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {ProfileInfoBrowserProxyImpl} from '/shared/settings/people_page/profile_info_browser_proxy.js';
+import {SyncBrowserProxyImpl, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
 
 import {loadTimeData} from '../i18n_setup.js';
 
-import {ProfileInfoBrowserProxyImpl} from './profile_info_browser_proxy.js';
 import {getTemplate} from './signout_dialog.html.js';
-import {SyncBrowserProxyImpl, SyncStatus} from './sync_browser_proxy.js';
 
 export interface SettingsSignoutDialogElement {
   $: {
diff --git a/chrome/browser/resources/settings/people_page/sync_account_control.ts b/chrome/browser/resources/settings/people_page/sync_account_control.ts
index 4fce9e7..c019d48 100644
--- a/chrome/browser/resources/settings/people_page/sync_account_control.ts
+++ b/chrome/browser/resources/settings/people_page/sync_account_control.ts
@@ -13,7 +13,7 @@
 import '//resources/cr_elements/cr_shared_style.css.js';
 import '//resources/cr_elements/cr_shared_vars.css.js';
 import '//resources/polymer/v3_0/iron-icon/iron-icon.js';
-import './profile_info_browser_proxy.js';
+import '/shared/settings/people_page/profile_info_browser_proxy.js';
 import '../icons.html.js';
 import 'chrome://resources/cr_components/settings_prefs/prefs.js';
 import '../settings_shared.css.js';
@@ -22,13 +22,13 @@
 import {WebUiListenerMixin} from '//resources/cr_elements/web_ui_listener_mixin.js';
 import {assert} from '//resources/js/assert_ts.js';
 import {DomRepeatEvent, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {StatusAction, StoredAccount, SyncBrowserProxy, SyncBrowserProxyImpl, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {PrefsMixin} from 'chrome://resources/cr_components/settings_prefs/prefs_mixin.js';
 
 import {loadTimeData} from '../i18n_setup.js';
 import {Router} from '../router.js';
 
 import {getTemplate} from './sync_account_control.html.js';
-import {StatusAction, StoredAccount, SyncBrowserProxy, SyncBrowserProxyImpl, SyncStatus} from './sync_browser_proxy.js';
 
 export const MAX_SIGNIN_PROMO_IMPRESSION: number = 10;
 
diff --git a/chrome/browser/resources/settings/people_page/sync_controls.ts b/chrome/browser/resources/settings/people_page/sync_controls.ts
index b816297..6685826 100644
--- a/chrome/browser/resources/settings/people_page/sync_controls.ts
+++ b/chrome/browser/resources/settings/people_page/sync_controls.ts
@@ -12,9 +12,10 @@
 import '//resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js';
 import '../settings_shared.css.js';
 
-import {assert} from '//resources/js/assert_ts.js';
 import {WebUiListenerMixin} from '//resources/cr_elements/web_ui_listener_mixin.js';
+import {assert} from '//resources/js/assert_ts.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {StatusAction, SyncBrowserProxy, SyncBrowserProxyImpl, SyncPrefs, syncPrefsIndividualDataTypes, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
 
 // <if expr="is_chromeos">
 import {loadTimeData} from '../i18n_setup.js';
@@ -22,7 +23,6 @@
 
 import {Route, Router} from '../router.js';
 
-import {StatusAction, SyncBrowserProxy, SyncBrowserProxyImpl, SyncPrefs, syncPrefsIndividualDataTypes, SyncStatus} from './sync_browser_proxy.js';
 import {getTemplate} from './sync_controls.html.js';
 
 /**
diff --git a/chrome/browser/resources/settings/people_page/sync_encryption_options.ts b/chrome/browser/resources/settings/people_page/sync_encryption_options.ts
index befd85f..7670f40f 100644
--- a/chrome/browser/resources/settings/people_page/sync_encryption_options.ts
+++ b/chrome/browser/resources/settings/people_page/sync_encryption_options.ts
@@ -17,8 +17,8 @@
 
 import {assert} from '//resources/js/assert_ts.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {SyncBrowserProxyImpl, SyncPrefs, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
 
-import {SyncBrowserProxyImpl, SyncPrefs, SyncStatus} from './sync_browser_proxy.js';
 import {getTemplate} from './sync_encryption_options.html.js';
 
 /**
diff --git a/chrome/browser/resources/settings/people_page/sync_page.ts b/chrome/browser/resources/settings/people_page/sync_page.ts
index 2bd71cf9..69cff412 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.ts
+++ b/chrome/browser/resources/settings/people_page/sync_page.ts
@@ -31,6 +31,7 @@
 import {focusWithoutInk} from '//resources/js/focus_without_ink.js';
 import {IronCollapseElement} from '//resources/polymer/v3_0/iron-collapse/iron-collapse.js';
 import {flush, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {PageStatus, StatusAction, SyncBrowserProxy, SyncBrowserProxyImpl, SyncPrefs, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
 
 import {FocusConfig} from '../focus_config.js';
@@ -41,7 +42,6 @@
 
 import {RouteObserverMixin, Router} from '../router.js';
 
-import {PageStatus, StatusAction, SyncBrowserProxy, SyncBrowserProxyImpl, SyncPrefs, SyncStatus} from './sync_browser_proxy.js';
 // <if expr="chromeos_ash">
 import {SettingsSyncEncryptionOptionsElement} from './sync_encryption_options.js';
 // </if>
diff --git a/chrome/browser/resources/settings/privacy_page/personalization_options.ts b/chrome/browser/resources/settings/privacy_page/personalization_options.ts
index 7a189b37..77301cf2 100644
--- a/chrome/browser/resources/settings/privacy_page/personalization_options.ts
+++ b/chrome/browser/resources/settings/privacy_page/personalization_options.ts
@@ -24,17 +24,17 @@
 import {CrToastElement} from '//resources/cr_elements/cr_toast/cr_toast.js';
 import {WebUiListenerMixin} from '//resources/cr_elements/web_ui_listener_mixin.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {StatusAction, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
+import {MetricsReporting, PrivacyPageBrowserProxy, PrivacyPageBrowserProxyImpl} from '/shared/settings/privacy_page/privacy_page_browser_proxy.js';
 import {PrefsMixin} from 'chrome://resources/cr_components/settings_prefs/prefs_mixin.js';
 
 import {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js';
 import {loadTimeData} from '../i18n_setup.js';
 import {PrivacyPageVisibility} from '../page_visibility.js';
 import {SettingsSignoutDialogElement} from '../people_page/signout_dialog.js';
-import {StatusAction, SyncStatus} from '../people_page/sync_browser_proxy.js';
 import {RelaunchMixin, RestartType} from '../relaunch_mixin.js';
 
 import {getTemplate} from './personalization_options.html.js';
-import {MetricsReporting, PrivacyPageBrowserProxy, PrivacyPageBrowserProxyImpl} from './privacy_page_browser_proxy.js';
 
 
 export interface SettingsPersonalizationOptionsElement {
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_availability_mixin.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_availability_mixin.ts
index 1edab65..16a41a7 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_availability_mixin.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_availability_mixin.ts
@@ -7,11 +7,11 @@
  * Contains utilities that track whether the Privacy Guide is available.
  */
 
+import {SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {WebUiListenerMixin, WebUiListenerMixinInterface} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {dedupingMixin, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {loadTimeData} from '../../i18n_setup.js';
-import {SyncStatus} from '../../people_page/sync_browser_proxy.js';
 
 type Constructor<T> = new (...args: any[]) => T;
 
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.ts
index 9eedb0d1..d08a40a 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_history_sync_fragment.ts
@@ -13,13 +13,13 @@
 import './privacy_guide_fragment_shared.css.js';
 import '../../controls/settings_toggle_button.js';
 
+import {SyncBrowserProxy, SyncBrowserProxyImpl, SyncPrefs, syncPrefsIndividualDataTypes} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {BaseMixin} from '../../base_mixin.js';
 import {SettingsToggleButtonElement} from '../../controls/settings_toggle_button.js';
 import {MetricsBrowserProxy, MetricsBrowserProxyImpl, PrivacyGuideSettingsStates, PrivacyGuideStepsEligibleAndReached} from '../../metrics_browser_proxy.js';
-import {SyncBrowserProxy, SyncBrowserProxyImpl, SyncPrefs, syncPrefsIndividualDataTypes} from '../../people_page/sync_browser_proxy.js';
 import {routes} from '../../route.js';
 import {Route, RouteObserverMixin, Router} from '../../router.js';
 
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.ts
index 33110ae..43a2f14 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.ts
@@ -20,6 +20,7 @@
 import './privacy_guide_welcome_fragment.js';
 import './step_indicator.js';
 
+import {SyncBrowserProxy, SyncBrowserProxyImpl, SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
 import {PrefsMixin} from 'chrome://resources/cr_components/settings_prefs/prefs_mixin.js';
 import {CrSettingsPrefs} from 'chrome://resources/cr_components/settings_prefs/prefs_types.js';
 import {CrViewManagerElement} from 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.js';
@@ -31,7 +32,6 @@
 import {HatsBrowserProxyImpl, TrustSafetyInteraction} from '../../hats_browser_proxy.js';
 import {loadTimeData} from '../../i18n_setup.js';
 import {MetricsBrowserProxy, MetricsBrowserProxyImpl, PrivacyGuideInteractions, PrivacyGuideStepsEligibleAndReached} from '../../metrics_browser_proxy.js';
-import {SyncBrowserProxy, SyncBrowserProxyImpl, SyncStatus} from '../../people_page/sync_browser_proxy.js';
 import {SafeBrowsingSetting} from '../../privacy_page/security_page.js';
 import {routes} from '../../route.js';
 import {Route, RouteObserverMixin, Router} from '../../router.js';
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.ts b/chrome/browser/resources/settings/privacy_page/privacy_page.ts
index fce931b..9d1041d 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.ts
@@ -20,6 +20,7 @@
 import '../site_settings/settings_category_default_radio_group.js';
 import './privacy_guide/privacy_guide_dialog.js';
 
+import {PrivacyPageBrowserProxy, PrivacyPageBrowserProxyImpl} from '/shared/settings/privacy_page/privacy_page_browser_proxy.js';
 import {PrefsMixin} from 'chrome://resources/cr_components/settings_prefs/prefs_mixin.js';
 import {CrLinkRowElement} from 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
@@ -41,7 +42,6 @@
 
 import {PrivacyGuideAvailabilityMixin} from './privacy_guide/privacy_guide_availability_mixin.js';
 import {getTemplate} from './privacy_page.html.js';
-import {PrivacyPageBrowserProxy, PrivacyPageBrowserProxyImpl} from './privacy_page_browser_proxy.js';
 
 interface BlockAutoplayStatus {
   enabled: boolean;
diff --git a/chrome/browser/resources/settings/privacy_page/secure_dns.ts b/chrome/browser/resources/settings/privacy_page/secure_dns.ts
index 68d157a7..da0bd60 100644
--- a/chrome/browser/resources/settings/privacy_page/secure_dns.ts
+++ b/chrome/browser/resources/settings/privacy_page/secure_dns.ts
@@ -20,19 +20,20 @@
 import 'chrome://resources/cr_components/settings_prefs/prefs.js';
 import '../controls/settings_toggle_button.js';
 import '../settings_shared.css.js';
+import '../strings.m.js';
 import './secure_dns_input.js';
 
+import {PrivacyPageBrowserProxy, PrivacyPageBrowserProxyImpl, ResolverOption, SecureDnsMode, SecureDnsSetting, SecureDnsUiManagementMode} from '/shared/settings/privacy_page/privacy_page_browser_proxy.js';
 import {PrefsMixin} from 'chrome://resources/cr_components/settings_prefs/prefs_mixin.js';
 import {CrRadioGroupElement} from 'chrome://resources/cr_elements/cr_radio_group/cr_radio_group.js';
 import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {assertNotReached} from 'chrome://resources/js/assert_ts.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {sanitizeInnerHtml} from 'chrome://resources/js/parse_html_subset.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js';
-import {loadTimeData} from '../i18n_setup.js';
 
-import {PrivacyPageBrowserProxy, PrivacyPageBrowserProxyImpl, ResolverOption, SecureDnsMode, SecureDnsSetting, SecureDnsUiManagementMode} from './privacy_page_browser_proxy.js';
 import {getTemplate} from './secure_dns.html.js';
 import {SecureDnsInputElement} from './secure_dns_input.js';
 
diff --git a/chrome/browser/resources/settings/privacy_page/secure_dns_input.ts b/chrome/browser/resources/settings/privacy_page/secure_dns_input.ts
index b675e65..44c4928 100644
--- a/chrome/browser/resources/settings/privacy_page/secure_dns_input.ts
+++ b/chrome/browser/resources/settings/privacy_page/secure_dns_input.ts
@@ -10,15 +10,15 @@
 import 'chrome://resources/cr_elements/cr_textarea/cr_textarea.js';
 // <if expr="chromeos_ash">
 import 'chrome://resources/cr_elements/chromeos/cros_color_overrides.css.js';
-
 // </if>
 
+import '../strings.m.js';
+
+import {PrivacyPageBrowserProxy, PrivacyPageBrowserProxyImpl} from '/shared/settings/privacy_page/privacy_page_browser_proxy.js';
 import {CrTextareaElement} from 'chrome://resources/cr_elements/cr_textarea/cr_textarea.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {loadTimeData} from '../i18n_setup.js';
-
-import {PrivacyPageBrowserProxy, PrivacyPageBrowserProxyImpl} from './privacy_page_browser_proxy.js';
 import {getTemplate} from './secure_dns_input.html.js';
 
 export interface SecureDnsInputElement {
diff --git a/chrome/browser/resources/settings/privacy_page/security_page.ts b/chrome/browser/resources/settings/privacy_page/security_page.ts
index 10b9eba4..e8eefff 100644
--- a/chrome/browser/resources/settings/privacy_page/security_page.ts
+++ b/chrome/browser/resources/settings/privacy_page/security_page.ts
@@ -14,17 +14,19 @@
 import '../settings_shared.css.js';
 import '../simple_confirmation_dialog.js';
 
+import {PrivacyPageBrowserProxy, PrivacyPageBrowserProxyImpl} from '/shared/settings/privacy_page/privacy_page_browser_proxy.js';
 import {HelpBubbleMixin} from 'chrome://resources/cr_components/help_bubble/help_bubble_mixin.js';
 import {PrefsMixin} from 'chrome://resources/cr_components/settings_prefs/prefs_mixin.js';
 import {CrSettingsPrefs} from 'chrome://resources/cr_components/settings_prefs/prefs_types.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {assert} from 'chrome://resources/js/assert_ts.js';
 import {focusWithoutInk} from 'chrome://resources/js/focus_without_ink.js';
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 // <if expr="is_chromeos or chrome_root_store_supported">
 import {OpenWindowProxyImpl} from 'chrome://resources/js/open_window_proxy.js';
 // </if>
 
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
 import {SettingsRadioGroupElement} from '../controls/settings_radio_group.js';
 import {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js';
 import {FocusConfig} from '../focus_config.js';
@@ -34,7 +36,6 @@
 import {Route, RouteObserverMixin, Router} from '../router.js';
 
 import {SettingsCollapseRadioButtonElement} from './collapse_radio_button.js';
-import {PrivacyPageBrowserProxy, PrivacyPageBrowserProxyImpl} from './privacy_page_browser_proxy.js';
 import {getTemplate} from './security_page.html.js';
 
 /**
diff --git a/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.ts b/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.ts
index 66e839d1..4072f67 100644
--- a/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.ts
+++ b/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.ts
@@ -12,13 +12,12 @@
 import '../settings_shared.css.js';
 import '../site_favicon.js';
 
+import {ExtensionControlBrowserProxy, ExtensionControlBrowserProxyImpl} from '/shared/settings/extension_control_browser_proxy.js';
 import {AnchorAlignment} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js';
 import {FocusRowMixin} from 'chrome://resources/cr_elements/focus_row_mixin.js';
 import {assert} from 'chrome://resources/js/assert_ts.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {ExtensionControlBrowserProxy, ExtensionControlBrowserProxyImpl} from '../extension_control_browser_proxy.js';
-
 import {getTemplate} from './omnibox_extension_entry.html.js';
 import {SearchEngine} from './search_engines_browser_proxy.js';
 
diff --git a/chrome/browser/resources/settings/settings.ts b/chrome/browser/resources/settings/settings.ts
index a2d70ab1..ffcf67b 100644
--- a/chrome/browser/resources/settings/settings.ts
+++ b/chrome/browser/resources/settings/settings.ts
@@ -4,7 +4,11 @@
 
 import './settings_ui/settings_ui.js';
 
+export {ExtensionControlBrowserProxy, ExtensionControlBrowserProxyImpl} from '/shared/settings/extension_control_browser_proxy.js';
 export {LifetimeBrowserProxy, LifetimeBrowserProxyImpl} from '/shared/settings/lifetime_browser_proxy.js';
+export {ProfileInfo, ProfileInfoBrowserProxy, ProfileInfoBrowserProxyImpl} from '/shared/settings/people_page/profile_info_browser_proxy.js';
+export {PageStatus, StatusAction, StoredAccount, SyncBrowserProxy, SyncBrowserProxyImpl, SyncPrefs, syncPrefsIndividualDataTypes, SyncStatus, TrustedVaultBannerState} from '/shared/settings/people_page/sync_browser_proxy.js';
+export {MetricsReporting, PrivacyPageBrowserProxy, PrivacyPageBrowserProxyImpl, ResolverOption, SecureDnsMode, SecureDnsSetting, SecureDnsUiManagementMode} from '/shared/settings/privacy_page/privacy_page_browser_proxy.js';
 export {prefToString, stringToPrefValue} from 'chrome://resources/cr_components/settings_prefs/pref_util.js';
 export {SettingsPrefsElement} from 'chrome://resources/cr_components/settings_prefs/prefs.js';
 export {PrefsMixin, PrefsMixinInterface} from 'chrome://resources/cr_components/settings_prefs/prefs_mixin.js';
@@ -22,10 +26,13 @@
 export {PluralStringProxyImpl as SettingsPluralStringProxyImpl} from 'chrome://resources/js/plural_string_proxy.js';
 export {getTrustedHTML} from 'chrome://resources/js/static_types.js';
 export {SettingsAboutPageElement} from './about_page/about_page.js';
+// clang-format off
 export {AboutPageBrowserProxy, AboutPageBrowserProxyImpl, UpdateStatus} from './about_page/about_page_browser_proxy.js';
 // <if expr="_google_chrome and is_macosx">
 export {PromoteUpdaterStatus} from './about_page/about_page_browser_proxy.js';
 // </if>
+// clang-format on
+
 export {AppearanceBrowserProxy, AppearanceBrowserProxyImpl} from './appearance_page/appearance_browser_proxy.js';
 export {SettingsAppearancePageElement, SystemTheme} from './appearance_page/appearance_page.js';
 export {HomeUrlInputElement} from './appearance_page/home_url_input.js';
@@ -43,7 +50,6 @@
 export {DefaultBrowserBrowserProxy, DefaultBrowserBrowserProxyImpl, DefaultBrowserInfo} from './default_browser_page/default_browser_browser_proxy.js';
 export {SettingsDefaultBrowserPageElement} from './default_browser_page/default_browser_page.js';
 // </if>
-export {ExtensionControlBrowserProxy, ExtensionControlBrowserProxyImpl} from './extension_control_browser_proxy.js';
 export {HatsBrowserProxy, HatsBrowserProxyImpl, TrustSafetyInteraction} from './hats_browser_proxy.js';
 export {loadTimeData} from './i18n_setup.js';
 export {MetricsBrowserProxy, MetricsBrowserProxyImpl, PrivacyElementInteractions, PrivacyGuideInteractions, PrivacyGuideSettingsStates, PrivacyGuideStepsEligibleAndReached, SafeBrowsingInteractions, SafetyCheckInteractions, SafetyCheckNotificationsModuleInteractions, SafetyCheckUnusedSitePermissionsModuleInteractions} from './metrics_browser_proxy.js';
@@ -58,9 +64,7 @@
 export {AccountManagerBrowserProxy, AccountManagerBrowserProxyImpl} from './people_page/account_manager_browser_proxy.js';
 // </if>
 export {SettingsPeoplePageElement} from './people_page/people_page.js';
-export {ProfileInfo, ProfileInfoBrowserProxy, ProfileInfoBrowserProxyImpl} from './people_page/profile_info_browser_proxy.js';
 export {MAX_SIGNIN_PROMO_IMPRESSION, SettingsSyncAccountControlElement} from './people_page/sync_account_control.js';
-export {PageStatus, StatusAction, StoredAccount, SyncBrowserProxy, SyncBrowserProxyImpl, SyncPrefs, syncPrefsIndividualDataTypes, SyncStatus, TrustedVaultBannerState} from './people_page/sync_browser_proxy.js';
 export {BATTERY_SAVER_MODE_PREF, SettingsBatteryPageElement} from './performance_page/battery_page.js';
 export {PerformanceBrowserProxy, PerformanceBrowserProxyImpl} from './performance_page/performance_browser_proxy.js';
 export {BatterySaverModeState, HighEfficiencyModeExceptionListAction, PerformanceMetricsProxy, PerformanceMetricsProxyImpl} from './performance_page/performance_metrics_proxy.js';
@@ -70,7 +74,6 @@
 export {TAB_DISCARD_EXCEPTIONS_OVERFLOW_SIZE, TabDiscardExceptionListElement} from './performance_page/tab_discard_exception_list.js';
 export {PrivacyGuideBrowserProxy, PrivacyGuideBrowserProxyImpl} from './privacy_page/privacy_guide/privacy_guide_browser_proxy.js';
 export {SettingsPrivacyPageElement} from './privacy_page/privacy_page.js';
-export {MetricsReporting, PrivacyPageBrowserProxy, PrivacyPageBrowserProxyImpl, ResolverOption, SecureDnsMode, SecureDnsSetting, SecureDnsUiManagementMode} from './privacy_page/privacy_page_browser_proxy.js';
 export {CanonicalTopic, FledgeState, PrivacySandboxBrowserProxy, PrivacySandboxBrowserProxyImpl, PrivacySandboxInterest, TopicsState} from './privacy_page/privacy_sandbox/privacy_sandbox_browser_proxy.js';
 export {RelaunchMixin, RestartType} from './relaunch_mixin.js';
 export {ResetBrowserProxy, ResetBrowserProxyImpl} from './reset_page/reset_browser_proxy.js';
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.ts b/chrome/browser/resources/settings/settings_menu/settings_menu.ts
index 73d14937..d8f1eae 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.ts
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.ts
@@ -81,6 +81,16 @@
       }
     }
 
+    // <if expr="_google_chrome">
+    if (newRoute === routes.GET_MOST_CHROME) {
+      const about =
+          this.shadowRoot!.querySelector<HTMLAnchorElement>('#about-menu');
+      assert(about);
+      this.setSelectedUrl_(about.href);
+      return;
+    }
+    // </if>
+
     // Focus the initially selected path.
     const anchors = this.shadowRoot!.querySelectorAll('a');
     for (let i = 0; i < anchors.length; ++i) {
diff --git a/chrome/browser/resources/settings_shared/BUILD.gn b/chrome/browser/resources/settings_shared/BUILD.gn
index c828b177..ce57d24 100644
--- a/chrome/browser/resources/settings_shared/BUILD.gn
+++ b/chrome/browser/resources/settings_shared/BUILD.gn
@@ -10,9 +10,20 @@
   grd_prefix = "settings_shared"
   grd_resource_path_prefix = "shared/settings"
 
-  non_web_component_files = [ "lifetime_browser_proxy.ts" ]
+  non_web_component_files = [
+    "a11y_page/captions_browser_proxy.ts",
+    "appearance_page/fonts_browser_proxy.ts",
+    "extension_control_browser_proxy.ts",
+    "lifetime_browser_proxy.ts",
+    "people_page/profile_info_browser_proxy.ts",
+    "people_page/sync_browser_proxy.ts",
+    "privacy_page/privacy_page_browser_proxy.ts",
+  ]
 
   ts_composite = true
-  ts_definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ]
+  ts_definitions = [
+    "//tools/typescript/definitions/chrome_send.d.ts",
+    "//tools/typescript/definitions/metrics_private.d.ts",
+  ]
   ts_deps = [ "//ui/webui/resources/js:build_ts" ]
 }
diff --git a/chrome/browser/resources/settings/a11y_page/captions_browser_proxy.ts b/chrome/browser/resources/settings_shared/a11y_page/captions_browser_proxy.ts
similarity index 100%
rename from chrome/browser/resources/settings/a11y_page/captions_browser_proxy.ts
rename to chrome/browser/resources/settings_shared/a11y_page/captions_browser_proxy.ts
diff --git a/chrome/browser/resources/settings/appearance_page/fonts_browser_proxy.ts b/chrome/browser/resources/settings_shared/appearance_page/fonts_browser_proxy.ts
similarity index 100%
rename from chrome/browser/resources/settings/appearance_page/fonts_browser_proxy.ts
rename to chrome/browser/resources/settings_shared/appearance_page/fonts_browser_proxy.ts
diff --git a/chrome/browser/resources/settings/extension_control_browser_proxy.ts b/chrome/browser/resources/settings_shared/extension_control_browser_proxy.ts
similarity index 100%
rename from chrome/browser/resources/settings/extension_control_browser_proxy.ts
rename to chrome/browser/resources/settings_shared/extension_control_browser_proxy.ts
diff --git a/chrome/browser/resources/settings/people_page/profile_info_browser_proxy.ts b/chrome/browser/resources/settings_shared/people_page/profile_info_browser_proxy.ts
similarity index 100%
rename from chrome/browser/resources/settings/people_page/profile_info_browser_proxy.ts
rename to chrome/browser/resources/settings_shared/people_page/profile_info_browser_proxy.ts
diff --git a/chrome/browser/resources/settings/people_page/sync_browser_proxy.ts b/chrome/browser/resources/settings_shared/people_page/sync_browser_proxy.ts
similarity index 100%
rename from chrome/browser/resources/settings/people_page/sync_browser_proxy.ts
rename to chrome/browser/resources/settings_shared/people_page/sync_browser_proxy.ts
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.ts b/chrome/browser/resources/settings_shared/privacy_page/privacy_page_browser_proxy.ts
similarity index 100%
rename from chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.ts
rename to chrome/browser/resources/settings_shared/privacy_page/privacy_page_browser_proxy.ts
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_edit_dialog.html b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_edit_dialog.html
index 62efb9d2..358faaec 100644
--- a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_edit_dialog.html
+++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_edit_dialog.html
@@ -30,7 +30,25 @@
   }
 
   .folder-row[selected] {
-    background-color: var(--cr-active-background-color);
+    background-color: var(--google-blue-50);
+  }
+
+  @media (prefers-color-scheme: dark) {
+    .folder-row[selected] {
+      background-color: var(--google-blue-300);
+    }
+
+    .folder-row[selected] > .cr-icon {
+      background-color: var(--google-grey-900);
+    }
+
+    .folder-row[selected] > .folder-title {
+      color: var(--google-grey-900);
+    }
+
+    .folder-row[selected] > .subpage-arrow {
+      --cr-icon-button-fill-color: var(--google-grey-900);
+    }
   }
 
   .folder-selector {
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
index cbe1075..b473bbe 100644
--- a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
+++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
@@ -49,6 +49,9 @@
 import {editingDisabledByPolicy, Label, PowerBookmarksService} from './power_bookmarks_service.js';
 import {BookmarkProductInfo} from './shopping_list.mojom-webui.js';
 
+const ADD_FOLDER_ACTION_UMA = 'Bookmarks.FolderAddedFromSidePanel';
+const ADD_URL_ACTION_UMA = 'Bookmarks.AddedFromSidePanel';
+
 function getBookmarkName(bookmark: chrome.bookmarks.BookmarkTreeNode): string {
   return bookmark.title || bookmark.url || '';
 }
@@ -635,6 +638,7 @@
     event.stopPropagation();
     let parentId = event.detail.folderId;
     for (const folder of event.detail.newFolders) {
+      chrome.metricsPrivate.recordUserAction(ADD_FOLDER_ACTION_UMA);
       const newFolder =
           await this.bookmarksApi_.createFolder(folder.parentId!, folder.title);
       folder.children!.forEach(child => child.parentId = newFolder.id);
@@ -776,6 +780,7 @@
       this.showDisabledFeatureDialog_();
       return;
     }
+    chrome.metricsPrivate.recordUserAction(ADD_FOLDER_ACTION_UMA);
     this.bookmarksApi_
         .createFolder(newParent.id, loadTimeData.getString('newFolderTitle'))
         .then((newFolder) => {
@@ -915,6 +920,7 @@
       this.showDisabledFeatureDialog_();
       return;
     }
+    chrome.metricsPrivate.recordUserAction(ADD_URL_ACTION_UMA);
     this.bookmarksApi_.bookmarkCurrentTabInFolder(newParent.id);
   }
 
diff --git a/chrome/browser/resources/side_panel/customize_chrome/appearance.html b/chrome/browser/resources/side_panel/customize_chrome/appearance.html
index f104756d..0463155 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/appearance.html
+++ b/chrome/browser/resources/side_panel/customize_chrome/appearance.html
@@ -13,11 +13,15 @@
     --cr-icon-image: url(icons/image.svg);
     --cr-icon-size: 12px;
     height: 12px;
-    margin-inline-end: 8px;
+    margin-inline-end: 0;
     margin-inline-start: 0;
     width: 12px;
   }
 
+  :host-context([chrome-refresh-2023]) #imageIcon {
+    --cr-icon-color: currentColor;
+  }
+
   #setClassicChromeButton {
     --cr-icon-image: url(icons/reset.svg);
   }
@@ -39,8 +43,8 @@
     label-description="$i18n{currentTheme}">
 </customize-chrome-hover-button>
 <cr-button id="editThemeButton" on-click="onEditThemeClicked_"
-    class="action-button">
-  <div id="imageIcon" class="cr-icon"></div>
+    class$="[[themeButtonClass_]]">
+  <div id="imageIcon" class="cr-icon" slot="prefix-icon"></div>
   $i18n{changeTheme}
 </cr-button>
 <customize-chrome-colors id="chromeColors"
diff --git a/chrome/browser/resources/side_panel/customize_chrome/appearance.ts b/chrome/browser/resources/side_panel/customize_chrome/appearance.ts
index fa8106e..1d038d35 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/appearance.ts
+++ b/chrome/browser/resources/side_panel/customize_chrome/appearance.ts
@@ -39,6 +39,7 @@
   static get properties() {
     return {
       theme_: Object,
+      themeButtonClass_: String,
 
       thirdPartyThemeId_: {
         type: String,
@@ -71,6 +72,7 @@
   }
 
   private theme_: Theme|undefined = undefined;
+  private themeButtonClass_: string;
   private thirdPartyThemeId_: string|null = null;
   private thirdPartyThemeName_: string|null = null;
   private showClassicChromeButton_: boolean;
@@ -90,6 +92,10 @@
 
   override connectedCallback() {
     super.connectedCallback();
+    this.themeButtonClass_ =
+        document.documentElement.hasAttribute('chrome-refresh-2023') ?
+        'floating-button' :
+        'action-button';
     this.setThemeListenerId_ =
         this.callbackRouter_.setTheme.addListener((theme: Theme) => {
           this.theme_ = theme;
diff --git a/chrome/browser/share/android/java/res/values/dimens.xml b/chrome/browser/share/android/java/res/values/dimens.xml
index 658d69f70..926da784 100644
--- a/chrome/browser/share/android/java/res/values/dimens.xml
+++ b/chrome/browser/share/android/java/res/values/dimens.xml
@@ -25,5 +25,5 @@
     <dimen name="toggle_iph_y_inset">8dp</dimen>
 
     <!-- Android share sheet -->
-    <dimen name="share_preview_favicon_size">32dp</dimen>
+    <dimen name="share_preview_favicon_size">48dp</dimen>
 </resources>
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java
index b1b9954..f7b71203 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java
@@ -207,7 +207,8 @@
             Context context, Bitmap bitmap, int size, Callback<Uri> onImageUriAvailable) {
         // If bitmap is not provided, fallback to the globe placeholder icon.
         if (bitmap == null) {
-            bitmap = FaviconUtils.createGenericFaviconBitmap(context, size);
+            bitmap = FaviconUtils.createGenericFaviconBitmap(
+                    context, size, context.getColor(R.color.modern_white));
         }
         String fileName = String.valueOf(System.currentTimeMillis());
         ShareImageFileUtils.generateTemporaryUriFromBitmap(fileName, bitmap, onImageUriAvailable);
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContent.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContent.java
index 8392cb47..ff95698 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContent.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContent.java
@@ -525,7 +525,7 @@
         // If we didn't get a favicon, use the generic favicon instead.
         Bitmap scaledIcon;
         if (icon == null) {
-            scaledIcon = FaviconUtils.createGenericFaviconBitmap(mActivity, size);
+            scaledIcon = FaviconUtils.createGenericFaviconBitmap(mActivity, size, null);
             RecordUserAction.record("SharingHubAndroid.GenericFaviconShown");
         } else {
             scaledIcon = Bitmap.createScaledBitmap(icon, size, size, true);
diff --git a/chrome/browser/tab/BUILD.gn b/chrome/browser/tab/BUILD.gn
index 6b70279b..22b5fa7 100644
--- a/chrome/browser/tab/BUILD.gn
+++ b/chrome/browser/tab/BUILD.gn
@@ -75,6 +75,7 @@
     "//build/android:build_java",
     "//chrome/browser/android/crypto:java",
     "//chrome/browser/commerce/android:java",
+    "//chrome/browser/commerce/price_tracking/android:java",
     "//chrome/browser/contextmenu:java",
     "//chrome/browser/endpoint_fetcher:java",
     "//chrome/browser/flags:java",
@@ -85,6 +86,7 @@
     "//chrome/browser/ui/android/strings:ui_strings_grd",
     "//components/browser_ui/util/android:java",
     "//components/commerce/core:proto_java",
+    "//components/commerce/core/android:core_java",
     "//components/embedder_support/android:content_view_java",
     "//components/embedder_support/android:util_java",
     "//components/embedder_support/android:web_contents_delegate_java",
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/DEPS b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/DEPS
index 8bab404..26c1040c 100644
--- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/DEPS
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/DEPS
@@ -7,6 +7,7 @@
   "+build/android/java/src/org/chromium/build",
   "+chrome/browser/android/crypto/java",
   '+chrome/browser/commerce/android/java',
+  '+chrome/browser/commerce/price_tracking/android/java',
   "+chrome/browser/contextmenu/java",
   "+chrome/browser/endpoint_fetcher",
   "+chrome/browser/tab/java",
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java
index 2d1a0bd..605c312 100644
--- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java
@@ -22,6 +22,7 @@
 import org.chromium.chrome.browser.commerce.PriceUtils;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridgeFactory;
+import org.chromium.chrome.browser.price_tracking.PriceTrackingFeatures;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.proto.ShoppingPersistedTabData.ShoppingPersistedTabDataProto;
@@ -1029,9 +1030,10 @@
         if (FeatureList.isInitialized()) {
             return ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
                     ChromeFeatureList.COMMERCE_PRICE_TRACKING,
-                    PRICE_TRACKING_WITH_OPTIMIZATION_GUIDE_PARAM, false);
+                    PRICE_TRACKING_WITH_OPTIMIZATION_GUIDE_PARAM,
+                    PriceTrackingFeatures.isPriceTrackingEnabled());
         }
-        return false;
+        return PriceTrackingFeatures.isPriceTrackingEnabled();
     }
 
     /**
diff --git a/chrome/browser/taskbar/taskbar_decorator_win.cc b/chrome/browser/taskbar/taskbar_decorator_win.cc
index 3410749..b111a00 100644
--- a/chrome/browser/taskbar/taskbar_decorator_win.cc
+++ b/chrome/browser/taskbar/taskbar_decorator_win.cc
@@ -32,7 +32,6 @@
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkFont.h"
 #include "third_party/skia/include/core/SkImage.h"
-#include "third_party/skia/include/core/SkImageEncoder.h"
 #include "third_party/skia/include/core/SkImageInfo.h"
 #include "third_party/skia/include/core/SkRRect.h"
 #include "third_party/skia/include/core/SkStream.h"
diff --git a/chrome/browser/thumbnail/cc/etc1_thumbnail_helper.cc b/chrome/browser/thumbnail/cc/etc1_thumbnail_helper.cc
index e29fc44..7b8c7a22 100644
--- a/chrome/browser/thumbnail/cc/etc1_thumbnail_helper.cc
+++ b/chrome/browser/thumbnail/cc/etc1_thumbnail_helper.cc
@@ -259,8 +259,8 @@
 
   if (!raw_data.empty()) {
     gfx::Size raw_data_size(raw_data.width(), raw_data.height());
-    size_t pixel_size = 4;  // Pixel size is 4 bytes for kARGB_8888_Config.
-    size_t stride = pixel_size * raw_data_size.width();
+    constexpr size_t kPixelSize = 4;  // For kARGB_8888_Config.
+    size_t stride = kPixelSize * raw_data_size.width();
 
     size_t encoded_bytes =
         etc1_get_encoded_data_size(encoded_size.width(), encoded_size.height());
@@ -273,7 +273,7 @@
 
     bool success = etc1_encode_image(
         reinterpret_cast<unsigned char*>(raw_data.getPixels()),
-        raw_data_size.width(), raw_data_size.height(), pixel_size, stride,
+        raw_data_size.width(), raw_data_size.height(), kPixelSize, stride,
         reinterpret_cast<unsigned char*>(etc1_pixel_ref->pixels()),
         encoded_size.width(), encoded_size.height());
     etc1_pixel_ref->setImmutable();
diff --git a/chrome/browser/thumbnail/cc/jpeg_thumbnail_helper.cc b/chrome/browser/thumbnail/cc/jpeg_thumbnail_helper.cc
index d4fdec0..065ca53 100644
--- a/chrome/browser/thumbnail/cc/jpeg_thumbnail_helper.cc
+++ b/chrome/browser/thumbnail/cc/jpeg_thumbnail_helper.cc
@@ -6,7 +6,9 @@
 
 #include <algorithm>
 
+#include "base/cxx17_backports.h"
 #include "base/files/file_util.h"
+#include "base/functional/bind.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/sequenced_task_runner.h"
@@ -16,10 +18,8 @@
 
 namespace thumbnail {
 namespace {
-void CompressTask(
-    double jpeg_aspect_ratio,
-    const SkBitmap& bitmap,
-    base::OnceCallback<void(std::vector<uint8_t>)> post_processing_task) {
+
+SkBitmap ResizeBitmap(double jpeg_aspect_ratio, const SkBitmap& bitmap) {
   // We want to show thumbnails in a specific aspect ratio. Therefore, the
   // thumbnail saved needs to be cropped to the target aspect ratio, otherwise
   // it would be vertically center-aligned and the top would be hidden in
@@ -37,14 +37,21 @@
   int end_x = begin_x + width;
   SkIRect dest_subset = {begin_x, 0, end_x, height};
 
-  SkBitmap result_bitmap = skia::ImageOperations::Resize(
+  SkBitmap output = skia::ImageOperations::Resize(
       bitmap, skia::ImageOperations::RESIZE_BETTER, bitmap.width() / kScale,
       bitmap.height() / kScale, dest_subset);
+  output.setImmutable();
+  return output;
+}
 
+void CompressTask(
+    double jpeg_aspect_ratio,
+    const SkBitmap& bitmap,
+    base::OnceCallback<void(std::vector<uint8_t>)> post_processing_task) {
   constexpr int kCompressionQuality = 97;
   std::vector<uint8_t> data;
-  const bool result =
-      gfx::JPEGCodec::Encode(result_bitmap, kCompressionQuality, &data);
+  const bool result = gfx::JPEGCodec::Encode(
+      ResizeBitmap(jpeg_aspect_ratio, bitmap), kCompressionQuality, &data);
   DCHECK(result);
 
   std::move(post_processing_task).Run(std::move(data));
diff --git a/chrome/browser/thumbnail/cc/jpeg_thumbnail_helper.h b/chrome/browser/thumbnail/cc/jpeg_thumbnail_helper.h
index e219523..f0153113 100644
--- a/chrome/browser/thumbnail/cc/jpeg_thumbnail_helper.h
+++ b/chrome/browser/thumbnail/cc/jpeg_thumbnail_helper.h
@@ -6,7 +6,8 @@
 #define CHROME_BROWSER_THUMBNAIL_CC_JPEG_THUMBNAIL_HELPER_H_
 
 #include "base/files/file_path.h"
-#include "base/memory/weak_ptr.h"
+#include "base/functional/callback_forward.h"
+#include "base/task/task_runner.h"
 #include "chrome/browser/thumbnail/cc/thumbnail.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -35,6 +36,7 @@
   void Write(thumbnail::TabId tab_id,
              std::vector<uint8_t> compressed_data,
              base::OnceClosure post_write_task);
+
   // `post_read_task` will run on the thread that created this
   // JpegThumbnailHelper.
   void Read(thumbnail::TabId tab_id,
diff --git a/chrome/browser/thumbnail/cc/jpeg_thumbnail_helper_unittest.cc b/chrome/browser/thumbnail/cc/jpeg_thumbnail_helper_unittest.cc
index 4dd0b13..1dfa07c8 100644
--- a/chrome/browser/thumbnail/cc/jpeg_thumbnail_helper_unittest.cc
+++ b/chrome/browser/thumbnail/cc/jpeg_thumbnail_helper_unittest.cc
@@ -11,11 +11,12 @@
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/functional/bind.h"
 #include "base/run_loop.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
+#include "base/test/task_environment.h"
 #include "chrome/browser/thumbnail/cc/thumbnail.h"
-#include "content/public/test/browser_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -30,13 +31,26 @@
 namespace thumbnail {
 namespace {
 
+constexpr double kJpegImageRatio = 0.85;
 constexpr int kDimension = 16;
 constexpr int kKiB = 1024;
 
+SkPaint SetupPaint() {
+  SkColor colors[] = {SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE};
+  SkScalar pos[] = {0, SK_Scalar1 / 2, SK_Scalar1};
+  SkPaint paint;
+  paint.setShader(SkGradientShader::MakeSweep(256, 256, colors, pos, 3));
+  return paint;
+}
+
 }  // anonymous namespace
 
 class JpegThumbnailHelperTest : public ::testing::Test {
  protected:
+  JpegThumbnailHelperTest()
+      : task_environment_(
+            base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED) {}
+
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     interface_ = std::make_unique<thumbnail::JpegThumbnailHelper>(
@@ -47,12 +61,11 @@
   void TearDown() override {}
 
   thumbnail::JpegThumbnailHelper& GetInterface() { return *interface_; }
-  SkPaint SetupPaint();
   base::FilePath GetFile(int tab_id) {
     return interface_->GetJpegFilePath(tab_id);
   }
 
-  content::BrowserTaskEnvironment task_environment_;
+  base::test::TaskEnvironment task_environment_;
 
  private:
   std::unique_ptr<thumbnail::JpegThumbnailHelper> interface_;
@@ -79,7 +92,8 @@
         EXPECT_GT(bitmap->height(), 0);
       }).Then(loop1.QuitClosure());
 
-  GetInterface().Compress(0, image, std::move(once));
+  GetInterface().Compress(kJpegImageRatio, image, std::move(once));
+  task_environment_.RunUntilIdle();
   loop1.Run();
 }
 
@@ -100,6 +114,7 @@
   // Write the image
   base::RunLoop loop1;
   GetInterface().Write(tab_id, data, loop1.QuitClosure());
+  task_environment_.RunUntilIdle();
   loop1.Run();
 
   base::FilePath file_path = GetFile(tab_id);
@@ -146,6 +161,7 @@
       }).Then(loop1.QuitClosure());
 
   GetInterface().Read(tab_id, std::move(once));
+  task_environment_.RunUntilIdle();
   loop1.Run();
 }
 
@@ -178,12 +194,4 @@
   EXPECT_FALSE(base::PathExists(post_delete_file_path));
 }
 
-SkPaint JpegThumbnailHelperTest::SetupPaint() {
-  SkColor colors[] = {SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE};
-  SkScalar pos[] = {0, SK_Scalar1 / 2, SK_Scalar1};
-  SkPaint paint;
-  paint.setShader(SkGradientShader::MakeSweep(256, 256, colors, pos, 3));
-  return paint;
-}
-
 }  // namespace thumbnail
diff --git a/chrome/browser/thumbnail/cc/thumbnail_cache.cc b/chrome/browser/thumbnail/cc/thumbnail_cache.cc
index 6a1b602..748d720 100644
--- a/chrome/browser/thumbnail/cc/thumbnail_cache.cc
+++ b/chrome/browser/thumbnail/cc/thumbnail_cache.cc
@@ -109,10 +109,12 @@
                                bool use_approximation_thumbnail,
                                bool save_jpeg_thumbnails,
                                double jpeg_aspect_ratio)
-    : file_sequenced_task_runner_(
+    : etc1_file_sequenced_task_runner_(
           base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})),
-      etc1_helper_(GetCacheDirectory(), file_sequenced_task_runner_),
-      jpeg_helper_(GetCacheDirectory(), file_sequenced_task_runner_),
+      jpeg_file_sequenced_task_runner_(
+          base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})),
+      etc1_helper_(GetCacheDirectory(), etc1_file_sequenced_task_runner_),
+      jpeg_helper_(GetCacheDirectory(), jpeg_file_sequenced_task_runner_),
       compression_queue_max_size_(compression_queue_max_size),
       write_queue_max_size_(write_queue_max_size),
       use_approximation_thumbnail_(use_approximation_thumbnail),
diff --git a/chrome/browser/thumbnail/cc/thumbnail_cache.h b/chrome/browser/thumbnail/cc/thumbnail_cache.h
index 728663b..231a53f 100644
--- a/chrome/browser/thumbnail/cc/thumbnail_cache.h
+++ b/chrome/browser/thumbnail/cc/thumbnail_cache.h
@@ -160,9 +160,12 @@
   void OnMemoryPressure(
       base::MemoryPressureListener::MemoryPressureLevel level);
 
-  // TODO(ckitagawa): Look into making this USER_VISIBLE for at least a subset
-  // of tasks.
-  const scoped_refptr<base::SequencedTaskRunner> file_sequenced_task_runner_;
+  // TODO(crbug/1402843): Look into making these USER_VISIBLE. They do look
+  // visually jarring if late.
+  const scoped_refptr<base::SequencedTaskRunner>
+      etc1_file_sequenced_task_runner_;
+  const scoped_refptr<base::SequencedTaskRunner>
+      jpeg_file_sequenced_task_runner_;
   thumbnail::Etc1ThumbnailHelper etc1_helper_;
   thumbnail::JpegThumbnailHelper jpeg_helper_;
 
@@ -172,6 +175,8 @@
   const bool save_jpeg_thumbnails_;
   base::TimeDelta capture_min_request_time_ms_;
 
+  // TODO(crbug/1402843): Determine if these limits are still relevant.
+  // Remove or tune accordingly (i.e. split by jpeg and etc1).
   size_t compression_tasks_count_;
   size_t write_tasks_count_;
   bool read_in_progress_;
diff --git a/chrome/browser/tracing/chrome_tracing_delegate.cc b/chrome/browser/tracing/chrome_tracing_delegate.cc
index da177fd..77f98d97 100644
--- a/chrome/browser/tracing/chrome_tracing_delegate.cc
+++ b/chrome/browser/tracing/chrome_tracing_delegate.cc
@@ -268,9 +268,13 @@
 absl::optional<base::Value::Dict>
 ChromeTracingDelegate::GenerateMetadataDict() {
   base::Value::Dict metadata_dict;
+  base::FieldTrial::ActiveGroups active_groups;
+  // Do not include low anonymity field trials, to prevent them from being
+  // included in chrometto reports.
+  base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
   std::vector<std::string> variations;
   variations::GetFieldTrialActiveGroupIdsAsStrings(base::StringPiece(),
-                                                   &variations);
+                                                   active_groups, &variations);
 
   base::Value::List variations_list;
   for (const auto& it : variations)
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 180f5ea..7cd1eba 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3381,6 +3381,7 @@
       "//chromeos/ash/services/bluetooth_config/public/mojom",
       "//chromeos/ash/services/cellular_setup",
       "//chromeos/ash/services/cellular_setup/public/mojom",
+      "//chromeos/ash/services/connectivity/public/mojom",
       "//chromeos/ash/services/federated/public/cpp",
       "//chromeos/ash/services/federated/public/mojom",
       "//chromeos/ash/services/hotspot_config",
@@ -3456,6 +3457,7 @@
       "//ui/chromeos/resources",
       "//ui/chromeos/strings",
       "//ui/chromeos/strings:strings_provider",
+      "//ui/chromeos/styles:cros_styles_resources",
       "//ui/compositor_extra",
       "//ui/display/manager",
       "//ui/events/ash",
@@ -5631,20 +5633,24 @@
       ]
     }
 
-    if (use_aura) {
+    if (use_aura && (is_linux || is_chromeos_lacros)) {
       # These files can do Gtk+-based theming for builds with gtk enabled.
-      if (is_linux || is_chromeos_lacros) {
+      sources += [
+        "views/chrome_browser_main_extra_parts_views_linux.cc",
+        "views/chrome_browser_main_extra_parts_views_linux.h",
+      ]
+      deps += [
+        "//ui/base/cursor",
+        "//ui/ozone",
+      ]
+      if (use_dbus) {
         sources += [
-          "views/chrome_browser_main_extra_parts_views_linux.cc",
-          "views/chrome_browser_main_extra_parts_views_linux.h",
           "views/dark_mode_manager_linux.cc",
           "views/dark_mode_manager_linux.h",
         ]
         deps += [
           "//components/dbus/thread_linux",
           "//dbus",
-          "//ui/base/cursor",
-          "//ui/ozone",
         ]
       }
     }
diff --git a/chrome/browser/ui/android/favicon/java/src/org/chromium/chrome/browser/ui/favicon/FaviconUtils.java b/chrome/browser/ui/android/favicon/java/src/org/chromium/chrome/browser/ui/favicon/FaviconUtils.java
index 32c49443..8841627 100644
--- a/chrome/browser/ui/android/favicon/java/src/org/chromium/chrome/browser/ui/favicon/FaviconUtils.java
+++ b/chrome/browser/ui/android/favicon/java/src/org/chromium/chrome/browser/ui/favicon/FaviconUtils.java
@@ -74,13 +74,18 @@
      * Create a bitmap with corresponding size of a generic favicon.
      * @param context {@link Context} to read the generic favicon.
      * @param size Desired size of the bitmap.
+     * @param backgroundColor Optional background color for the favicon.
      * @return A generic globe favicon.
      */
-    public static Bitmap createGenericFaviconBitmap(Context context, int size) {
+    public static Bitmap createGenericFaviconBitmap(
+            Context context, int size, @Nullable @ColorInt Integer backgroundColor) {
         Bitmap bitmap = Bitmap.createBitmap(size, size, Config.ARGB_8888);
-        Drawable drawable = AppCompatResources.getDrawable(context, R.drawable.ic_globe_24dp);
+        Drawable drawable = AppCompatResources.getDrawable(context, R.drawable.ic_globe_48dp);
         drawable.setBounds(0, 0, size, size);
         Canvas canvas = new Canvas(bitmap);
+        if (backgroundColor != null) {
+            canvas.drawColor(backgroundColor);
+        }
         drawable.draw(canvas);
         return bitmap;
     }
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_da.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_da.xtb
index 17ce292a..3ce162e5 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_da.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_da.xtb
@@ -402,7 +402,7 @@
 <translation id="3211426585530211793"><ph name="ITEM_TITLE" /> blev slettet</translation>
 <translation id="3214996641768123781"><ph name="BEGIN_LINK1" />Søgehistorik<ph name="END_LINK1" /> og <ph name="BEGIN_LINK2" />andre former for aktivitet<ph name="END_LINK2" /> kan blive gemt på din Google-konto, når du er logget ind. Du kan til enhver tid slette dem.</translation>
 <translation id="321773570071367578">Hvis du har glemt din adgangssætning eller vil ændre denne indstilling, skal du <ph name="BEGIN_LINK" />nulstille synkroniseringen<ph name="END_LINK" /></translation>
-<translation id="3220943972464248773">Bekræft din identitet for at synkronisere dine adgangskoder</translation>
+<translation id="3220943972464248773">Verificer din identitet for at synkronisere dine adgangskoder</translation>
 <translation id="3223522355830797639">Din bank vil gerne bekræfte, at det er dig.</translation>
 <translation id="3227557059438308877">Google Chrome som sikkerhedsnøgle</translation>
 <translation id="3232754137068452469">Webapp</translation>
@@ -463,7 +463,7 @@
 <translation id="3518985090088779359">Acceptér og fortsæt</translation>
 <translation id="3522247891732774234">Tilgængelig opdatering. Flere valgmuligheder</translation>
 <translation id="3524138585025253783">Brugerflade for udviklere</translation>
-<translation id="3524334353996115845">Tillad, at <ph name="ORIGIN" /> bekræfter din identitet</translation>
+<translation id="3524334353996115845">Tillad, at <ph name="ORIGIN" /> verificerer din identitet</translation>
 <translation id="3527085408025491307">Mappe</translation>
 <translation id="3542235761944717775">Der er <ph name="KILOBYTES" /> kB til rådighed</translation>
 <translation id="3549657413697417275">Søg i din historik</translation>
@@ -513,7 +513,7 @@
 <translation id="3819183753496523827">Du er offline. Tjek din internetforbindelse, og prøv igen.</translation>
 <translation id="3830886834687455630">Opdater Google Play-tjenester for at tjekke dine adgangskoder</translation>
 <translation id="3845098929839618392">Åbn i inkognitofane</translation>
-<translation id="3856096718352044181">Bekræft, at dette er en gyldig udbyder, eller prøv igen senere</translation>
+<translation id="3856096718352044181">Verificer, at dette er en gyldig udbyder, eller prøv igen senere</translation>
 <translation id="3858860766373142691">Navn</translation>
 <translation id="3861633093716975811">Populære videoer</translation>
 <translation id="3874520961715512166">Websitet er fjernet</translation>
@@ -983,7 +983,7 @@
 <translation id="6343495912647200061">{SHIPPING_ADDRESS,plural, =1{<ph name="SHIPPING_ADDRESS_PREVIEW" />\u2026 og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> mere}one{<ph name="SHIPPING_ADDRESS_PREVIEW" />\u2026 og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> mere}other{<ph name="SHIPPING_ADDRESS_PREVIEW" />\u2026 og <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> mere}}</translation>
 <translation id="6345878117466430440">Markér som læst</translation>
 <translation id="6357653805084533597">Du kan bruge denne telefon til at logge ind på den enhed, der viser QR-koden.</translation>
-<translation id="6363990818884053551">Bekræft din identitet for at starte synkroniseringen</translation>
+<translation id="6363990818884053551">Verificer din identitet for at starte synkroniseringen</translation>
 <translation id="6364438453358674297">Vil du fjerne forslaget fra historikken?</translation>
 <translation id="6380100320871303656">Forudindlæser oftere sider, som Chrome tror, der er stor chance for, at du besøger. Denne indstilling kan medføre et højere dataforbrug.</translation>
 <translation id="6394791151443660613">Søg: <ph name="SEARCH_QUERY" /></translation>
@@ -1230,7 +1230,7 @@
 <translation id="7581273696622423628">Deltag i undersøgelsen</translation>
 <translation id="7583262514280211622">Her finder du din læseliste</translation>
 <translation id="7588219262685291874">Aktivér mørkt tema, når enhedens batterisparefunktion er aktiveret</translation>
-<translation id="7594687499944811403">Tillad, at <ph name="EMBEDDED_ORIGIN" /> bekræfter din identitet for <ph name="TOP_ORIGIN" /></translation>
+<translation id="7594687499944811403">Tillad, at <ph name="EMBEDDED_ORIGIN" /> verificerer din identitet for <ph name="TOP_ORIGIN" /></translation>
 <translation id="7596558890252710462">Operativsystem</translation>
 <translation id="7605594153474022051">Synkronisering fungerer ikke</translation>
 <translation id="7612619742409846846">Du er logget ind på Google som</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ko.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ko.xtb
index 1a053dfd..7309ac9 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ko.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ko.xtb
@@ -301,7 +301,7 @@
 <translation id="2702516483241149200">신규: 이 텍스트로 스크롤하는 링크 공유하기</translation>
 <translation id="2707726405694321444">페이지 새로고침</translation>
 <translation id="271033894570825754">New</translation>
-<translation id="2711073837061989559">무료 체험</translation>
+<translation id="2711073837061989559">체험판</translation>
 <translation id="2718352093833049315">Wi-Fi 연결 시</translation>
 <translation id="2718846868787000099">콘텐츠를 기본 언어로 표시하기 위해 방문하는 사이트에서 기본 설정을 확인할 수 있습니다.</translation>
 <translation id="2722945394406572875">개인 정보 보호 샌드박스 메시지 닫힘</translation>
@@ -424,7 +424,7 @@
 <translation id="3282568296779691940">Chrome에 로그인</translation>
 <translation id="3285080554353377245">Chrome 사용 방법에 관한 동영상</translation>
 <translation id="3290249595466894471">또한 페이지, 다운로드 항목, 확장 프로그램 활동, 시스템 정보의 표본을 일부 전송하여 새로운 위협을 발견하는 데 도움을 줍니다.</translation>
-<translation id="3293181007446299124">방문 기록은 기기에서 비공개로 유지되며 신고는 사용자의 신원을 보호하기 위해 보고서 전송이 지연됩니다.</translation>
+<translation id="3293181007446299124">방문 기록은 기기에서 비공개로 유지되며 사용자의 신원을 보호하기 위해 보고서 전송이 지연됩니다.</translation>
 <translation id="3303414029551471755">콘텐츠를 다운로드하시겠습니까?</translation>
 <translation id="3305795716056605962">옵션 더보기 버튼을 눌러 페이지 번역하기</translation>
 <translation id="3319664549618064419">사이트를 더 편하게 보려면 데스크톱 사이트로 전환하세요</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_pl.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_pl.xtb
index 293da2c..b3f7373 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_pl.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_pl.xtb
@@ -1163,7 +1163,7 @@
 <translation id="7242755609445462077">Stylizowane wyróżnienie: <ph name="CURRENT_DATE" /></translation>
 <translation id="7248069434667874558">Sprawdź, czy <ph name="TARGET_DEVICE_NAME" /> ma włączoną synchronizację w Chrome</translation>
 <translation id="7252076891734325316">Przybliż telefon do komputera</translation>
-<translation id="7260367682327802201">Twoje urządzenie z Androidem może mieć podobne ustawienie. Jeśli w Chrome i na Twoim urządzeniu z Androidem jest włączony pomiar skuteczności reklam, firma może mierzyć skuteczność reklam w odwiedzanych przez Ciebie witrynach i w aplikacjach, z których korzystasz.</translation>
+<translation id="7260367682327802201">Twoje urządzenie z Androidem może mieć podobne ustawienie. Jeśli w Chrome i na Twoim urządzeniu z Androidem jest włączony pomiar skuteczności reklam, firma może mierzyć skuteczność reklam w odwiedzanych przez Ciebie witrynach i w aplikacjach, z których korzystasz</translation>
 <translation id="727288900855680735">Przesłać <ph name="ONE_TIME_CODE" /> do <ph name="ORIGIN" />?</translation>
 <translation id="7274013316676448362">Zablokowana witryna</translation>
 <translation id="7286572596625053347">Zmienić język <ph name="LANGUAGE" /> na inny?</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-TW.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-TW.xtb
index 37a96d1..3ad6559b 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-TW.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-TW.xtb
@@ -355,7 +355,7 @@
 <translation id="2979025552038692506">選取的無痕式分頁</translation>
 <translation id="2979639724566107830">於新視窗中開啟</translation>
 <translation id="2981364137500752533">最多只能開啟 5 個視窗。</translation>
-<translation id="2983102365694924129">根據你在網站上的活動獨家推薦。這項設定已關閉。</translation>
+<translation id="2983102365694924129">以你的網站活動做為依據。這項設定已關閉。</translation>
 <translation id="2984978667043170458">使用 Google 搜尋時納入前後文</translation>
 <translation id="2987620471460279764">從其他裝置分享的文字</translation>
 <translation id="2989523299700148168">最近造訪過</translation>
@@ -368,7 +368,7 @@
 <translation id="301080557829842765">隱私權指南</translation>
 <translation id="3016635187733453316">請確認此裝置已連上網際網路</translation>
 <translation id="3026955690410463085">加入連結</translation>
-<translation id="3027644380269727216">根據你在網站上的活動獨家推薦。這項設定已開啟。</translation>
+<translation id="3027644380269727216">以你的網站活動做為依據。這項設定已開啟。</translation>
 <translation id="3029276696788198026">不使用預先載入模式</translation>
 <translation id="3029704984691124060">通關密語不符</translation>
 <translation id="3036750288708366620"><ph name="BEGIN_LINK" />取得說明<ph name="END_LINK" /></translation>
@@ -537,7 +537,7 @@
 <translation id="3969863827134279083">上移</translation>
 <translation id="397583555483684758">同步處理功能已停止運作</translation>
 <translation id="3976396876660209797">移除這個捷徑後再重新建立</translation>
-<translation id="3981902534690264083">廣告客戶可以瞭解廣告成效</translation>
+<translation id="3981902534690264083">廣告商可以瞭解廣告成效</translation>
 <translation id="3985022125189960801">你重新新增的網站可再次推斷你的興趣喜好</translation>
 <translation id="3985215325736559418">你要再次下載 <ph name="FILE_NAME" /> 嗎?</translation>
 <translation id="3987993985790029246">複製連結</translation>
@@ -560,7 +560,7 @@
 <translation id="4096227151372679484">書籤儲存流程已開啟,目前顯示半個版面的內容</translation>
 <translation id="4101475238162928417">進行同步處理,取得你在其他裝置上的密碼、書籤和其他資料</translation>
 <translation id="410351446219883937">自動播放</translation>
-<translation id="4106587138345390261">Chrome 正在探索新功能,讓網站在存取較少個人資訊的情況下,仍能提供相同的瀏覽體驗</translation>
+<translation id="4106587138345390261">Chrome 團隊正在研究新功能,設法讓網站減少存取個人資訊的情況,同時讓使用者享有相同的瀏覽體驗。</translation>
 <translation id="4108314971463891922">追蹤</translation>
 <translation id="4108998448622696017">可偵測不安全事件,並在這類事件發生時顯示警告訊息。</translation>
 <translation id="4116038641877404294">下載網頁以便離線存取</translation>
@@ -787,7 +787,7 @@
 <translation id="5271967389191913893">裝置無法開啟您要下載的這項內容。</translation>
 <translation id="5274286919938458946">已連結到 <ph name="CARD_DETAIL" /></translation>
 <translation id="5292796745632149097">傳送到</translation>
-<translation id="5300426565656326054">以瀏覽器為主的廣告個人化</translation>
+<translation id="5300426565656326054">根據瀏覽器的使用記錄放送個人化廣告</translation>
 <translation id="5304593522240415983">這個欄位不能留空</translation>
 <translation id="5308380583665731573">連線</translation>
 <translation id="5317780077021120954">儲存</translation>
@@ -1186,7 +1186,7 @@
 <translation id="7375125077091615385">類型:</translation>
 <translation id="7376560087009844242">使用輕觸搜尋功能時,納入較多網頁文字也許能找到更相關的結果。你隨時可以前往<ph name="BEGIN_LINK" />設定頁面<ph name="END_LINK" />調整設定。</translation>
 <translation id="7379900596734708416">現已推出網站的深色主題</translation>
-<translation id="7388615499319468910">網站和廣告客戶可以瞭解廣告成效。這項設定已關閉。</translation>
+<translation id="7388615499319468910">網站和廣告商可以瞭解廣告成效。這項設定已關閉。</translation>
 <translation id="7400418766976504921">網址</translation>
 <translation id="7403691278183511381">Chrome 初次使用體驗</translation>
 <translation id="7411224099004328643">Google 帳戶使用者</translation>
@@ -1199,7 +1199,7 @@
 <translation id="7453467225369441013">大多數網站都會將你登出,但系統並不會將你登出 Google 帳戶。</translation>
 <translation id="7453810262525006706">收合至側邊面板</translation>
 <translation id="7454641608352164238">空間不足</translation>
-<translation id="7455988709578031708">根據你的瀏覽記錄獨家推薦。這項設定已開啟。</translation>
+<translation id="7455988709578031708">以你的瀏覽記錄做為依據。這項設定已開啟。</translation>
 <translation id="7456774706094330779">延伸預先載入模式</translation>
 <translation id="7466431077154602932">密集檢視</translation>
 <translation id="7474822150871987353">不必離開原本的網頁,即可查看網站上各主題的資訊。只要選取網頁上的一或多個字詞,就能展開搜尋。</translation>
@@ -1453,7 +1453,7 @@
 <translation id="8662811608048051533">大多數網站都會將你登出。</translation>
 <translation id="8664215986015753476">以個人化的方式使用 Chrome</translation>
 <translation id="8664979001105139458">檔案名稱已存在</translation>
-<translation id="8666759526542103597">關於以瀏覽器為主的廣告個人化</translation>
+<translation id="8666759526542103597">「根據瀏覽器的使用記錄放送個人化廣告」的相關說明</translation>
 <translation id="8676789164135894283">登入驗證</translation>
 <translation id="8683039184091909753">圖片</translation>
 <translation id="869891660844655955">到期日</translation>
@@ -1531,11 +1531,11 @@
 <translation id="9084103763810123431">如要在其他裝置上繼續瀏覽,可以同步分頁和歷史記錄</translation>
 <translation id="9086302186042011942">正在同步處理</translation>
 <translation id="9086455579313502267">無法存取網路</translation>
-<translation id="9099220545925418560">根據你的瀏覽記錄獨家推薦。這項設定已關閉。</translation>
+<translation id="9099220545925418560">以你的瀏覽記錄做為依據。這項設定已關閉。</translation>
 <translation id="9100610230175265781">請提供通關密語</translation>
 <translation id="9101137867221042551">管理設定</translation>
 <translation id="9102803872260866941">預覽分頁已開啟</translation>
-<translation id="9102864637938129124">網站和廣告客戶可以瞭解廣告成效。這項設定已開啟。</translation>
+<translation id="9102864637938129124">網站和廣告商可以瞭解廣告成效。這項設定已開啟。</translation>
 <translation id="9104217018994036254">要共用分頁的裝置清單。</translation>
 <translation id="9106148373857059373">書籤儲存流程已關閉</translation>
 <translation id="9108312223223904744">支援使用手機做為安全金鑰</translation>
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_client_impl_browsertest.cc b/chrome/browser/ui/ash/holding_space/holding_space_client_impl_browsertest.cc
index 4b2e193..1b01a6f1 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_client_impl_browsertest.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_client_impl_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/holding_space/holding_space_controller.h"
 #include "ash/public/cpp/holding_space/holding_space_image.h"
 #include "ash/public/cpp/holding_space/holding_space_item.h"
@@ -108,6 +109,15 @@
     const std::string& expected_id =
         client->AddItemOfType(expected_type, expected_file_path);
 
+    // Insertion into the model should only fail if the item is a Camera app
+    // item and Camera app integration is disabled.
+    if (expected_id.empty()) {
+      EXPECT_EQ(model->items().size(), expected_count);
+      EXPECT_TRUE(HoldingSpaceItem::IsCameraAppType(expected_type));
+      EXPECT_FALSE(features::IsHoldingSpaceCameraAppIntegrationEnabled());
+      continue;
+    }
+
     // Verify the item was created as expected.
     ASSERT_EQ(model->items().size(), ++expected_count);
     const HoldingSpaceItem* item = model->items().back().get();
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc
index c4d15c8..d8a54ae8 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc
@@ -290,10 +290,17 @@
   std::vector<std::unique_ptr<HoldingSpaceItem>> items_to_add;
 
   for (auto& item : items) {
+    // Ignore any `items` that are of Camera app types if Camera app integration
+    // is disabled.
+    if (HoldingSpaceItem::IsCameraAppType(item->type()) &&
+        !features::IsHoldingSpaceCameraAppIntegrationEnabled()) {
+      result.push_back(std::cref(base::EmptyString()));
+      continue;
+    }
+    // Ignore any `items` that already exist in the `holding_space_model_` if
+    // `allow_duplicates` is false.
     if (!allow_duplicates &&
         holding_space_model_.ContainsItem(item->type(), item->file_path())) {
-      // Ignore any `items` that already exist in the `holding_space_model_`
-      // if `allow_duplicates` is false.
       result.push_back(std::cref(base::EmptyString()));
       continue;
     }
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
index 2e17fc4..4d4f6cb 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_unittest.cc
@@ -23,6 +23,7 @@
 #include "base/scoped_observation.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/test_future.h"
 #include "base/time/time.h"
 #include "base/time/time_override.h"
@@ -138,6 +139,18 @@
   return deserialized_item_ptr;
 }
 
+bool ShouldRestoreFromPersistence(HoldingSpaceItem::Type type) {
+  if (HoldingSpaceItem::IsCameraAppType(type) &&
+      !features::IsHoldingSpaceCameraAppIntegrationEnabled()) {
+    return false;
+  }
+  if (HoldingSpaceItem::IsSuggestion(type) &&
+      !features::IsHoldingSpaceSuggestionsEnabled()) {
+    return false;
+  }
+  return true;
+}
+
 // Utility class which can wait until a `HoldingSpaceModel` for a given profile
 // is attached to the `HoldingSpaceController`.
 class HoldingSpaceModelAttachedWaiter : public HoldingSpaceControllerObserver {
@@ -599,24 +612,19 @@
 class HoldingSpaceKeyedServiceWithExperimentalFeatureTest
     : public HoldingSpaceKeyedServiceTest,
       public testing::WithParamInterface<
-          std::tuple</*enable_predictability=*/bool,
-                     /*enable_suggestion=*/bool>> {
+          std::tuple</*enable_camera_app_integration=*/bool,
+                     /*enable_predictability=*/bool,
+                     /*enable_suggestions=*/bool>> {
  public:
   HoldingSpaceKeyedServiceWithExperimentalFeatureTest() {
     std::vector<base::test::FeatureRef> enabled_features;
     std::vector<base::test::FeatureRef> disabled_features;
-    if (std::get<0>(GetParam())) {
-      enabled_features.push_back(features::kHoldingSpacePredictability);
-    } else {
-      disabled_features.push_back(features::kHoldingSpacePredictability);
-    }
-
-    if (std::get<1>(GetParam())) {
-      enabled_features.push_back(features::kHoldingSpaceSuggestions);
-    } else {
-      disabled_features.push_back(features::kHoldingSpaceSuggestions);
-    }
-
+    (std::get<0>(GetParam()) ? enabled_features : disabled_features)
+        .push_back(features::kHoldingSpaceCameraAppIntegration);
+    (std::get<1>(GetParam()) ? enabled_features : disabled_features)
+        .push_back(features::kHoldingSpacePredictability);
+    (std::get<2>(GetParam()) ? enabled_features : disabled_features)
+        .push_back(features::kHoldingSpaceSuggestions);
     scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
   }
 
@@ -624,9 +632,12 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         HoldingSpaceKeyedServiceWithExperimentalFeatureTest,
-                         testing::Combine(testing::Bool(), testing::Bool()));
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    HoldingSpaceKeyedServiceWithExperimentalFeatureTest,
+    testing::Combine(/*enable_camera_app_integration=*/testing::Bool(),
+                     /*enable_predictability*/ testing::Bool(),
+                     /*enabled_suggestions=*/testing::Bool()));
 
 TEST_P(HoldingSpaceKeyedServiceWithExperimentalFeatureTest, GuestUserProfile) {
   // Construct a guest session profile.
@@ -1349,10 +1360,7 @@
           persisted_holding_space_items_before_restoration.Append(
               fresh_holding_space_item->Serialize());
 
-          // Suggestions should not be restored if the suggestion feature is
-          // disabled.
-          if (!HoldingSpaceItem::IsSuggestion(type) ||
-              features::IsHoldingSpaceSuggestionsEnabled()) {
+          if (ShouldRestoreFromPersistence(type)) {
             // We expect the `fresh_holding_space_item` to still be in
             // persistence after model restoration since its backing file
             // exists.
@@ -1422,15 +1430,11 @@
       "HoldingSpace.Item.TotalCount.All",
       secondary_holding_space_model->items().size(), 1);
   for (const HoldingSpaceItem::Type type : GetHoldingSpaceItemTypes()) {
-    // Suggestions are not added to the model if the feature is disabled.
-    const bool should_restore = !HoldingSpaceItem::IsSuggestion(type) ||
-                                features::IsHoldingSpaceSuggestionsEnabled();
-    const int expected_count = should_restore ? 1 : 0;
-
     histogram_tester.ExpectBucketCount(
         base::StringPrintf("HoldingSpace.Item.TotalCount.%s",
                            holding_space_util::ToString(type).c_str()),
-        /*sample=*/1, expected_count);
+        /*sample=*/1,
+        /*expected_count=*/ShouldRestoreFromPersistence(type) ? 1 : 0);
   }
 }
 
@@ -1472,11 +1476,7 @@
           persisted_holding_space_items_before_restoration.Append(
               delayed_holding_space_item->Serialize());
 
-          // Suggestions should not be restored if the suggestion feature is
-          // disabled.
-          const bool should_restore =
-              !HoldingSpaceItem::IsSuggestion(type) ||
-              features::IsHoldingSpaceSuggestionsEnabled();
+          const bool should_restore = ShouldRestoreFromPersistence(type);
 
           // If an item should be restored, it should be restored after delayed
           // volume mount, and remain in persistent storage.
@@ -1642,11 +1642,7 @@
           persisted_holding_space_items_before_restoration.Append(
               delayed_holding_space_item->Serialize());
 
-          // Suggestions should not be restored if the suggestion feature is
-          // disabled.
-          const bool should_restore =
-              !HoldingSpaceItem::IsSuggestion(type) ||
-              features::IsHoldingSpaceSuggestionsEnabled();
+          const bool should_restore = ShouldRestoreFromPersistence(type);
 
           // The item is restored after delayed volume mount, and remain
           // in persistent storage if it should be restored.
@@ -1789,10 +1785,7 @@
 
           // The item should be immediately added to the model, and remain in
           // the persistent storage if it should be restored.
-          const bool should_restore =
-              !HoldingSpaceItem::IsSuggestion(type) ||
-              features::IsHoldingSpaceSuggestionsEnabled();
-          if (should_restore) {
+          if (ShouldRestoreFromPersistence(type)) {
             initialized_items_before_delayed_mount.push_back(
                 fresh_holding_space_item->id());
             persisted_holding_space_items_after_restoration.Append(
@@ -1962,13 +1955,9 @@
           persisted_holding_space_items_before_restoration.Append(
               fresh_holding_space_item->Serialize());
 
-          bool should_restore = false;
-          if (!features::IsHoldingSpaceSuggestionsEnabled() &&
-              HoldingSpaceItem::IsSuggestion(type)) {
-            // Suggestion items should not be restored if the suggestion feature
-            // is disabled.
-            should_restore = false;
-          } else {
+          bool should_restore = ShouldRestoreFromPersistence(type);
+
+          if (should_restore) {
             // Pinned files are exempt from age checks. If the predictability
             // feature is disabled, we expect all holding space items of other
             // types to be removed from persistence during restoration due to
@@ -2561,18 +2550,27 @@
 }
 
 // Base class for tests which verify adding and removing items from holding
-// space works as intended, parameterized by holding space item type.
+// space works as intended, parameterized by holding space item type and
+// whether Camera app integration is enabled.
 class HoldingSpaceKeyedServiceAddAndRemoveItemTest
     : public HoldingSpaceKeyedServiceTest,
-      public ::testing::WithParamInterface<HoldingSpaceItem::Type> {
+      public ::testing::WithParamInterface<
+          std::tuple<HoldingSpaceItem::Type,
+                     /*enable_camera_app_integration=*/bool>> {
  public:
+  HoldingSpaceKeyedServiceAddAndRemoveItemTest() {
+    scoped_feature_list_.InitWithFeatureState(
+        features::kHoldingSpaceCameraAppIntegration,
+        /*enable_camera_app_integration=*/std::get<1>(GetParam()));
+  }
+
   // Returns the holding space service associated with the specified `profile`.
   HoldingSpaceKeyedService* GetService(Profile* profile) {
     return HoldingSpaceKeyedServiceFactory::GetInstance()->GetService(profile);
   }
 
   // Returns the type of holding space item under test.
-  HoldingSpaceItem::Type GetType() const { return GetParam(); }
+  HoldingSpaceItem::Type GetType() const { return std::get<0>(GetParam()); }
 
   // Adds an item of `type` to the holding space belonging to `profile`, backed
   // by the file at the specified absolute `file_path`. Returns the `id` of the
@@ -2598,7 +2596,14 @@
       case HoldingSpaceItem::Type::kCameraAppScanJpg:
       case HoldingSpaceItem::Type::kCameraAppScanPdf:
       case HoldingSpaceItem::Type::kCameraAppVideoGif:
-      case HoldingSpaceItem::Type::kCameraAppVideoMp4:
+      case HoldingSpaceItem::Type::kCameraAppVideoMp4: {
+        const auto& id = holding_space_service->AddItemOfType(type, file_path);
+        if (!features::IsHoldingSpaceCameraAppIntegrationEnabled()) {
+          EXPECT_TRUE(id.empty());
+          return id;
+        }
+        break;
+      }
       case HoldingSpaceItem::Type::kDiagnosticsLog:
       case HoldingSpaceItem::Type::kNearbyShare:
         holding_space_service->AddItemOfType(type, file_path);
@@ -2638,11 +2643,16 @@
     EXPECT_TRUE(item);
     return item->id();
   }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         HoldingSpaceKeyedServiceAddAndRemoveItemTest,
-                         ::testing::ValuesIn(GetHoldingSpaceItemTypes()));
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    HoldingSpaceKeyedServiceAddAndRemoveItemTest,
+    testing::Combine(testing::ValuesIn(GetHoldingSpaceItemTypes()),
+                     /*enable_camera_app_integration=*/testing::Bool()));
 
 TEST_P(HoldingSpaceKeyedServiceAddAndRemoveItemTest, AddAndRemoveItem) {
   // Wait for the holding space model to attach.
@@ -2675,6 +2685,15 @@
   // Add a holding space item of the type under test.
   const std::string id = AddItem(profile, GetType(), file_path);
 
+  // Insertion into the model should only fail if the item is a Camera app item
+  // and Camera app integration is disabled.
+  if (id.empty()) {
+    EXPECT_EQ(model->items().size(), 0u);
+    EXPECT_TRUE(HoldingSpaceItem::IsCameraAppType(GetType()));
+    EXPECT_FALSE(features::IsHoldingSpaceCameraAppIntegrationEnabled());
+    return;
+  }
+
   // Verify a holding space item has been added to the model.
   ASSERT_EQ(model->items().size(), 1u);
 
@@ -2758,7 +2777,15 @@
 
   // Add a holding space item of the type under test.
   const auto& id = GetService(profile)->AddItemOfType(GetType(), file_path);
-  EXPECT_FALSE(id.empty());
+
+  // Insertion into the model should only fail if the item is a Camera app item
+  // and Camera app integration is disabled.
+  if (id.empty()) {
+    EXPECT_EQ(model->items().size(), 0u);
+    EXPECT_TRUE(HoldingSpaceItem::IsCameraAppType(GetType()));
+    EXPECT_FALSE(features::IsHoldingSpaceCameraAppIntegrationEnabled());
+    return;
+  }
 
   // Verify a holding space item has been added to the model.
   ASSERT_EQ(model->items().size(), 1u);
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_persistence_delegate.cc b/chrome/browser/ui/ash/holding_space/holding_space_persistence_delegate.cc
index 6a396c9b7..e461090 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_persistence_delegate.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_persistence_delegate.cc
@@ -131,8 +131,9 @@
 void HoldingSpacePersistenceDelegate::RestoreModelFromPersistence() {
   DCHECK(model()->items().empty());
 
-  // Clear suggestions before restoration if needed.
-  MaybeRemoveSuggestionsFromPersistence();
+  // Remove items from persistent storage that should not be restored to the
+  // in-memory holding space model.
+  MaybeRemoveItemsFromPersistence();
 
   const base::Value::List& persisted_holding_space_items =
       profile()->GetPrefs()->GetList(kPersistencePath);
@@ -160,16 +161,27 @@
   std::move(persistence_restored_callback_).Run();
 }
 
-void HoldingSpacePersistenceDelegate::MaybeRemoveSuggestionsFromPersistence() {
-  DCHECK(is_restoring_persistence());
+void HoldingSpacePersistenceDelegate::MaybeRemoveItemsFromPersistence() {
+  CHECK(is_restoring_persistence());
 
-  if (features::IsHoldingSpaceSuggestionsEnabled())
+  const bool remove_camera_app_items =
+      !features::IsHoldingSpaceCameraAppIntegrationEnabled();
+  const bool remove_suggestion_items =
+      !features::IsHoldingSpaceSuggestionsEnabled();
+
+  // No-op when there are no item types we'd attempt to remove.
+  if (!remove_camera_app_items && !remove_suggestion_items) {
     return;
+  }
 
   ScopedListPrefUpdate update(profile()->GetPrefs(), kPersistencePath);
-  update->EraseIf([](const base::Value& persisted_item) {
-    return HoldingSpaceItem::IsSuggestion(
-        HoldingSpaceItem::DeserializeType(persisted_item.GetDict()));
+  update->EraseIf([&](const base::Value& persisted_item) {
+    auto type = HoldingSpaceItem::DeserializeType(persisted_item.GetDict());
+    if ((remove_camera_app_items && HoldingSpaceItem::IsCameraAppType(type)) ||
+        (remove_suggestion_items && HoldingSpaceItem::IsSuggestion(type))) {
+      return true;
+    }
+    return false;
   });
 }
 
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_persistence_delegate.h b/chrome/browser/ui/ash/holding_space/holding_space_persistence_delegate.h
index 409d85c..e70c29b1 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_persistence_delegate.h
+++ b/chrome/browser/ui/ash/holding_space/holding_space_persistence_delegate.h
@@ -64,8 +64,9 @@
   // Restores the holding space model from persistent storage.
   void RestoreModelFromPersistence();
 
-  // Removes the persisted suggestions if the suggestion feature is disabled.
-  void MaybeRemoveSuggestionsFromPersistence();
+  // Removes items from persistent storage that should not be restored to the
+  // in-memory holding space model.
+  void MaybeRemoveItemsFromPersistence();
 
   // Owned by `HoldingSpaceKeyedService`.
   ThumbnailLoader* const thumbnail_loader_;
diff --git a/chrome/browser/ui/ash/shelf/app_service/shelf_app_service_app_updater.cc b/chrome/browser/ui/ash/shelf/app_service/shelf_app_service_app_updater.cc
index 2cbbfe8..422056b5 100644
--- a/chrome/browser/ui/ash/shelf/app_service/shelf_app_service_app_updater.cc
+++ b/chrome/browser/ui/ash/shelf/app_service/shelf_app_service_app_updater.cc
@@ -44,11 +44,11 @@
         delegate()->OnAppInstalled(browser_context(), app_id);
         return;
       case apps::Readiness::kUninstalledByUser:
-      case apps::Readiness::kUninstalledByMigration:
+      case apps::Readiness::kUninstalledByNonUser:
         if (it != installed_apps_.end()) {
           installed_apps_.erase(it);
           const bool by_migration =
-              update.Readiness() == apps::Readiness::kUninstalledByMigration;
+              update.Readiness() == apps::Readiness::kUninstalledByNonUser;
           delegate()->OnAppUninstalledPrepared(browser_context(), app_id,
                                                by_migration);
           delegate()->OnAppUninstalled(browser_context(), app_id);
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
index 93132db..aab7f86f7 100644
--- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
+++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
@@ -1140,7 +1140,7 @@
         true /* notifications_enabled */, true /* app_ready */,
         false /* suspended */, false /* shortcut */, true /* launchable */,
         false /* need_fixup */, ArcAppListPrefs::WindowLayout(),
-        app_size_in_bytes, data_size_in_bytes);
+        app_size_in_bytes, data_size_in_bytes, app_info.app_category);
     const std::string app_id =
         ArcAppListPrefs::GetAppId(app_info.package_name, app_info.activity);
     EXPECT_TRUE(prefs->GetApp(app_id));
diff --git a/chrome/browser/ui/color/chrome_color_id.h b/chrome/browser/ui/color/chrome_color_id.h
index bec7416..93586e8 100644
--- a/chrome/browser/ui/color/chrome_color_id.h
+++ b/chrome/browser/ui/color/chrome_color_id.h
@@ -243,6 +243,7 @@
   E_CPONLY(kColorOmniboxText) \
   E_CPONLY(kColorOmniboxTextDimmed) \
   /* Page Info colors */ \
+  E_CPONLY(kColorPageActionIcon) \
   E_CPONLY(kColorPageActionIconHover) \
   E_CPONLY(kColorPageActionIconPressed) \
   E_CPONLY(kColorPageInfoBackground) \
diff --git a/chrome/browser/ui/color/material_chrome_color_mixer.cc b/chrome/browser/ui/color/material_chrome_color_mixer.cc
index 10d3c18..8e6162f 100644
--- a/chrome/browser/ui/color/material_chrome_color_mixer.cc
+++ b/chrome/browser/ui/color/material_chrome_color_mixer.cc
@@ -82,12 +82,6 @@
   mixer[kColorOmniboxChipForegroundLowVisibility] = {
       ui::kColorSysOnSurfaceSubtle};
   mixer[kColorOmniboxChipForegroundNormalVisibility] = {ui::kColorSysOnSurface};
-  mixer[kColorPageActionIconHover] = {ui::kColorSysStateHoverOnSubtle};
-  mixer[kColorPageActionIconPressed] = {
-      ui::kColorSysStateRippleNeutralOnSubtle};
-  mixer[kColorPageInfoBackground] = {ui::kColorSysBaseContainerElevated};
-  mixer[kColorPageInfoIconHover] = {ui::kColorSysStateHoverDimBlendProtection};
-  mixer[kColorPageInfoIconPressed] = {ui::kColorSysStateRippleNeutralOnSubtle};
   mixer[kColorToolbar] = {ui::kColorSysBase};
   mixer[kColorToolbarButtonBackgroundHighlightedDefault] = {
       ui::kColorSysStateHoverOnSubtle};
diff --git a/chrome/browser/ui/color/new_tab_page_color_mixer_unittest.cc b/chrome/browser/ui/color/new_tab_page_color_mixer_unittest.cc
index 28c6bcb..a267d65 100644
--- a/chrome/browser/ui/color/new_tab_page_color_mixer_unittest.cc
+++ b/chrome/browser/ui/color/new_tab_page_color_mixer_unittest.cc
@@ -54,7 +54,7 @@
       ui::ColorProviderManager::ColorMode::kLight,
       ui::ColorProviderManager::ContrastMode::kNormal,
       ui::SystemTheme::kDefault, ui::ColorProviderManager::FrameType::kChromium,
-      absl::nullopt,
+      absl::nullopt, absl::nullopt,
       base::WrapRefCounted(new CustomThemeSupplier(ThemeType::kAutogenerated)));
   AddNewTabPageColorMixer(&provider, key);
   provider.GenerateColorMap();
@@ -84,7 +84,7 @@
       ui::ColorProviderManager::ColorMode::kLight,
       ui::ColorProviderManager::ContrastMode::kNormal,
       ui::SystemTheme::kDefault, ui::ColorProviderManager::FrameType::kChromium,
-      absl::nullopt,
+      absl::nullopt, absl::nullopt,
       base::WrapRefCounted(new CustomThemeSupplier(ThemeType::kAutogenerated)));
   AddNewTabPageColorMixer(&provider, key);
   provider.GenerateColorMap();
@@ -113,7 +113,7 @@
       ui::ColorProviderManager::ColorMode::kLight,
       ui::ColorProviderManager::ContrastMode::kNormal,
       ui::SystemTheme::kDefault, ui::ColorProviderManager::FrameType::kChromium,
-      absl::nullopt,
+      absl::nullopt, absl::nullopt,
       base::WrapRefCounted(new CustomThemeSupplier(ThemeType::kAutogenerated)));
   AddNewTabPageColorMixer(&provider, key);
   provider.GenerateColorMap();
diff --git a/chrome/browser/ui/color/omnibox_color_mixer.cc b/chrome/browser/ui/color/omnibox_color_mixer.cc
index 99dafba1..3d42bd6 100644
--- a/chrome/browser/ui/color/omnibox_color_mixer.cc
+++ b/chrome/browser/ui/color/omnibox_color_mixer.cc
@@ -93,6 +93,26 @@
   mixer[kColorOmniboxTextDimmed] = {selected_text_color_dimmed};
 }
 
+void ApplyCR2023OmniboxIconColors(ui::ColorMixer& mixer,
+                                  const ui::ColorProviderManager::Key& key) {
+  const bool cr2023_icons_colors_enabled =
+      features::GetChromeRefresh2023Level() ==
+          features::ChromeRefresh2023Level::kLevel2 ||
+      base::FeatureList::IsEnabled(omnibox::kOmniboxCR23SteadyStateIcons);
+
+  if (!cr2023_icons_colors_enabled) {
+    return;
+  }
+
+  mixer[kColorPageActionIconHover] = {ui::kColorSysStateHoverOnSubtle};
+  mixer[kColorPageActionIconPressed] = {
+      ui::kColorSysStateRippleNeutralOnSubtle};
+  mixer[kColorPageInfoBackground] = {ui::kColorSysBaseContainerElevated};
+  mixer[kColorPageInfoIconHover] = {ui::kColorSysStateHoverDimBlendProtection};
+  mixer[kColorPageInfoIconPressed] = {ui::kColorSysStateRippleNeutralOnSubtle};
+  mixer[kColorPageActionIcon] = {ui::kColorSysOnSurfaceSubtle};
+}
+
 // Apply updates to the Omnibox "expanded state" color tokens per CR2023 spec.
 void ApplyCR2023OmniboxExpandedStateColors(
     ui::ColorMixer& mixer,
@@ -148,6 +168,7 @@
   }
   ApplyGM3OmniboxTextColor(mixer, key);
   ApplyCR2023OmniboxExpandedStateColors(mixer, key);
+  ApplyCR2023OmniboxIconColors(mixer, key);
 }
 
 }  // namespace
@@ -349,6 +370,20 @@
   mixer[kColorOmniboxAnswerIconGM3Foreground] = ui::SelectBasedOnDarkInput(
       kColorToolbar, SkColorSetRGB(194, 231, 255), SkColorSetRGB(4, 30, 73));
 
+  // location bar icon colors.
+  mixer[kColorPageInfoBackground] = {kColorToolbar};
+  // Literal constants are `kOmniboxOpacityHovered` and
+  // `kOmniboxOpacitySelected`. This is so that we can more cleanly use the
+  // colors in the inkdrop instead of handling themes and non-themes separately
+  // in-code as they have different opacity requirements.
+  mixer[kColorPageInfoIconHover] = {
+      ui::SetAlpha(kColorOmniboxText, std::ceil(0.10f * 255.0f))};
+  mixer[kColorPageInfoIconPressed] = {
+      ui::SetAlpha(kColorOmniboxText, std::ceil(0.16f * 255.0f))};
+  mixer[kColorPageActionIconHover] = {kColorPageInfoIconHover};
+  mixer[kColorPageActionIconPressed] = {kColorPageInfoIconPressed};
+  mixer[kColorPageActionIcon] = {kColorOmniboxResultsIcon};
+
   // Override omnibox colors per CR2023 spec.
   ApplyOmniboxCR2023Colors(mixer, key);
 }
diff --git a/chrome/browser/ui/performance_controls/performance_controls_hats_service_unittest.cc b/chrome/browser/ui/performance_controls/performance_controls_hats_service_unittest.cc
index c428f306..5f7f9d1 100644
--- a/chrome/browser/ui/performance_controls/performance_controls_hats_service_unittest.cc
+++ b/chrome/browser/ui/performance_controls/performance_controls_hats_service_unittest.cc
@@ -125,7 +125,6 @@
         {performance_manager::features::
              kPerformanceControlsBatteryPerformanceSurvey,
          {}},
-        {performance_manager::features::kBatterySaverModeAvailable, {}},
     };
   }
 };
@@ -150,7 +149,6 @@
         {performance_manager::features::
              kPerformanceControlsBatterySaverOptOutSurvey,
          {}},
-        {performance_manager::features::kBatterySaverModeAvailable, {}},
     };
   }
 };
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc
index 57eff9c..7d8a9752 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/notreached.h"
 #include "chrome/browser/bookmarks/url_and_id.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/model_type_store_service_factory.h"
@@ -52,7 +53,9 @@
   }
 }
 
-SavedTabGroupKeyedService::~SavedTabGroupKeyedService() = default;
+SavedTabGroupKeyedService::~SavedTabGroupKeyedService() {
+  model_.RemoveObserver(this);
+}
 
 syncer::OnceModelTypeStoreFactory SavedTabGroupKeyedService::GetStoreFactory() {
   DCHECK(ModelTypeStoreServiceFactory::GetForProfile(profile()));
@@ -287,14 +290,42 @@
     ConnectLocalTabGroup(local_group_id, saved_guid);
   }
 
-  // SavedTabGroupModelLoaded is only called once when the model is initially
-  // loaded. As such we can stop oberserving the model and assume that all of
-  // the data in `saved_guid_to_local_group_id_mapping_` has been used.
-  model_.RemoveObserver(this);
+  // Clear `saved_guid_to_local_group_id_mapping_` expecting that this observer
+  // function will only be called once on startup freeing unsued space.
+  //
+  // TODO(dljames): Investigate using a single use callback to connect local and
+  // saved groups together. There are crashes that occur when restarting the
+  // browser before the browser process completely shuts down. This triggers the
+  // CHECK in StoreLocalToSavedId because the SavedTabGroupModel has already
+  // loaded. The callback will also remove the need of
+  // `saved_guid_to_local_group_id_mapping_`.
   saved_guid_to_local_group_id_mapping_.clear();
   CHECK(saved_guid_to_local_group_id_mapping_.empty());
 }
 
+void SavedTabGroupKeyedService::SavedTabGroupUpdatedFromSync(
+    const base::Uuid& group_guid,
+    const absl::optional<base::Uuid>& tab_guid) {
+  const SavedTabGroup* const saved_group = model_.Get(group_guid);
+  CHECK(saved_group);
+
+  // Do nothing if the saved group is not open in the tabstrip.
+  if (!saved_group->local_group_id().has_value()) {
+    return;
+  }
+
+  if (tab_guid.has_value()) {
+    // TODO(dljames): Update tabs in the tabstrip if the respective group is
+    // open with the updated tab metadata. Figure out if the tab should be
+    // added, removed, or updated based on the data in saved_group.
+    NOTIMPLEMENTED();
+  } else {
+    // Update the visual data of the saved group if it exists and is open in
+    // the tabstrip.
+    UpdateGroupVisualData(group_guid, saved_group->local_group_id().value());
+  }
+}
+
 const TabStripModel* SavedTabGroupKeyedService::GetTabStripModelWithTabGroupId(
     const tab_groups::TabGroupId& local_group_id) {
   const Browser* const browser =
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h
index 4f22cdf..4f6145b 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h
+++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h
@@ -54,6 +54,9 @@
 
   // SavedTabGroupModelObserver
   void SavedTabGroupModelLoaded() override;
+  void SavedTabGroupUpdatedFromSync(
+      const base::Uuid& group_guid,
+      const absl::optional<base::Uuid>& tab_guid) override;
 
  private:
   // Returns a pointer to the TabStripModel which contains `local_group_id`.
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service_unittest.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service_unittest.cc
index 0c80831..6e7ad3c 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service_unittest.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service_unittest.cc
@@ -8,10 +8,12 @@
 
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
+#include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
 #include "content/public/browser/render_process_host.h"
@@ -157,76 +159,6 @@
   EXPECT_TRUE(tab_token_mapping.contains(added_tab));
 }
 
-TEST_F(SavedTabGroupKeyedServiceUnitTest,
-       KeyedServiceLinksTabIdsToGuidsWhenModelIsLoaded) {
-  Browser* browser_1 = AddBrowser();
-  ASSERT_EQ(0, browser_1->tab_strip_model()->count());
-
-  // Add 4 tabs to the browser.
-  for (size_t i = 0; i < 4; ++i) {
-    AddTabToBrowser(browser_1, 0);
-  }
-
-  ASSERT_EQ(4, browser_1->tab_strip_model()->count());
-
-  const tab_groups::TabGroupId tab_group_id_1 =
-      browser_1->tab_strip_model()->AddToNewGroup({0});
-  const tab_groups::TabGroupId tab_group_id_2 =
-      browser_1->tab_strip_model()->AddToNewGroup({1, 2});
-  const tab_groups::TabGroupId tab_group_id_3 =
-      browser_1->tab_strip_model()->AddToNewGroup({3});
-
-  const base::GUID guid_1 = base::GUID::GenerateRandomV4();
-  const base::GUID guid_2 = base::GUID::GenerateRandomV4();
-
-  // Store the guid to tab_group_id association in the keyed service. We should
-  // expect at the end of the test, `tab_group_id_3` has no association with the
-  // SavedTabGroupModel at all.
-  service()->StoreLocalToSavedId(guid_1, tab_group_id_1);
-  service()->StoreLocalToSavedId(guid_2, tab_group_id_2);
-
-  // Populate the SavedTabGroupModel with some test data to simulate the browser
-  // loading in persisted data on startup.
-  std::vector<SavedTabGroupTab> group_1_tabs = {
-      SavedTabGroupTab(GURL("chrome://newtab"), u"New Tab", guid_1)};
-  std::vector<SavedTabGroupTab> group_2_tabs = {
-      SavedTabGroupTab(GURL("chrome://newtab"), u"New Tab", guid_2),
-      SavedTabGroupTab(GURL("chrome://newtab"), u"New Tab", guid_2)};
-
-  SavedTabGroup saved_group_1(u"Group 1", tab_groups::TabGroupColorId::kGrey,
-                              std::move(group_1_tabs), guid_1);
-  SavedTabGroup saved_group_2(u"Group 2", tab_groups::TabGroupColorId::kRed,
-                              std::move(group_2_tabs), guid_2);
-  service()->model()->Add(saved_group_1);
-  service()->model()->Add(saved_group_2);
-
-  // Notify the KeyedService that the SavedTabGroupModel has loaded all local
-  // data triggered by the completion of SavedTabGroupModel::LoadStoredEntries.
-  service()->model()->LoadStoredEntries({});
-
-  // Retrieve the 2 saved groups from the model.
-  SavedTabGroupModel* model = service()->model();
-  const SavedTabGroup* retrieved_saved_group_1 = model->Get(guid_1);
-  const SavedTabGroup* retrieved_saved_group_2 = model->Get(guid_2);
-
-  // Verify saved group 1 and 2 have the correct tab group id.
-  ASSERT_TRUE(retrieved_saved_group_1);
-  ASSERT_TRUE(retrieved_saved_group_1->local_group_id().has_value());
-  EXPECT_EQ(tab_group_id_1, retrieved_saved_group_1->local_group_id().value());
-
-  ASSERT_TRUE(retrieved_saved_group_2);
-  ASSERT_TRUE(retrieved_saved_group_2->local_group_id().has_value());
-  EXPECT_EQ(tab_group_id_2, retrieved_saved_group_2->local_group_id().value());
-
-  // Expect the model can locate tab group ids for group 1 and 2 but not
-  // group 3.
-  EXPECT_TRUE(model->Contains(tab_group_id_1));
-  EXPECT_TRUE(model->Contains(tab_group_id_2));
-  EXPECT_FALSE(model->Contains(tab_group_id_3));
-
-  EXPECT_DEATH(service()->StoreLocalToSavedId(guid_1, tab_group_id_1), "");
-}
-
 TEST_F(SavedTabGroupKeyedServiceUnitTest, PauseResumeTracking) {
   Browser* browser_1 = AddBrowser();
 
@@ -305,3 +237,141 @@
   EXPECT_DEATH(service()->ResumeTrackingLocalTabGroup(saved_group_id, group_id),
                "");
 }
+
+TEST_F(SavedTabGroupKeyedServiceUnitTest,
+       KeyedServiceLinksTabIdsToGuidsWhenModelIsLoaded) {
+  Browser* browser_1 = AddBrowser();
+  ASSERT_EQ(0, browser_1->tab_strip_model()->count());
+
+  // Add 4 tabs to the browser.
+  for (size_t i = 0; i < 4; ++i) {
+    AddTabToBrowser(browser_1, 0);
+  }
+
+  ASSERT_EQ(4, browser_1->tab_strip_model()->count());
+
+  const tab_groups::TabGroupId tab_group_id_1 =
+      browser_1->tab_strip_model()->AddToNewGroup({0});
+  const tab_groups::TabGroupId tab_group_id_2 =
+      browser_1->tab_strip_model()->AddToNewGroup({1, 2});
+  const tab_groups::TabGroupId tab_group_id_3 =
+      browser_1->tab_strip_model()->AddToNewGroup({3});
+
+  const base::GUID guid_1 = base::GUID::GenerateRandomV4();
+  const base::GUID guid_2 = base::GUID::GenerateRandomV4();
+
+  // Store the guid to tab_group_id association in the keyed service. We should
+  // expect at the end of the test, `tab_group_id_3` has no association with the
+  // SavedTabGroupModel at all.
+  service()->StoreLocalToSavedId(guid_1, tab_group_id_1);
+  service()->StoreLocalToSavedId(guid_2, tab_group_id_2);
+
+  // Populate the SavedTabGroupModel with some test data to simulate the browser
+  // loading in persisted data on startup.
+  std::vector<SavedTabGroupTab> group_1_tabs = {
+      SavedTabGroupTab(GURL("chrome://newtab"), u"New Tab", guid_1)};
+  std::vector<SavedTabGroupTab> group_2_tabs = {
+      SavedTabGroupTab(GURL("chrome://newtab"), u"New Tab", guid_2),
+      SavedTabGroupTab(GURL("chrome://newtab"), u"New Tab", guid_2)};
+
+  SavedTabGroup saved_group_1(u"Group 1", tab_groups::TabGroupColorId::kGrey,
+                              std::move(group_1_tabs), guid_1);
+  SavedTabGroup saved_group_2(u"Group 2", tab_groups::TabGroupColorId::kRed,
+                              std::move(group_2_tabs), guid_2);
+  service()->model()->Add(saved_group_1);
+  service()->model()->Add(saved_group_2);
+
+  // Notify the KeyedService that the SavedTabGroupModel has loaded all local
+  // data triggered by the completion of SavedTabGroupModel::LoadStoredEntries.
+  service()->model()->LoadStoredEntries({});
+
+  // Retrieve the 2 saved groups from the model.
+  SavedTabGroupModel* model = service()->model();
+  const SavedTabGroup* retrieved_saved_group_1 = model->Get(guid_1);
+  const SavedTabGroup* retrieved_saved_group_2 = model->Get(guid_2);
+
+  // Verify saved group 1 and 2 have the correct tab group id.
+  ASSERT_TRUE(retrieved_saved_group_1);
+  ASSERT_TRUE(retrieved_saved_group_1->local_group_id().has_value());
+  EXPECT_EQ(tab_group_id_1, retrieved_saved_group_1->local_group_id().value());
+
+  ASSERT_TRUE(retrieved_saved_group_2);
+  ASSERT_TRUE(retrieved_saved_group_2->local_group_id().has_value());
+  EXPECT_EQ(tab_group_id_2, retrieved_saved_group_2->local_group_id().value());
+
+  // Expect the model can locate tab group ids for group 1 and 2 but not
+  // group 3.
+  EXPECT_TRUE(model->Contains(tab_group_id_1));
+  EXPECT_TRUE(model->Contains(tab_group_id_2));
+  EXPECT_FALSE(model->Contains(tab_group_id_3));
+
+  // StoreLocalToSavedId should only be called before the
+  // SavedTabGroupModel is loaded to temporarily preserve id associations before
+  // it is emptied an never used again. Calling StoreLocalToSavedId after the
+  // SavedTabGroupModel is loaded will never use the data taking up space until
+  // the browser is restarted. To prevent this we crash.
+  EXPECT_DEATH(service()->StoreLocalToSavedId(guid_1, tab_group_id_1), "");
+}
+
+TEST_F(SavedTabGroupKeyedServiceUnitTest,
+       KeyedServiceUpdatesOpenTabGroupOnSyncUpdates) {
+  Browser* browser = AddBrowser();
+  ASSERT_EQ(0, browser->tab_strip_model()->count());
+
+  // Add 1 tab to the browser.
+  AddTabToBrowser(browser, 0);
+  ASSERT_EQ(1, browser->tab_strip_model()->count());
+
+  const tab_groups::TabGroupId tab_group_id =
+      browser->tab_strip_model()->AddToNewGroup({0});
+  const base::GUID guid = base::GUID::GenerateRandomV4();
+
+  // Store the guid to tab_group_id association in the keyed service.
+  service()->StoreLocalToSavedId(guid, tab_group_id);
+
+  // Populate the SavedTabGroupModel with some test data to simulate the browser
+  // loading persisted data on startup.
+  std::vector<SavedTabGroupTab> group_tabs = {
+      SavedTabGroupTab(GURL("chrome://newtab"), u"New Tab", guid)};
+
+  SavedTabGroup saved_group(u"Group", tab_groups::TabGroupColorId::kGrey,
+                            std::move(group_tabs), guid);
+  service()->model()->Add(saved_group);
+
+  // Notify the KeyedService that the SavedTabGroupModel has loaded all local
+  // data triggered by the completion of SavedTabGroupModel::LoadStoredEntries.
+  service()->model()->LoadStoredEntries({});
+
+  // Retrieve the saved group from the SavedTabGroupModel.
+  SavedTabGroupModel* model = service()->model();
+  const SavedTabGroup* retrieved_saved_group = model->Get(guid);
+
+  // Retrieve the tab group from the TabStripModel.
+  const TabStripModel* tab_strip_model = browser->tab_strip_model();
+  ASSERT_TRUE(tab_strip_model);
+
+  const TabGroup* tab_group =
+      tab_strip_model->group_model()->GetTabGroup(tab_group_id);
+  ASSERT_TRUE(tab_group);
+
+  // Verify the visual data of the groups are the same.
+  EXPECT_EQ(tab_group->visual_data()->title(), retrieved_saved_group->title());
+  EXPECT_EQ(tab_group->visual_data()->color(), retrieved_saved_group->color());
+
+  const std::u16string new_title = u"First new title";
+  const tab_groups::TabGroupColorId new_color =
+      tab_groups::TabGroupColorId::kOrange;
+
+  tab_groups::TabGroupVisualData visual_data_1(new_title, new_color);
+
+  // Simulate an update on saved groups 1 and 2 from the sync service.
+  service()->model()->UpdatedVisualDataFromSync(guid, &visual_data_1);
+
+  // Verify the groups still have the same visual data and that they have
+  // updated to the new values.
+  EXPECT_EQ(new_title, tab_group->visual_data()->title());
+  EXPECT_EQ(new_color, tab_group->visual_data()->color());
+
+  EXPECT_EQ(tab_group->visual_data()->title(), retrieved_saved_group->title());
+  EXPECT_EQ(tab_group->visual_data()->color(), retrieved_saved_group->color());
+}
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.cc
index d165774..6e37f315 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.cc
@@ -160,7 +160,12 @@
     return;
   }
 
+  if (observed_browsers_.contains(browser)) {
+    return;
+  }
+
   browser->tab_strip_model()->AddObserver(this);
+  observed_browsers_.insert(browser);
 }
 
 void SavedTabGroupModelListener::OnBrowserRemoved(Browser* browser) {
@@ -169,4 +174,6 @@
   }
 
   browser->tab_strip_model()->RemoveObserver(this);
+  CHECK(observed_browsers_.contains(browser));
+  observed_browsers_.erase(browser);
 }
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h
index 546edce..fffe011 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h
+++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h
@@ -83,6 +83,9 @@
       local_tab_group_listeners_;
   raw_ptr<SavedTabGroupModel> model_ = nullptr;
   raw_ptr<Profile> profile_;
+
+  // Use to prevent double-observation. See https://crbug.com/1426389.
+  std::unordered_set<Browser*> observed_browsers_;
 };
 
 #endif  // CHROME_BROWSER_UI_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_MODEL_LISTENER_H_
diff --git a/chrome/browser/ui/tabs/tab_style.h b/chrome/browser/ui/tabs/tab_style.h
index 104f21f..f88ec0cc 100644
--- a/chrome/browser/ui/tabs/tab_style.h
+++ b/chrome/browser/ui/tabs/tab_style.h
@@ -139,13 +139,13 @@
 
   static const TabStyle* Get();
 
- protected:
-  // Avoid implicitly-deleted constructor.
-  TabStyle() = default;
-
   // Returns how far from the leading and trailing edges of a tab the contents
   // should actually be laid out.
   int GetContentsHorizontalInsetSize() const;
+
+ protected:
+  // Avoid implicitly-deleted constructor.
+  TabStyle() = default;
 };
 
 #endif  // CHROME_BROWSER_UI_TABS_TAB_STYLE_H_
diff --git a/chrome/browser/ui/views/autofill/payments/virtual_card_enroll_bubble_views.cc b/chrome/browser/ui/views/autofill/payments/virtual_card_enroll_bubble_views.cc
index b381224a..928c7f99 100644
--- a/chrome/browser/ui/views/autofill/payments/virtual_card_enroll_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/payments/virtual_card_enroll_bubble_views.cc
@@ -178,6 +178,8 @@
       card_name_4digits_view->AddChildView(std::make_unique<views::Label>(
           card.CardNameForAutofillDisplay(),
           views::style::CONTEXT_DIALOG_BODY_TEXT, views::style::STYLE_PRIMARY));
+  card_name_label->SetHorizontalAlignment(
+      gfx::HorizontalAlignment::ALIGN_TO_HEAD);
   card_name_4digits_view->SetFlexForView(card_name_label, /*flex=*/1);
   card_name_4digits_view->AddChildView(std::make_unique<views::Label>(
       card.ObfuscatedNumberWithVisibleLastFourDigits(),
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc
index 0b07047..b72ef20 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc
@@ -46,9 +46,11 @@
 // The maximum number of buttons (excluding the overflow menu button) that can
 // appear in the SavedTabGroupBar.
 constexpr int kMaxVisibleButtons = 4;
-
 // The amount of padding between elements listed in the overflow menu.
 const int kOverflowMenuButtonPadding = 8;
+// The padding at the top and bottom of the bar used to center all displayed
+// buttons.
+constexpr int kButtonPadding = 2;
 
 SavedTabGroupModel* GetSavedTabGroupModelFromBrowser(Browser* browser) {
   DCHECK(browser);
@@ -132,8 +134,9 @@
   std::unique_ptr<views::LayoutManager> layout_manager =
       std::make_unique<views::BoxLayout>(
           views::BoxLayout::Orientation::kHorizontal,
-          gfx::Insets::TLBR(0, GetLayoutConstant(TOOLBAR_ELEMENT_PADDING) / 2,
-                            0, 0),
+          gfx::Insets::TLBR(kButtonPadding,
+                            GetLayoutConstant(TOOLBAR_ELEMENT_PADDING) / 2,
+                            kButtonPadding, 0),
           GetLayoutConstant(TOOLBAR_ELEMENT_PADDING));
   SetLayoutManager(std::move(layout_manager));
 
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.cc
index 2481285..abb9bd9 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.cc
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.cc
@@ -12,6 +12,7 @@
 #include "base/cxx20_to_address.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_forward.h"
+#include "cc/paint/paint_flags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/favicon/favicon_utils.h"
 #include "chrome/browser/ui/bookmarks/bookmark_utils_desktop.h"
@@ -44,9 +45,14 @@
 #include "ui/base/models/image_model.h"
 #include "ui/base/theme_provider.h"
 #include "ui/base/ui_base_types.h"
+#include "ui/color/color_id.h"
 #include "ui/gfx/animation/slide_animation.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/point_f.h"
+#include "ui/views/background.h"
+#include "ui/views/border.h"
 #include "ui/views/controls/button/label_button_border.h"
 #include "ui/views/controls/button/menu_button.h"
 #include "ui/views/controls/highlight_path_generator.h"
@@ -60,14 +66,16 @@
                                       kMoveGroupToNewWindowMenuItem);
 
 namespace {
-constexpr float kBorderRadius = 4.5f;
-constexpr float kButtonRadius = 5.0f;
-constexpr float kBorderThickness = 2.0f;
-
-// This value comes from tab_group_style.cc (kEmptyChipSize). Since this
-// button and the tab_group_header are rendered on different surfaces, keep
-// the value here in case we want to change one but not the other.
-constexpr float kCircleRadius = 14.0f;
+// The max height of the button and the max width of a button with no title.
+constexpr int kButtonSize = 24;
+// The corner radius for the button.
+constexpr float kButtonRadius = 4.0f;
+// The amount of insets from the buttons border.
+constexpr float kInsets = 5.0f;
+// The width of the outline of the button when open in the Tab Strip.
+constexpr float kBorderThickness = 1.0f;
+// The radius for the circle that is displayed for buttons with no title.
+constexpr float kCircleRadius = 7.0f;
 }  // namespace
 
 SavedTabGroupButton::SavedTabGroupButton(
@@ -100,19 +108,7 @@
   SetTooltipText(group.title());
   SetID(VIEW_ID_BOOKMARK_BAR_ELEMENT);
   SetProperty(views::kElementIdentifierKey, kSavedTabGroupButtonElementId);
-
-  // Since the theme provider is not currently available when instantiated the
-  // text color will be set to a placeholder color now. the text color will then
-  // be enabled when a theme provider can provide one onpaint.
-  SetEnabledTextColors(gfx::kPlaceholderColor);
-
-  SetMaxSize(gfx::Size(bookmark_button_util::kMaxButtonWidth, 0));
-
-  ConfigureInkDropForToolbar(this);
-  SetImageLabelSpacing(ChromeLayoutProvider::Get()->GetDistanceMetric(
-      ChromeDistanceMetric::DISTANCE_RELATED_LABEL_HORIZONTAL_LIST));
-  views::InstallRoundRectHighlightPathGenerator(this, GetInsets(),
-                                                kBorderRadius);
+  SetMaxSize(gfx::Size(bookmark_button_util::kMaxButtonWidth, kButtonSize));
 
   show_animation_ = std::make_unique<gfx::SlideAnimation>(this);
   if (!animations_enabled) {
@@ -123,15 +119,11 @@
     show_animation_->Show();
   }
 
-  int button_height = GetLayoutConstant(BOOKMARK_BAR_BUTTON_HEIGHT);
-  if (GetText().empty()) {
-    // When the text is empty force the button to have square dimensions.
-    // Likewise, we already have a constant that denotes the standard button
-    // height for all elements in the bookmarks bar. As such, we will use this
-    // constant for the width of the button to create a square that will
-    // comfortably fit in the bookmarks bar.
-    SetPreferredSize(gfx::Size(button_height, button_height));
-  }
+  ConfigureInkDropForToolbar(this);
+  SetImageLabelSpacing(ChromeLayoutProvider::Get()->GetDistanceMetric(
+      ChromeDistanceMetric::DISTANCE_RELATED_LABEL_HORIZONTAL_LIST));
+  views::InstallRoundRectHighlightPathGenerator(this, gfx::Insets(0),
+                                                kButtonRadius);
 
   set_drag_controller(this);
 }
@@ -148,17 +140,7 @@
   tabs_.clear();
   tabs_ = group.saved_tabs();
 
-  int button_height = GetLayoutConstant(BOOKMARK_BAR_BUTTON_HEIGHT);
-  if (GetText().empty()) {
-    // When the text is empty force the button to have square dimensions.
-    // Likewise, we already have a constant that denotes the standard button
-    // height for all elements in the bookmarks bar. As such, we will use this
-    // constant for the width of the button to create a square that will
-    // comfortably fit in the bookmarks bar.
-    SetPreferredSize(gfx::Size(button_height, button_height));
-  } else {
-    SetPreferredSize(CalculatePreferredSize());
-  }
+  UpdateButtonLayout();
 }
 
 std::u16string SavedTabGroupButton::GetTooltipText(const gfx::Point& p) const {
@@ -179,46 +161,59 @@
   }
 }
 
-void SavedTabGroupButton::OnPaintBackground(gfx::Canvas* canvas) {
-  const ui::ColorProvider* const cp = GetColorProvider();
-  gfx::PointF center_point_f = gfx::PointF(width() / 2, height() / 2);
-  gfx::RectF rect_f = gfx::RectF(width(), height());
-  rect_f.Inset(1.0f);
+void SavedTabGroupButton::PaintButtonContents(gfx::Canvas* canvas) {
+  if (!GetText().empty()) {
+    return;
+  }
 
-  // Relies on logic in theme_helper.cc to determine dark/light palette.
-  SkColor background_color =
-      cp->GetColor(GetTabGroupBookmarkColorId(tab_group_color_id_));
+  // When the title is empty, we draw a circle similar to the tab group
+  // header when there is no title.
+  const ui::ColorProvider* const cp = GetColorProvider();
   SkColor text_and_outline_color =
       cp->GetColor(GetTabGroupDialogColorId(tab_group_color_id_));
-  SetEnabledTextColors(text_and_outline_color);
 
-  // Draw background.
+  // Draw circle.
   cc::PaintFlags flags;
   flags.setAntiAlias(true);
   flags.setStyle(cc::PaintFlags::kFill_Style);
-  flags.setColor(background_color);
-  canvas->DrawRoundRect(rect_f, kButtonRadius, flags);
-
-  // At the time this was written, all non-background elements share the same
-  // color. As such, we can set the color once here.
   flags.setColor(text_and_outline_color);
 
+  const gfx::PointF center_point_f = gfx::PointF(width() / 2, height() / 2);
+  canvas->DrawCircle(center_point_f, kCircleRadius, flags);
+}
+
+void SavedTabGroupButton::UpdateButtonLayout() {
   if (GetText().empty()) {
-    // When the title is empty, we draw a circle similar to the tab group header
-    // when there is no title.
-    canvas->DrawCircle(center_point_f, kCircleRadius / 2, flags);
+    // When the text is empty force the button to have square dimensions.
+    // Likewise, we already have a constant that denotes the standard button
+    // height for all elements in the bookmarks bar. As such, we will use
+    // this constant for the width of the button to create a square that will
+    // comfortably fit in the bookmarks bar.
+    SetPreferredSize(gfx::Size(kButtonSize, kButtonSize));
+  } else {
+    SetPreferredSize(CalculatePreferredSize());
   }
 
-  // Draw border.
-  flags.setStyle(cc::PaintFlags::kStroke_Style);
-  flags.setStrokeWidth(kBorderThickness);
-  if (local_group_id_.has_value()) {
-    canvas->DrawRoundRect(rect_f, kBorderRadius, flags);
-  }
+  // Relies on logic in theme_helper.cc to determine dark/light palette.
+  ui::ColorId text_and_outline_color =
+      GetTabGroupDialogColorId(tab_group_color_id_);
 
-  if (GetState() == STATE_HOVERED) {
-    // TODO: Draw a box shadow on hover.
-    return;
+  ui::ColorId background_color =
+      GetTabGroupBookmarkColorId(tab_group_color_id_);
+
+  SetEnabledTextColorIds(GetTabGroupDialogColorId(tab_group_color_id_));
+  SetBackground(views::CreateThemedRoundedRectBackground(background_color,
+                                                         kButtonRadius));
+
+  // Only draw a border if the group is open in the tab strip.
+  if (!local_group_id_.has_value()) {
+    SetBorder(views::CreateEmptyBorder(gfx::Insets(kInsets)));
+  } else {
+    std::unique_ptr<views::Border> border =
+        views::CreateThemedRoundedRectBorder(kBorderThickness, kButtonRadius,
+                                             text_and_outline_color);
+    SetBorder(
+        views::CreatePaddedBorder(std::move(border), gfx::Insets(kInsets)));
   }
 }
 
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.h b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.h
index 2cf1fc6..e01a688 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.h
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_button.h
@@ -50,7 +50,7 @@
   // views::MenuButton:
   std::u16string GetTooltipText(const gfx::Point& p) const override;
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
-  void OnPaintBackground(gfx::Canvas* canvas) override;
+  void PaintButtonContents(gfx::Canvas* canvas) override;
   std::unique_ptr<views::LabelButtonBorder> CreateDefaultBorder()
       const override;
   void OnThemeChanged() override;
@@ -67,8 +67,6 @@
   // Updates the buttons visuals (title and color) alongside its list of tabs
   // displayed in the context menu.
   void UpdateButtonData(const SavedTabGroup& group);
-  void RemoveButtonOutline();
-  bool HasButtonOutline() const;
 
   tab_groups::TabGroupColorId tab_group_color_id() {
     return tab_group_color_id_;
@@ -80,6 +78,7 @@
   DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kMoveGroupToNewWindowMenuItem);
 
  private:
+  void UpdateButtonLayout();
   void TabMenuItemPressed(const GURL& url, int event_flags);
   void MoveGroupToNewWindowPressed(int event_flags);
   void DeleteGroupPressed(int event_flags);
@@ -98,8 +97,8 @@
   // The local guid used to identify the group in the tabstrip if it is open.
   absl::optional<tab_groups::TabGroupId> local_group_id_;
 
-  // The tabs to be displayed in the context menu. Currently supports tab title,
-  // url, and favicon.
+  // The tabs to be displayed in the context menu. Currently supports tab
+  // title, url, and favicon.
   std::vector<SavedTabGroupTab> tabs_;
 
   const raw_ref<Browser> browser_;
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
index d7fad5b..23d0611 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
@@ -7,7 +7,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "chrome/browser/themes/theme_service_aura_linux.h"
 #include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/views/dark_mode_manager_linux.h"
 #include "chrome/browser/ui/views/theme_profile_key.h"
 #include "ui/base/buildflags.h"
 #include "ui/base/cursor/cursor_factory.h"
@@ -19,6 +18,10 @@
 #include "ui/native_theme/native_theme.h"
 #include "ui/ozone/public/ozone_platform.h"
 
+#if defined(USE_DBUS)
+#include "chrome/browser/ui/views/dark_mode_manager_linux.h"
+#endif
+
 namespace {
 
 class LinuxUiGetterImpl : public ui::LinuxUiGetter {
@@ -57,8 +60,9 @@
     UMA_HISTOGRAM_ENUMERATION("Linux.SystemTheme.Default",
                               linux_ui_theme->GetNativeTheme()->system_theme());
   }
-
+#if defined(USE_DBUS)
   dark_mode_manager_ = std::make_unique<ui::DarkModeManagerLinux>();
+#endif
 }
 
 void ChromeBrowserMainExtraPartsViewsLinux::PreCreateThreads() {
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h
index 6deb520..bc9167b 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h
@@ -13,7 +13,9 @@
 
 namespace ui {
 class LinuxUiGetter;
+#if defined(USE_DBUS)
 class DarkModeManagerLinux;
+#endif
 }
 
 // Extra parts, which are used by both Ozone/X11/Wayland and inherited by the
@@ -42,8 +44,9 @@
   absl::optional<display::ScopedDisplayObserver> display_observer_;
 
   std::unique_ptr<ui::LinuxUiGetter> linux_ui_getter_;
-
+#if defined(USE_DBUS)
   std::unique_ptr<ui::DarkModeManagerLinux> dark_mode_manager_;
+#endif
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_CHROME_BROWSER_MAIN_EXTRA_PARTS_VIEWS_LINUX_H_
diff --git a/chrome/browser/ui/views/chrome_layout_provider.cc b/chrome/browser/ui/views/chrome_layout_provider.cc
index 077116c..ede4d877 100644
--- a/chrome/browser/ui/views/chrome_layout_provider.cc
+++ b/chrome/browser/ui/views/chrome_layout_provider.cc
@@ -6,9 +6,12 @@
 
 #include <algorithm>
 
+#include "base/feature_list.h"
 #include "base/logging.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
+#include "components/omnibox/common/omnibox_features.h"
 #include "ui/base/pointer/touch_ui_controller.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/gfx/shadow_value.h"
 
 namespace {
@@ -69,9 +72,16 @@
     case INSETS_TOAST:
       return gfx::Insets::VH(0, kHarmonyLayoutUnit);
     case INSETS_OMNIBOX_PILL_BUTTON:
-      return touch_ui
-                 ? gfx::Insets::VH(kHarmonyLayoutUnit / 2, kHarmonyLayoutUnit)
-                 : gfx::Insets::VH(5, 12);
+      if ((base::FeatureList::IsEnabled(omnibox::kCr2023ActionChips) ||
+           features::GetChromeRefresh2023Level() ==
+               features::ChromeRefresh2023Level::kLevel2) &&
+          !touch_ui) {
+        return gfx::Insets::VH(4, 8);
+      } else {
+        return touch_ui
+                   ? gfx::Insets::VH(kHarmonyLayoutUnit / 2, kHarmonyLayoutUnit)
+                   : gfx::Insets::VH(5, 12);
+      }
     case INSETS_PAGE_INFO_HOVER_BUTTON: {
       const gfx::Insets insets =
           LayoutProvider::GetInsetsMetric(views::INSETS_LABEL_BUTTON);
diff --git a/chrome/browser/ui/views/device_id/pen_id_browsertest_win.cc b/chrome/browser/ui/views/device_id/pen_id_browsertest_win.cc
index bcfa78bb..ed01e0b 100644
--- a/chrome/browser/ui/views/device_id/pen_id_browsertest_win.cc
+++ b/chrome/browser/ui/views/device_id/pen_id_browsertest_win.cc
@@ -16,6 +16,7 @@
 #include "base/win/core_winrt_util.h"
 #include "base/win/hstring_reference.h"
 #include "base/win/scoped_hstring.h"
+#include "base/win/windows_version.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -76,6 +77,11 @@
 };
 
 void PenIdBrowserTest::SetUpOnMainThread() {
+  if (base::win::GetVersion() < base::win::Version::WIN10_21H2 ||
+      (base::win::GetVersion() == base::win::Version::WIN10_21H2 &&
+       base::win::OSInfo::GetInstance()->version_number().patch < 1503)) {
+    GTEST_SKIP() << "Pen Device Api not supported on this machine";
+  }
   https_server_.reset(
       new net::EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTPS));
   https_server_->ServeFilesFromSourceDirectory("chrome/test/data");
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_site_permissions_page_view_unittest.cc b/chrome/browser/ui/views/extensions/extensions_menu_site_permissions_page_view_unittest.cc
index b17d763..80ae89f 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_site_permissions_page_view_unittest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_site_permissions_page_view_unittest.cc
@@ -276,15 +276,10 @@
 // permissions controls (e.g restricted site) closes the site permissions page.
 TEST_F(ExtensionsSitePermissionsPageViewUnitTest,
        PageNavigationWithMenuOpen_UserLosesRuntimeHostPermissionsControls) {
-  content::WebContentsTester* web_contents_tester =
-      AddWebContentsAndGetTester();
-
   auto extension =
       InstallExtensionWithHostPermissions("Extension", {"<all_urls>"});
 
-  const GURL url("http://www.non-restricted.com");
-  web_contents_tester->NavigateAndCommit(url);
-  WaitForAnimation();
+  NavigateAndCommit("http://www.non-restricted.com");
 
   ShowSitePermissionsPage(extension->id());
   EXPECT_FALSE(IsMainPageOpened());
@@ -292,9 +287,7 @@
 
   // While the menu is open, navigate to an url where extension should not have
   // a site permissions page.
-  const GURL restricted_url("chrome://extensions");
-  web_contents_tester->NavigateAndCommit(restricted_url);
-  WaitForAnimation();
+  NavigateAndCommit("chrome://extensions");
 
   // Menu should navigate back to main page since site permissions page should
   // not be visible for the new url.
@@ -306,15 +299,10 @@
 // permissions controls updates the page contents.
 TEST_F(ExtensionsSitePermissionsPageViewUnitTest,
        PageNavigationWithMenuOpen_UserMaintainsRuntimeHostPermissionsControls) {
-  content::WebContentsTester* web_contents_tester =
-      AddWebContentsAndGetTester();
-
   auto extension =
       InstallExtensionWithHostPermissions("Extension", {"<all_urls>"});
 
-  const GURL url_a("http://www.a.com");
-  web_contents_tester->NavigateAndCommit(url_a);
-  WaitForAnimation();
+  NavigateAndCommit("http://www.a.com");
 
   ShowSitePermissionsPage(extension->id());
   EXPECT_FALSE(IsMainPageOpened());
@@ -322,9 +310,7 @@
 
   // While the menu is open, navigate to an url where extension also should have
   // a site permissions page.
-  const GURL url_b("http://www.b.com");
-  web_contents_tester->NavigateAndCommit(url_b);
-  WaitForAnimation();
+  NavigateAndCommit("http://www.b.com");
 
   // Menu should stay open in site permissions page for `extension`.
   EXPECT_FALSE(IsMainPageOpened());
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view_interactive_uitest.cc b/chrome/browser/ui/views/extensions/extensions_menu_view_interactive_uitest.cc
index b20d211..335e776 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_view_interactive_uitest.cc
@@ -9,6 +9,7 @@
 #include "base/ranges/algorithm.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
+#include "chrome/browser/extensions/browsertest_util.h"
 #include "chrome/browser/extensions/chrome_test_extension_loader.h"
 #include "chrome/browser/extensions/extension_action_runner.h"
 #include "chrome/browser/extensions/extension_context_menu_model.h"
@@ -16,6 +17,7 @@
 #include "chrome/browser/extensions/install_verifier.h"
 #include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/extensions/extension_install_ui_default.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
 #include "chrome/browser/ui/views/controls/hover_button.h"
@@ -810,9 +812,8 @@
   auto extension = extensions().back();
   extensions::ScriptingPermissionsModifier modifier(profile(), extension);
   modifier.SetWithholdHostPermissions(true);
-
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(
-      browser(), embedded_test_server()->GetURL("example.com", "/empty.html")));
+  GURL url = embedded_test_server()->GetURL("/simple.html");
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
 
   ShowUi("");
   VerifyUi();
@@ -824,6 +825,11 @@
       extensions::ExtensionActionRunner::GetForWebContents(web_contents);
 
   EXPECT_TRUE(action_runner->WantsToRun(extension.get()));
+  extensions::SitePermissionsHelper permissions_helper(browser()->profile());
+  // A refresh should be needed in order to run the actions and inject the
+  // content script.
+  EXPECT_TRUE(permissions_helper.PageNeedsRefreshToRun(
+      action_runner->GetBlockedActions(extension->id())));
 
   TriggerSingleExtensionButton();
 
@@ -838,18 +844,29 @@
 
   const bool accept_reload_dialog = GetParam();
   if (accept_reload_dialog) {
-    content::TestNavigationObserver observer(web_contents);
     action_bubble->AcceptDialog();
     EXPECT_TRUE(web_contents->IsLoading());
     // Wait for reload to finish.
-    observer.WaitForNavigationFinished();
-    EXPECT_TRUE(observer.last_navigation_succeeded());
-    // After reload the extension should be allowed to run.
+    ASSERT_TRUE(content::WaitForLoadStop(web_contents));
+    // After reload the extension should run.
+    EXPECT_TRUE(DidInjectScript(web_contents));
     EXPECT_FALSE(action_runner->WantsToRun(extension.get()));
   } else {
     action_bubble->CancelDialog();
     EXPECT_FALSE(web_contents->IsLoading());
+    // The extension permission should have been applied at this point, but the
+    // extension's script and blocked actions should not inject/run since a
+    // reload is needed.
+    EXPECT_EQ(permissions_helper.GetSiteInteraction(*extension, web_contents),
+              extensions::SitePermissionsHelper::SiteInteraction::kGranted);
+    EXPECT_FALSE(DidInjectScript(web_contents));
     EXPECT_TRUE(action_runner->WantsToRun(extension.get()));
+    // Manual reload should then allow for script inject and blocked actions to
+    // run.
+    chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
+    ASSERT_TRUE(content::WaitForLoadStop(web_contents));
+    EXPECT_TRUE(DidInjectScript(web_contents));
+    EXPECT_FALSE(action_runner->WantsToRun(extension.get()));
   }
 }
 
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container_interactive_uitest.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_container_interactive_uitest.cc
index 12e9545..c5c4a96 100644
--- a/chrome/browser/ui/views/extensions/extensions_toolbar_container_interactive_uitest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container_interactive_uitest.cc
@@ -762,7 +762,7 @@
     EXPECT_TRUE(observer.last_navigation_succeeded());
   }
 
-  // Access to |url| should have been withheld.
+  // Access to `url` should have been withheld.
   blocked_action_waiter.WaitAndReset();
   EXPECT_TRUE(runner->WantsToRun(extension()));
   extensions::PermissionsManager* permissions_manager =
@@ -818,11 +818,11 @@
       extensions::ExtensionContextMenuModel::PAGE_ACCESS_RUN_ON_ALL_SITES,
       0 /* event_flags */);
 
-  // Permissions to the extension shouldn't have been granted, and the extension
-  // should still be in wants-to-run state.
+  // Permissions to the extension should now be been granted, and the
+  // extension should still be in wants-to-run state because we didn't refresh
+  // the page.
   EXPECT_TRUE(runner->WantsToRun(extension()));
-  EXPECT_FALSE(
-      permissions_manager->HasGrantedHostPermission(*extension(), url));
+  EXPECT_TRUE(permissions_manager->HasGrantedHostPermission(*extension(), url));
   EXPECT_EQ(tooltip_wants_access, GetActionTooltip());
   EXPECT_FALSE(injection_listener.was_satisfied());
 }
@@ -921,10 +921,28 @@
   raw_ptr<content::WebContents, DanglingUntriaged> web_contents_ = nullptr;
 };
 
-// Tests that clicking the request access button grants one time access to the
-// extensions listed which requires a page refresh.
-IN_PROC_BROWSER_TEST_F(ExtensionsToolbarContainerFeatureUITest,
-                       ClickingRequestAccessButtonRunsAction_RefreshRequired) {
+class ExtensionsToolbarContainerFeatureUIReloadBubbleAcceptanceTest
+    : public ExtensionsToolbarContainerFeatureUITest,
+      public testing::WithParamInterface<bool> {};
+
+INSTANTIATE_TEST_SUITE_P(
+    ,
+    ExtensionsToolbarContainerFeatureUIReloadBubbleAcceptanceTest,
+    // False does not accept the refresh bubble, true accepts.
+    testing::Bool(),
+    [](const testing::TestParamInfo<
+        ExtensionsToolbarContainerFeatureUIReloadBubbleAcceptanceTest::
+            ParamType>& info) {
+      return info.param ? "ReloadBubbleAccepted" : "ReloadBubbleDismissed";
+    });
+
+// Tests that when clicking the request access button (and a refresh should be
+// required to run blocked actions) it grants one time access to the extensions
+// listed. This also tests when that button is not clicked the one-time access
+// is granted, but blocked actions are not run until the page is reloaded.
+IN_PROC_BROWSER_TEST_P(
+    ExtensionsToolbarContainerFeatureUIReloadBubbleAcceptanceTest,
+    ClickingRequestAccessButtonRunsAction_RefreshRequired) {
   auto extensionA = InstallExtensionWithHostPermissions(
       "A Extension", "<all_urls>",
       /*content_script_run_location=*/"document_start");
@@ -969,33 +987,32 @@
   // dialog will appear since extension A needs a page reload to run its action.
   auto* action_runner =
       extensions::ExtensionActionRunner::GetForWebContents(web_contents());
-  action_runner->accept_bubble_for_testing(false);
+  const bool kReloadBubbleAccepted = GetParam();
+  action_runner->accept_bubble_for_testing(kReloadBubbleAccepted);
+  ExtensionTestMessageListener script_injection_listener("injection succeeded");
   ClickButton(request_access_button());
   WaitForAnimation();
 
-  // Site interaction should stay the same because dialog wasn't accepted.
-  EXPECT_TRUE(request_access_button()->GetVisible());
-  EXPECT_EQ(permissions_helper.GetSiteInteraction(*extensionA, web_contents()),
-            SiteInteraction::kWithheld);
-  EXPECT_EQ(permissions_helper.GetSiteInteraction(*extensionB, web_contents()),
-            SiteInteraction::kWithheld);
-  EXPECT_EQ(permissions_helper.GetSiteInteraction(*extensionC, web_contents()),
-            SiteInteraction::kGranted);
-
-  // Click the request access button again, and this time accept the dialog and
-  // wait for the page refresh.
-  content::TestNavigationObserver observer(web_contents());
-  extensions::ExtensionActionRunner::GetForWebContents(web_contents())
-      ->accept_bubble_for_testing(true);
-  ClickButton(request_access_button());
-  observer.WaitForNavigationFinished();
-  EXPECT_TRUE(observer.last_navigation_succeeded());
-  WaitForAnimation();
+  if (kReloadBubbleAccepted) {
+    // Site interaction should change and script should be injected since
+    // permission granted and page was reloaded. The request access button
+    // should be hidden since we reloaded.
+    EXPECT_TRUE(script_injection_listener.WaitUntilSatisfied());
+    EXPECT_FALSE(request_access_button()->GetVisible());
+  } else {
+    // Site interaction should change but script should not be injected
+    // since permission was granted but page was reloaded. The request access
+    // button should remain visible since we didn't reload.
+    EXPECT_TRUE(request_access_button()->GetVisible());
+    // TODO(crbug.com/1400812): Is there a way to confirm we didn't inject the
+    // script besides reusing the
+    // chrome/test/data/extensions/blocked_actions/content_scripts/ test
+    // extension?
+  }
 
   // Extension A and B should have active site interaction, since their actions
-  // ran, but keep the same site access since this is a one-time access grant.
-  // The request access button should be hidden.
-  EXPECT_FALSE(request_access_button()->GetVisible());
+  // ran, but keep the same user site access since this is a one-time access
+  // grant.
   EXPECT_EQ(permissions_helper.GetSiteInteraction(*extensionA, web_contents()),
             SiteInteraction::kGranted);
   EXPECT_EQ(permissions_helper.GetSiteInteraction(*extensionB, web_contents()),
@@ -1009,14 +1026,14 @@
   EXPECT_EQ(permissions_manager->GetUserSiteAccess(*extensionC, url),
             UserSiteAccess::kOnAllSites);
 
-  // Re-navigate to the same url. Refreshing the page doesn't remove the action,
-  // thus we need to navigate to another page and then navigate back to the
-  // original page.
+  // Re-navigate to the same url. Refreshing the page doesn't remove the
+  // action, thus we need to navigate to another page and then navigate back
+  // to the original page.
   NavigateToUrl(embedded_test_server()->GetURL("other.com", "/title1.html"));
   NavigateToUrl(url);
 
-  // Extension A and B should have pending access again and the request access
-  // button should be visible.
+  // Extension A and B should have pending access again and the request
+  // access button should be visible.
   EXPECT_TRUE(request_access_button()->GetVisible());
   EXPECT_THAT(request_access_button()->GetExtensionIdsForTesting(),
               testing::ElementsAre(extensionA->id(), extensionB->id()));
@@ -1026,6 +1043,12 @@
             SiteInteraction::kWithheld);
   EXPECT_EQ(permissions_helper.GetSiteInteraction(*extensionC, web_contents()),
             SiteInteraction::kGranted);
+  EXPECT_EQ(permissions_manager->GetUserSiteAccess(*extensionA, url),
+            UserSiteAccess::kOnClick);
+  EXPECT_EQ(permissions_manager->GetUserSiteAccess(*extensionB, url),
+            UserSiteAccess::kOnClick);
+  EXPECT_EQ(permissions_manager->GetUserSiteAccess(*extensionC, url),
+            UserSiteAccess::kOnAllSites);
 }
 
 // Tests that clicking the request access button grants one time access to the
@@ -1076,12 +1099,14 @@
 
   // Click the request access button to grant one-time access. Since no
   // extensions need page refresh to run their actions, it immediately grants
-  // access.
+  // access and the script is injected.
+  ExtensionTestMessageListener script_injection_listener("injection succeeded");
   ClickButton(request_access_button());
+  EXPECT_TRUE(script_injection_listener.WaitUntilSatisfied());
   WaitForAnimation();
 
-  // Extension A and B should have active site interaction, since their action
-  // run, but keep the same site access since this is a one-time access grant.
+  // Extension A and B should have active site interaction, since their actions
+  // ran, but keep the same site access since this is a one-time access grant.
   // The request access button should be hidden.
   EXPECT_FALSE(request_access_button()->GetVisible());
   EXPECT_EQ(permissions_helper.GetSiteInteraction(*extensionA, web_contents()),
diff --git a/chrome/browser/ui/views/extensions/reload_page_dialog.cc b/chrome/browser/ui/views/extensions/reload_page_dialog.cc
index 3fc8a82..e2be65c 100644
--- a/chrome/browser/ui/views/extensions/reload_page_dialog.cc
+++ b/chrome/browser/ui/views/extensions/reload_page_dialog.cc
@@ -20,7 +20,7 @@
     const std::vector<ToolbarActionViewController*> actions) {
   if (actions.size() == 0) {
     return l10n_util::GetStringUTF16(
-        IDS_EXTENSION_RELOAD_PAGE_BUBBLE_UPDATE_PERMISSIONS_TITLE);
+        IDS_EXTENSION_SITE_RELOAD_PAGE_BUBBLE_HEADING);
   }
   if (actions.size() == 1) {
     return l10n_util::GetStringFUTF16(
@@ -71,8 +71,8 @@
     }
   } else {
     dialog_builder
-        .SetTitle(
-            l10n_util::GetStringUTF16(IDS_EXTENSION_RELOAD_PAGE_BUBBLE_HEADING))
+        .SetTitle(l10n_util::GetStringUTF16(
+            IDS_EXTENSION_SITE_RELOAD_PAGE_BUBBLE_HEADING))
         .AddOkButton(
             base::BindOnce(std::move(callback)),
             ui::DialogModelButton::Params().SetLabel(l10n_util::GetStringUTF16(
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index 995186c..dc7d4a3e 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -346,7 +346,7 @@
     params.types_enabled.push_back(PageActionIconType::kBookmarkStar);
 
   params.icon_color = OmniboxFieldTrial::IsChromeRefreshIconsEnabled()
-                          ? ui::kColorSysOnSurfaceSubtle
+                          ? color_provider->GetColor(kColorPageActionIcon)
                           : icon_color;
   params.between_icon_spacing =
       OmniboxFieldTrial::IsChromeRefreshIconsEnabled() ? 8 : 0;
@@ -798,8 +798,10 @@
   if (!IsInitialized())
     return;
 
-  const SkColor icon_color =
-      GetColorProvider()->GetColor(kColorOmniboxResultsIcon);
+  const SkColor icon_color = GetColorProvider()->GetColor(
+      OmniboxFieldTrial::IsChromeRefreshIconsEnabled()
+          ? kColorPageActionIcon
+          : kColorOmniboxResultsIcon);
   page_action_icon_controller_->SetIconColor(icon_color);
   for (ContentSettingImageView* image_view : content_setting_views_)
     image_view->SetIconColor(icon_color);
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view.cc b/chrome/browser/ui/views/location_bar/location_icon_view.cc
index 84dbfb5..b042ea4 100644
--- a/chrome/browser/ui/views/location_bar/location_icon_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_icon_view.cc
@@ -25,6 +25,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/common/constants.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -75,9 +76,10 @@
     views::InkDrop::Get(this)->SetLayerRegion(views::LayerRegion::kAbove);
     views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating(
         [](views::View* host) -> std::unique_ptr<views::InkDropRipple> {
-          const SkColor pressed_color = host->GetColorProvider()->GetColor(
-              ui::kColorSysStateRippleNeutralOnSubtle);
+          const SkColor pressed_color =
+              host->GetColorProvider()->GetColor(kColorPageInfoIconPressed);
           const float pressed_alpha = SkColorGetA(pressed_color);
+
           return std::make_unique<views::FloodFillInkDropRipple>(
               views::InkDrop::Get(host), host->size(),
               host->GetLocalBounds().CenterPoint(),
@@ -88,9 +90,10 @@
 
     views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating(
         [](views::View* host) {
-          const SkColor hover_color = host->GetColorProvider()->GetColor(
-              ui::kColorSysStateHoverDimBlendProtection);
+          const SkColor hover_color =
+              host->GetColorProvider()->GetColor(kColorPageInfoIconHover);
           const float hover_alpha = SkColorGetA(hover_color);
+
           auto ink_drop_highlight = std::make_unique<views::InkDropHighlight>(
               host->size(), host->height() / 2,
               gfx::PointF(host->GetLocalBounds().CenterPoint()),
@@ -300,8 +303,7 @@
 void LocationIconView::UpdateBackground() {
   if (OmniboxFieldTrial::IsChromeRefreshIconsEnabled()) {
     SetBackground(views::CreateRoundedRectBackground(
-        GetColorProvider()->GetColor(ui::kColorSysBaseContainerElevated),
-        height() / 2));
+        GetColorProvider()->GetColor(kColorPageInfoBackground), height() / 2));
   }
 }
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc b/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc
index 42f7e06..696b739 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.h"
 
+#include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
 #include "base/ranges/algorithm.h"
@@ -19,6 +20,7 @@
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/browser/vector_icons.h"
+#include "components/omnibox/common/omnibox_features.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/vector_icons/vector_icons.h"
 #include "third_party/metrics_proto/omnibox_event.pb.h"
@@ -26,6 +28,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/base/window_open_disposition_utils.h"
 #include "ui/gfx/color_utils.h"
@@ -57,12 +60,22 @@
     SetTriggerableEventFlags(GetTriggerableEventFlags() |
                              ui::EF_MIDDLE_MOUSE_BUTTON);
     views::InstallPillHighlightPathGenerator(this);
-    SetImageLabelSpacing(ChromeLayoutProvider::Get()->GetDistanceMetric(
-        DISTANCE_RELATED_LABEL_HORIZONTAL_LIST));
-    SetCustomPadding(ChromeLayoutProvider::Get()->GetInsetsMetric(
-        INSETS_OMNIBOX_PILL_BUTTON));
-    SetCornerRadius(GetInsets().height() +
-                    GetLayoutConstant(LOCATION_BAR_ICON_SIZE));
+
+    if (base::FeatureList::IsEnabled(omnibox::kCr2023ActionChips) ||
+        features::GetChromeRefresh2023Level() ==
+            features::ChromeRefresh2023Level::kLevel2) {
+      SetImageLabelSpacing(4);
+      SetCustomPadding(ChromeLayoutProvider::Get()->GetInsetsMetric(
+          INSETS_OMNIBOX_PILL_BUTTON));
+      SetCornerRadius(GetLayoutConstant(TOOLBAR_CORNER_RADIUS));
+    } else {
+      SetImageLabelSpacing(ChromeLayoutProvider::Get()->GetDistanceMetric(
+          DISTANCE_RELATED_LABEL_HORIZONTAL_LIST));
+      SetCustomPadding(ChromeLayoutProvider::Get()->GetInsetsMetric(
+          INSETS_OMNIBOX_PILL_BUTTON));
+      SetCornerRadius(GetInsets().height() +
+                      GetLayoutConstant(LOCATION_BAR_ICON_SIZE));
+    }
 
     auto* const ink_drop = views::InkDrop::Get(this);
     ink_drop->SetHighlightOpacity(kOmniboxOpacityHovered);
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_view.cc b/chrome/browser/ui/views/page_action/page_action_icon_view.cc
index 30b4d41..5d05eff7 100644
--- a/chrome/browser/ui/views/page_action/page_action_icon_view.cc
+++ b/chrome/browser/ui/views/page_action/page_action_icon_view.cc
@@ -88,8 +88,8 @@
     views::InkDrop::Get(this)->SetLayerRegion(views::LayerRegion::kAbove);
     views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating(
         [](views::View* host) -> std::unique_ptr<views::InkDropRipple> {
-          const SkColor pressed_color = host->GetColorProvider()->GetColor(
-              ui::kColorSysStateRippleNeutralOnSubtle);
+          const SkColor pressed_color =
+              host->GetColorProvider()->GetColor(kColorPageActionIconPressed);
           const float pressed_alpha = SkColorGetA(pressed_color);
           return std::make_unique<views::FloodFillInkDropRipple>(
               views::InkDrop::Get(host), host->size(),
@@ -101,8 +101,8 @@
 
     views::InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating(
         [](views::View* host) {
-          const SkColor hover_color = host->GetColorProvider()->GetColor(
-              ui::kColorSysStateHoverOnSubtle);
+          const SkColor hover_color =
+              host->GetColorProvider()->GetColor(kColorPageActionIconHover);
           const float hover_alpha = SkColorGetA(hover_color);
           auto ink_drop_highlight = std::make_unique<views::InkDropHighlight>(
               host->size(), host->height() / 2,
diff --git a/chrome/browser/ui/views/performance_controls/battery_saver_button_browsertest.cc b/chrome/browser/ui/views/performance_controls/battery_saver_button_browsertest.cc
index 9b5e19b..f992c6c 100644
--- a/chrome/browser/ui/views/performance_controls/battery_saver_button_browsertest.cc
+++ b/chrome/browser/ui/views/performance_controls/battery_saver_button_browsertest.cc
@@ -52,8 +52,7 @@
 
   void SetUp() override {
     iph_features_.InitAndEnableFeatures(
-        {feature_engagement::kIPHBatterySaverModeFeature,
-         performance_manager::features::kBatterySaverModeAvailable});
+        {feature_engagement::kIPHBatterySaverModeFeature});
 
     SetUpFakeBatterySampler();
 
@@ -194,12 +193,7 @@
   BatterySaverBubbleViewTest() = default;
   ~BatterySaverBubbleViewTest() override = default;
 
-  void SetUp() override {
-    feature_list_.InitAndEnableFeature(
-        performance_manager::features::kBatterySaverModeAvailable);
-
-    InProcessBrowserTest::SetUp();
-  }
+  void SetUp() override { InProcessBrowserTest::SetUp(); }
 
   void TearDown() override { InProcessBrowserTest::TearDown(); }
 
@@ -215,9 +209,6 @@
     views::test::InteractionTestUtilSimulatorViews::PressButton(
         button, ui::test::InteractionTestUtil::InputType::kMouse);
   }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
 };
 
 // Disable the battery saver mode for the session using the battery saver
diff --git a/chrome/browser/ui/views/performance_controls/battery_saver_button_unittest.cc b/chrome/browser/ui/views/performance_controls/battery_saver_button_unittest.cc
index c991131..4e8838f 100644
--- a/chrome/browser/ui/views/performance_controls/battery_saver_button_unittest.cc
+++ b/chrome/browser/ui/views/performance_controls/battery_saver_button_unittest.cc
@@ -28,11 +28,7 @@
  public:
   BatterySaverButtonTest() = default;
 
-  void SetUp() override {
-    feature_list_.InitAndEnableFeature(
-        performance_manager::features::kBatterySaverModeAvailable);
-    TestWithBrowserView::SetUp();
-  }
+  void SetUp() override { TestWithBrowserView::SetUp(); }
 
   void SetBatterySaverModeEnabled(bool enabled) {
     auto mode = enabled ? performance_manager::user_tuning::prefs::
@@ -47,7 +43,6 @@
   base::HistogramTester* GetHistogramTester() { return &histogram_tester_; }
 
  private:
-  base::test::ScopedFeatureList feature_list_;
   base::HistogramTester histogram_tester_;
 };
 
@@ -191,26 +186,3 @@
       "PerformanceControls.BatterySaver.BubbleAction",
       BatterySaverBubbleActionType::kTurnOffNow, 1);
 }
-
-class BatterySaverButtonNoExperimentsAvailableTest
-    : public TestWithBrowserView {
- public:
-  BatterySaverButtonNoExperimentsAvailableTest() = default;
-
-  void SetUp() override {
-    feature_list_.InitAndDisableFeature(
-        performance_manager::features::kBatterySaverModeAvailable);
-    TestWithBrowserView::SetUp();
-  }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-};
-
-// When battery saver mode available feature is disabled the toolbar button
-// should not be initialized
-TEST_F(BatterySaverButtonNoExperimentsAvailableTest, ShouldNotShowTest) {
-  const BatterySaverButton* battery_saver_button =
-      browser_view()->toolbar()->battery_saver_button();
-  EXPECT_EQ(battery_saver_button, nullptr);
-}
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.cc
index a6d5a45..85252af 100644
--- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.cc
+++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_button_view.h"
 
+#include "chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h"
 #include "chrome/common/accessibility/read_anything_constants.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/models/image_model.h"
@@ -16,9 +17,11 @@
     const gfx::VectorIcon& icon,
     int icon_size,
     SkColor icon_color,
-    const std::u16string& tooltip) {
+    const std::u16string& tooltip)
+    : ImageButton(std::move(callback)) {
   views::SetImageFromVectorIconWithColorId(this, icon, icon_color, icon_color,
                                            icon_size);
+  ConfigureInkDropForToolbar(this);
   views::InstallCircleHighlightPathGenerator(this);
   SetBorder(views::CreateEmptyBorder(
       gfx::Insets::VH(kInternalInsets / 2, kInternalInsets / 2)));
diff --git a/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc b/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc
index c7e5705b..c5b9818 100644
--- a/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc
+++ b/chrome/browser/ui/views/side_panel/side_panel_coordinator.cc
@@ -383,6 +383,11 @@
 void SidePanelCoordinator::Show(
     SidePanelEntry* entry,
     absl::optional<SidePanelUtil::SidePanelOpenTrigger> open_trigger) {
+  // Side panel is not supported for non-normal browsers.
+  if (!browser_view_->browser()->is_type_normal()) {
+    return;
+  }
+
   if (!entry) {
     return;
   }
diff --git a/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc b/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc
index 611f2be..bc37bc9 100644
--- a/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc
+++ b/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc
@@ -10,7 +10,12 @@
 #include "chrome/browser/ui/browser_element_identifiers.h"
 #include "chrome/browser/ui/side_search/side_search_config.h"
 #include "chrome/browser/ui/ui_features.h"
+#include "chrome/browser/ui/views/side_panel/side_panel.h"
+#include "chrome/browser/ui/views/side_panel/side_panel_coordinator.h"
 #include "chrome/browser/ui/views/side_panel/side_panel_entry.h"
+#include "chrome/browser/ui/views/side_panel/side_panel_registry.h"
+#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
+#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/interaction/interaction_test_util_browser.h"
 #include "chrome/test/interaction/interactive_browser_test.h"
@@ -39,6 +44,60 @@
   }
 };
 
+// This test is specifically to guard against this regression
+// (crbug.com/1428606).
+IN_PROC_BROWSER_TEST_F(SidePanelInteractiveTest, SidePanelNotShownOnPwa) {
+  DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kSecondTabElementId);
+  GURL second_tab_url("https://test.com");
+
+  RunTestSequence(
+      // Add a second tab to the tab strip
+      AddInstrumentedTab(kSecondTabElementId, second_tab_url),
+      CheckResult(base::BindLambdaForTesting([this]() {
+                    return browser()->tab_strip_model()->active_index();
+                  }),
+                  testing::Eq(1)),
+      // Ensure the side panel isn't open
+      EnsureNotPresent(kSidePanelElementId),
+      CheckResult(base::BindLambdaForTesting([this]() {
+                    return browser()
+                        ->tab_strip_model()
+                        ->GetActiveWebContents()
+                        ->GetLastCommittedURL();
+                  }),
+                  second_tab_url));
+
+  // Register side search entry to second_tab.
+  content::WebContents* active_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  auto* registry = SidePanelRegistry::Get(active_contents);
+  registry->Register(std::make_unique<SidePanelEntry>(
+      SidePanelEntry::Id::kSideSearch, u"testing1", ui::ImageModel(),
+      base::BindRepeating([]() { return std::make_unique<views::View>(); })));
+
+  // Toggle side search entry to show on second_tab.
+  auto* coordinator = BrowserView::GetBrowserViewForBrowser(browser())
+                          ->side_panel_coordinator();
+  coordinator->Show(SidePanelEntry::Id::kSideSearch);
+  EXPECT_EQ(coordinator->GetComboboxDisplayedEntryIdForTesting(),
+            SidePanelEntry::Id::kSideSearch);
+
+  // Install an app using second_tab_url.
+  auto app_id = web_app::test::InstallDummyWebApp(browser()->profile(),
+                                                  "App Name", second_tab_url);
+
+  // Move second_tab contents to app, simulating open pwa from omnibox intent
+  // picker.
+  Browser* app_browser = web_app::ReparentWebContentsIntoAppBrowser(
+      browser()->tab_strip_model()->GetActiveWebContents(), app_id);
+  EXPECT_TRUE(app_browser->is_type_app());
+
+  // App does not show side panel.
+  EXPECT_FALSE(BrowserView::GetBrowserViewForBrowser(app_browser)
+                   ->unified_side_panel()
+                   ->GetVisible());
+}
+
 IN_PROC_BROWSER_TEST_F(SidePanelInteractiveTest, ToggleSidePanelVisibility) {
   RunTestSequence(
       // Ensure the side panel isn't open
diff --git a/chrome/browser/ui/views/tabs/compound_tab_container_unittest.cc b/chrome/browser/ui/views/tabs/compound_tab_container_unittest.cc
index c63bede..7093e40 100644
--- a/chrome/browser/ui/views/tabs/compound_tab_container_unittest.cc
+++ b/chrome/browser/ui/views/tabs/compound_tab_container_unittest.cc
@@ -389,7 +389,7 @@
   AddTab(0, TabPinned::kUnpinned, absl::nullopt, TabActive::kActive);
 
   // Create just enough tabs so tabs are not full size.
-  const int standard_width = TabStyleViews::Create()->GetStandardWidth();
+  const int standard_width = TabStyle::Get()->GetStandardWidth();
   while (tab_container_->GetActiveTabWidth() == standard_width) {
     AddTab(0, TabPinned::kUnpinned);
     tab_container_->CompleteAnimationAndLayout();
@@ -425,7 +425,7 @@
   AddTab(1, TabPinned::kUnpinned, absl::nullopt, TabActive::kInactive);
 
   // Create just enough (pinned) tabs so the active tab is not full size.
-  const int standard_width = TabStyleViews::Create()->GetStandardWidth();
+  const int standard_width = TabStyle::Get()->GetStandardWidth();
   while (tab_container_->GetActiveTabWidth() == standard_width) {
     AddTab(0, TabPinned::kPinned, absl::nullopt, TabActive::kInactive);
     tab_container_->CompleteAnimationAndLayout();
@@ -458,7 +458,7 @@
   AddTab(1, TabPinned::kUnpinned, absl::nullopt, TabActive::kActive);
 
   // Create just enough (pinned) tabs so the active tab is not full size.
-  const int standard_width = TabStyleViews::Create()->GetStandardWidth();
+  const int standard_width = TabStyle::Get()->GetStandardWidth();
   while (tab_container_->GetActiveTabWidth() == standard_width) {
     AddTab(0, TabPinned::kPinned);
     tab_container_->CompleteAnimationAndLayout();
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 8972016a..93cd928 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -123,8 +123,8 @@
 
 class TabStyleHighlightPathGenerator : public views::HighlightPathGenerator {
  public:
-  explicit TabStyleHighlightPathGenerator(TabStyleViews* tab_style)
-      : tab_style_(tab_style) {}
+  explicit TabStyleHighlightPathGenerator(TabStyleViews* tab_style_views)
+      : tab_style_views_(tab_style_views) {}
   TabStyleHighlightPathGenerator(const TabStyleHighlightPathGenerator&) =
       delete;
   TabStyleHighlightPathGenerator& operator=(
@@ -132,11 +132,11 @@
 
   // views::HighlightPathGenerator:
   SkPath GetHighlightPath(const views::View* view) override {
-    return tab_style_->GetPath(TabStyle::PathType::kHighlight, 1.0);
+    return tab_style_views_->GetPath(TabStyle::PathType::kHighlight, 1.0);
   }
 
  private:
-  const raw_ptr<TabStyleViews, DanglingUntriaged> tab_style_;
+  const raw_ptr<TabStyleViews, DanglingUntriaged> tab_style_views_;
 };
 
 }  // namespace
@@ -194,7 +194,7 @@
       title_animation_(this) {
   DCHECK(controller);
 
-  tab_style_ = TabStyleViews::CreateForTab(this);
+  tab_style_views_ = TabStyleViews::Create()->CreateForTab(this);
 
   // So we get don't get enter/exit on children and don't prematurely stop the
   // hover.
@@ -204,7 +204,7 @@
 
   // This will cause calls to GetContentsBounds to return only the rectangle
   // inside the tab shape, rather than to its extents.
-  SetBorder(views::CreateEmptyBorder(tab_style()->GetContentsInsets()));
+  SetBorder(views::CreateEmptyBorder(tab_style_views()->GetContentsInsets()));
 
   title_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
   title_->SetElideBehavior(gfx::FADE_TAIL);
@@ -244,7 +244,8 @@
   SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
   views::FocusRing::Install(this);
   views::HighlightPathGenerator::Install(
-      this, std::make_unique<TabStyleHighlightPathGenerator>(tab_style_.get()));
+      this,
+      std::make_unique<TabStyleHighlightPathGenerator>(tab_style_views()));
 
   SetProperty(views::kElementIdentifierKey, kTabElementId);
 }
@@ -274,7 +275,7 @@
   // When the window is maximized we don't want to shave off the edges or top
   // shadow of the tab, such that the user can click anywhere along the top
   // edge of the screen to select a tab. Ditto for immersive fullscreen.
-  *mask = tab_style()->GetPath(
+  *mask = tab_style_views()->GetPath(
       TabStyle::PathType::kHitTest,
       GetWidget()->GetCompositor()->device_scale_factor(),
       /* force_active */ false, TabStyle::RenderUnits::kDips);
@@ -557,7 +558,7 @@
 }
 
 void Tab::OnMouseMoved(const ui::MouseEvent& event) {
-  tab_style_->SetHoverLocation(event.location());
+  tab_style_views()->SetHoverLocation(event.location());
   controller_->OnMouseEventInTab(this, event);
 
   // Linux enter/leave events are sometimes flaky, so we don't want to "miss"
@@ -591,7 +592,7 @@
 #endif
 
   mouse_hovered_ = true;
-  tab_style_->ShowHover(TabStyle::ShowHoverStyle::kSubtle);
+  tab_style_views()->ShowHover(TabStyle::ShowHoverStyle::kSubtle);
   UpdateForegroundColors();
   Layout();
   if (g_show_hover_card_on_mouse_hover)
@@ -603,7 +604,7 @@
   if (!mouse_hovered_)
     return;
   mouse_hovered_ = false;
-  tab_style_->HideHover(TabStyle::HideHoverStyle::kGradual);
+  tab_style_views()->HideHover(TabStyle::HideHoverStyle::kGradual);
   UpdateForegroundColors();
   Layout();
 }
@@ -673,7 +674,7 @@
   // The paint recording scale for tabs is consistent along the x and y axis.
   const float paint_recording_scale = info.paint_recording_scale_x();
 
-  const SkPath clip_path = tab_style()->GetPath(
+  const SkPath clip_path = tab_style_views()->GetPath(
       TabStyle::PathType::kInteriorClip, paint_recording_scale);
 
   clip_recorder.ClipPathWithAntiAliasing(clip_path);
@@ -681,7 +682,7 @@
 }
 
 void Tab::OnPaint(gfx::Canvas* canvas) {
-  tab_style()->PaintTab(canvas);
+  tab_style_views()->PaintTab(canvas);
 }
 
 void Tab::AddedToWidget() {
@@ -718,8 +719,9 @@
 }
 
 TabSizeInfo Tab::GetTabSizeInfo() const {
-  return {tab_style()->GetPinnedWidth(), tab_style()->GetMinimumActiveWidth(),
-          tab_style()->GetMinimumInactiveWidth(),
+  return {tab_style()->GetPinnedWidth(),
+          tab_style_views()->GetMinimumActiveWidth(),
+          tab_style_views()->GetMinimumInactiveWidth(),
           tab_style()->GetStandardWidth()};
 }
 
@@ -784,8 +786,8 @@
        {kColorTabAlertAudioPlayingActiveFrameInactive,
         kColorTabAlertAudioPlayingActiveFrameActive}}};
   return color_provider->GetColor(
-      color_ids[group]
-               [tab_style_->GetApparentActiveState() == TabActive::kActive]
+      color_ids[group][tab_style_views()->GetApparentActiveState() ==
+                       TabActive::kActive]
                [controller_->ShouldPaintAsActiveFrame()]);
 }
 
@@ -1070,7 +1072,7 @@
 }
 
 void Tab::UpdateForegroundColors() {
-  TabStyle::TabColors colors = tab_style_->CalculateColors();
+  TabStyle::TabColors colors = tab_style_views()->CalculateColors();
   title_->SetEnabledColor(colors.foreground_color);
   close_button_->SetColors(colors);
   alert_indicator_button_->OnParentTabButtonColorChanged();
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index ee39e52..e7cac95e 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -13,6 +13,7 @@
 #include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/tab_renderer_data.h"
 #include "chrome/browser/ui/views/tabs/tab_slot_view.h"
+#include "chrome/browser/ui/views/tabs/tab_style_views.h"
 #include "components/performance_manager/public/freezing/freezing.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -33,7 +34,6 @@
 class TabSlotController;
 class TabIcon;
 struct TabSizeInfo;
-class TabStyleViews;
 
 namespace gfx {
 class Animation;
@@ -165,8 +165,11 @@
   bool mouse_hovered() const { return mouse_hovered_; }
 
   // Returns the TabStyle associated with this tab.
-  TabStyleViews* tab_style() { return tab_style_.get(); }
-  const TabStyleViews* tab_style() const { return tab_style_.get(); }
+  TabStyleViews* tab_style_views() { return tab_style_views_.get(); }
+  const TabStyleViews* tab_style_views() const {
+    return tab_style_views_.get();
+  }
+  const TabStyle* tab_style() const { return tab_style_views_->tab_style(); }
 
   // Returns the text to show in a tab's tooltip: The contents |title|, followed
   // by a break, followed by a localized string describing the |alert_state|.
@@ -229,7 +232,7 @@
 
   TabRendererData data_;
 
-  std::unique_ptr<TabStyleViews> tab_style_;
+  std::unique_ptr<TabStyleViews> tab_style_views_;
 
   // True if the tab is being animated closed.
   bool closing_ = false;
diff --git a/chrome/browser/ui/views/tabs/tab_group_style.cc b/chrome/browser/ui/views/tabs/tab_group_style.cc
index 67d899c6..5a8e32a 100644
--- a/chrome/browser/ui/views/tabs/tab_group_style.cc
+++ b/chrome/browser/ui/views/tabs/tab_group_style.cc
@@ -3,9 +3,11 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/views/tabs/tab_group_style.h"
-#include <string>
+
+#include "base/feature_list.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/tabs/tab_style.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_group_header.h"
 #include "chrome/browser/ui/views/tabs/tab_group_underline.h"
@@ -24,8 +26,12 @@
 constexpr int kHeaderChipVerticalInset = 1;
 constexpr int kTitleAdjustmentForEmptyHeader = 2;
 constexpr int kTitleAdjustmentForNonEmptyHeader = -2;
+// The default size of an empty chip in the tab group header.
 constexpr int kEmptyChipSize = 14;
-constexpr int kSyncIconWidth = 12;
+// The width of the sync icon when a tab group is saved.
+constexpr int kSyncIconWidth = 16;
+// The size of the empty chips when the #tab-groups-save flag is on.
+constexpr int kSavedEmptyChipSize = 22;
 
 constexpr int kChromeRefreshHeaderChipVerticalInset = 2;
 constexpr int kChromeRefreshEmptyChipSize = 20;
@@ -99,7 +105,9 @@
 }
 
 float TabGroupStyle::GetEmptyChipSize() const {
-  return kEmptyChipSize;
+  return base::FeatureList::IsEnabled(features::kTabGroupsSave)
+             ? kSavedEmptyChipSize
+             : kEmptyChipSize;
 }
 
 float TabGroupStyle::GetSyncIconWidth() const {
diff --git a/chrome/browser/ui/views/tabs/tab_group_style.h b/chrome/browser/ui/views/tabs/tab_group_style.h
index a6ac0bc..f9de40eb 100644
--- a/chrome/browser/ui/views/tabs/tab_group_style.h
+++ b/chrome/browser/ui/views/tabs/tab_group_style.h
@@ -13,6 +13,7 @@
 
 class TabGroupViews;
 
+// Default styling of tab groups.
 class TabGroupStyle {
  public:
   explicit TabGroupStyle(const TabGroupViews& tab_group_views);
@@ -57,6 +58,7 @@
   const raw_ref<const TabGroupViews> tab_group_views_;
 };
 
+// Styling of tab groups when the #chrome-refresh-2023 flag is on.
 class ChromeRefresh2023TabGroupStyle : public TabGroupStyle {
  public:
   explicit ChromeRefresh2023TabGroupStyle(const TabGroupViews& tab_group_views);
diff --git a/chrome/browser/ui/views/tabs/tab_scrubber_chromeos.cc b/chrome/browser/ui/views/tabs/tab_scrubber_chromeos.cc
index a9cc827..5a4c719 100644
--- a/chrome/browser/ui/views/tabs/tab_scrubber_chromeos.cc
+++ b/chrome/browser/ui/views/tabs/tab_scrubber_chromeos.cc
@@ -49,7 +49,7 @@
 
   // Start the swipe where the tab contents start/end.  This provides a small
   // amount of slop inside the tab before a swipe will change tabs.
-  auto contents_insets = tab->tab_style()->GetContentsInsets();
+  auto contents_insets = tab->tab_style_views()->GetContentsInsets();
   int left = contents_insets.left();
   int right = contents_insets.right();
 
@@ -184,7 +184,7 @@
   if (highlighted_tab_ != -1) {
     gfx::Point hover_point(swipe_x_, swipe_y_);
     views::View::ConvertPointToTarget(tab_strip_, new_tab, &hover_point);
-    new_tab->tab_style()->SetHoverLocation(hover_point);
+    new_tab->tab_style_views()->SetHoverLocation(hover_point);
   }
 }
 
@@ -273,7 +273,7 @@
     TabStrip* tab_strip = browser_view->tabstrip();
     if (activate && highlighted_tab_ != -1) {
       Tab* tab = tab_strip->tab_at(highlighted_tab_);
-      tab->tab_style()->HideHover(TabStyle::HideHoverStyle::kImmediate);
+      tab->tab_style_views()->HideHover(TabStyle::HideHoverStyle::kImmediate);
       int distance = std::abs(highlighted_tab_ -
                               browser_->tab_strip_model()->active_index());
       UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.ScrubDistance", distance, 1, 20, 21);
@@ -360,12 +360,13 @@
 
   if (highlighted_tab_ != -1) {
     Tab* tab = tab_strip_->tab_at(highlighted_tab_);
-    tab->tab_style()->HideHover(TabStyle::HideHoverStyle::kImmediate);
+    tab->tab_style_views()->HideHover(TabStyle::HideHoverStyle::kImmediate);
   }
 
   if (new_index != browser_->tab_strip_model()->active_index()) {
     highlighted_tab_ = new_index;
-    new_tab->tab_style()->ShowHover(TabStyle::ShowHoverStyle::kPronounced);
+    new_tab->tab_style_views()->ShowHover(
+        TabStyle::ShowHoverStyle::kPronounced);
   } else {
     highlighted_tab_ = -1;
   }
diff --git a/chrome/browser/ui/views/tabs/tab_style_views.cc b/chrome/browser/ui/views/tabs/tab_style_views.cc
index 0dabeae..32ec44d 100644
--- a/chrome/browser/ui/views/tabs/tab_style_views.cc
+++ b/chrome/browser/ui/views/tabs/tab_style_views.cc
@@ -48,23 +48,6 @@
 // Exclude the lower right arc.
 constexpr ShapeModifier kNoLowerRightArc = 0x02;
 
-void DrawHighlight(gfx::Canvas* canvas,
-                   const SkPoint& p,
-                   SkScalar radius,
-                   SkColor color) {
-  // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
-  const SkColor4f colors[2] = {
-      SkColor4f::FromColor(color),
-      SkColor4f::FromColor(SkColorSetA(color, SK_AlphaTRANSPARENT))};
-  cc::PaintFlags flags;
-  flags.setAntiAlias(true);
-  flags.setShader(cc::PaintShader::MakeRadialGradient(
-      p, radius, colors, nullptr, 2, SkTileMode::kClamp));
-  canvas->sk_canvas()->drawRect(
-      SkRect::MakeXYWH(p.x() - radius, p.y() - radius, radius * 2, radius * 2),
-      flags);
-}
-
 // Updates a target value, returning true if it changed.
 template <class T>
 bool UpdateValue(T* dest, const T& src) {
@@ -76,11 +59,12 @@
 }
 
 // Tab style implementation for the GM2 refresh (Chrome 69).
-class GM2TabStyle : public TabStyleViews {
+class GM2TabStyleViews : public TabStyleViews {
  public:
-  explicit GM2TabStyle(Tab* tab);
-  GM2TabStyle(const GM2TabStyle&) = delete;
-  GM2TabStyle& operator=(const GM2TabStyle&) = delete;
+  explicit GM2TabStyleViews(Tab* tab);
+  ~GM2TabStyleViews() override = default;
+  GM2TabStyleViews(const GM2TabStyleViews&) = delete;
+  GM2TabStyleViews& operator=(const GM2TabStyleViews&) = delete;
 
   const Tab* tab() const { return tab_; }
 
@@ -138,7 +122,7 @@
   bool IsHoverActive() const;
 
   // Returns the progress (0 to 1) of the hover animation.
-  double GetHoverAnimationValue() const;
+  double GetHoverAnimationValue() const override;
 
   // Returns the opacity of the hover effect that should be drawn, which may not
   // be the same as GetHoverAnimationValue.
@@ -167,6 +151,10 @@
                               bool paint_hover_effect,
                               absl::optional<int> fill_id,
                               int y_inset) const;
+  void PaintBackgroundHover(gfx::Canvas* canvas,
+                            const SkPoint& p,
+                            SkScalar radius,
+                            SkColor color) const;
   void PaintBackgroundStroke(gfx::Canvas* canvas,
                              TabActive active,
                              SkColor stroke_color) const;
@@ -188,7 +176,7 @@
 
 // GM2TabStyle -----------------------------------------------------------------
 
-GM2TabStyle::GM2TabStyle(Tab* tab)
+GM2TabStyleViews::GM2TabStyleViews(Tab* tab)
     : tab_(tab),
       hover_controller_((tab && gfx::Animation::ShouldRenderRichAnimation())
                             ? new GlowHoverController(tab)
@@ -197,10 +185,10 @@
   // repurposing CONTEXT_BUTTON_MD.
 }
 
-SkPath GM2TabStyle::GetPath(TabStyle::PathType path_type,
-                            float scale,
-                            bool force_active,
-                            TabStyle::RenderUnits render_units) const {
+SkPath GM2TabStyleViews::GetPath(TabStyle::PathType path_type,
+                                 float scale,
+                                 bool force_active,
+                                 TabStyle::RenderUnits render_units) const {
   CHECK(tab());
   const int stroke_thickness = GetStrokeThickness(force_active);
 
@@ -230,7 +218,7 @@
 
   // Compute |extension| as the width outside the separators.  This is a fixed
   // value equal to the normal corner radius.
-  const float extension = GetCornerRadius() * scale;
+  const float extension = tab_style()->GetCornerRadius() * scale;
 
   // Calculate the bounds of the actual path.
   const float left = aligned_bounds.x();
@@ -410,16 +398,16 @@
   return path;
 }
 
-gfx::Insets GM2TabStyle::GetContentsInsets() const {
+gfx::Insets GM2TabStyleViews::GetContentsInsets() const {
   const int stroke_thickness = GetStrokeThickness();
-  const int horizontal_inset = GetContentsHorizontalInsetSize();
+  const int horizontal_inset = tab_style()->GetContentsHorizontalInsetSize();
   return gfx::Insets::TLBR(
       stroke_thickness, horizontal_inset,
       stroke_thickness + GetLayoutConstant(TABSTRIP_TOOLBAR_OVERLAP),
       horizontal_inset);
 }
 
-float GM2TabStyle::GetZValue() const {
+float GM2TabStyleViews::GetZValue() const {
   CHECK(tab());
   // This will return values so that inactive tabs can be sorted in the
   // following order:
@@ -453,18 +441,18 @@
   return sort_value;
 }
 
-float GM2TabStyle::GetActiveOpacity() const {
+float GM2TabStyleViews::GetActiveOpacity() const {
   CHECK(tab());
   if (tab_->IsActive())
     return 1.0f;
   if (tab_->IsSelected())
-    return GetSelectedTabOpacity();
+    return tab_style()->GetSelectedTabOpacity();
   if (tab_->mouse_hovered())
     return GetHoverOpacity();
   return 0.0f;
 }
 
-TabActive GM2TabStyle::GetApparentActiveState() const {
+TabActive GM2TabStyleViews::GetApparentActiveState() const {
   // In some cases, inactive tabs may have background more like active tabs than
   // inactive tabs, so colors should be adapted to ensure appropriate contrast.
   // In particular, text should have plenty of contrast in all cases, so switch
@@ -473,7 +461,7 @@
   return GetActiveOpacity() > 0.5f ? TabActive::kActive : TabActive::kInactive;
 }
 
-TabStyle::TabColors GM2TabStyle::CalculateColors() const {
+TabStyle::TabColors GM2TabStyleViews::CalculateColors() const {
   CHECK(tab());
   const TabActive active = GetApparentActiveState();
   const SkColor foreground_color =
@@ -491,7 +479,7 @@
           close_button_focus_ring_color};
 }
 
-void GM2TabStyle::PaintTab(gfx::Canvas* canvas) const {
+void GM2TabStyleViews::PaintTab(gfx::Canvas* canvas) const {
   CHECK(tab());
   absl::optional<int> active_tab_fill_id;
   int active_tab_y_inset = 0;
@@ -517,7 +505,7 @@
   }
 }
 
-void GM2TabStyle::SetHoverLocation(const gfx::Point& location) {
+void GM2TabStyleViews::SetHoverLocation(const gfx::Point& location) {
   CHECK(tab());
   // There's a "glow" that gets drawn over inactive tabs based on the mouse's
   // location. There is no glow for the active tab so don't update the hover
@@ -526,7 +514,7 @@
     hover_controller_->SetLocation(location);
 }
 
-void GM2TabStyle::ShowHover(TabStyle::ShowHoverStyle style) {
+void GM2TabStyleViews::ShowHover(TabStyle::ShowHoverStyle style) {
   CHECK(tab());
   if (!hover_controller_)
     return;
@@ -538,18 +526,19 @@
   hover_controller_->Show(style);
 }
 
-void GM2TabStyle::HideHover(TabStyle::HideHoverStyle style) {
+void GM2TabStyleViews::HideHover(TabStyle::HideHoverStyle style) {
   CHECK(tab());
   if (hover_controller_)
     hover_controller_->Hide(style);
 }
 
-TabStyle::SeparatorBounds GM2TabStyle::GetSeparatorBounds(float scale) const {
+TabStyle::SeparatorBounds GM2TabStyleViews::GetSeparatorBounds(
+    float scale) const {
   CHECK(tab());
   const gfx::RectF aligned_bounds =
       ScaleAndAlignBounds(tab_->bounds(), scale, GetStrokeThickness());
-  const int corner_radius = GetCornerRadius() * scale;
-  gfx::SizeF separator_size(GetSeparatorSize());
+  const int corner_radius = tab_style()->GetCornerRadius() * scale;
+  gfx::SizeF separator_size(tab_style()->GetSeparatorSize());
   separator_size.Scale(scale);
 
   TabStyle::SeparatorBounds separator_bounds;
@@ -572,7 +561,7 @@
   return separator_bounds;
 }
 
-TabStyle::SeparatorOpacities GM2TabStyle::GetSeparatorOpacities(
+TabStyle::SeparatorOpacities GM2TabStyleViews::GetSeparatorOpacities(
     bool for_layout) const {
   // Adjacent slots should be visually separated from each other. This can be
   // achieved in multiple ways:
@@ -597,7 +586,8 @@
   return {leading_opacity, trailing_opacity};
 }
 
-float GM2TabStyle::GetSeparatorOpacity(bool for_layout, bool leading) const {
+float GM2TabStyleViews::GetSeparatorOpacity(bool for_layout,
+                                            bool leading) const {
   CHECK(tab());
   // If the current tab is active, never show the separator.
   if (tab_->IsActive())
@@ -682,7 +672,7 @@
   return GetHoverInterpolatedSeparatorOpacity(for_layout, adjacent_tab);
 }
 
-float GM2TabStyle::GetHoverInterpolatedSeparatorOpacity(
+float GM2TabStyleViews::GetHoverInterpolatedSeparatorOpacity(
     bool for_layout,
     const Tab* other_tab) const {
   CHECK(tab());
@@ -692,38 +682,39 @@
   // hover animation value, otherwise the separator on this tab will disappear
   // while that tab is being dragged.
   auto adjacent_hover_value = [for_layout](const Tab* other_tab) {
-    if (for_layout || !other_tab || other_tab->IsActive())
+    if (for_layout || !other_tab || other_tab->IsActive()) {
       return 0.0f;
-    auto* tab_style = static_cast<const GM2TabStyle*>(other_tab->tab_style());
-    return static_cast<float>(tab_style->GetHoverAnimationValue());
+    }
+    return static_cast<float>(
+        other_tab->tab_style_views()->GetHoverAnimationValue());
   };
   const float hover_value = GetHoverAnimationValue();
   return 1.0f - std::max(hover_value, adjacent_hover_value(other_tab));
 }
 
-bool GM2TabStyle::ShouldExtendHitTest() const {
+bool GM2TabStyleViews::ShouldExtendHitTest() const {
   const views::Widget* widget = tab_->GetWidget();
   return widget->IsMaximized() || widget->IsFullscreen();
 }
 
-bool GM2TabStyle::IsHoverActive() const {
+bool GM2TabStyleViews::IsHoverActive() const {
   if (!hover_controller_)
     return false;
   return hover_controller_->ShouldDraw();
 }
 
-double GM2TabStyle::GetHoverAnimationValue() const {
+double GM2TabStyleViews::GetHoverAnimationValue() const {
   if (!hover_controller_)
     return 0.0;
   return hover_controller_->GetAnimationValue();
 }
 
-float GM2TabStyle::GetHoverOpacity() const {
+float GM2TabStyleViews::GetHoverOpacity() const {
   CHECK(tab());
   // Opacity boost varies on tab width.  The interpolation is nonlinear so
   // that most tabs will fall on the low end of the opacity range, but very
   // narrow tabs will still stand out on the high end.
-  const float range_start = static_cast<float>(GetStandardWidth());
+  const float range_start = static_cast<float>(tab_style()->GetStandardWidth());
   constexpr float kWidthForMaxHoverOpacity = 32.0f;
   const float value_in_range = static_cast<float>(tab_->width());
   const float t = std::clamp(
@@ -732,12 +723,13 @@
   return tab_->controller()->GetHoverOpacityForTab(t * t);
 }
 
-float GM2TabStyle::GetThrobValue() const {
+float GM2TabStyleViews::GetThrobValue() const {
   const bool is_selected = tab_->IsSelected();
-  double val = is_selected ? GetSelectedTabOpacity() : 0;
+  double val = is_selected ? tab_style()->GetSelectedTabOpacity() : 0;
 
   if (IsHoverActive()) {
-    const float kSelectedTabThrobScale = 0.95f - GetSelectedTabOpacity();
+    const float kSelectedTabThrobScale =
+        0.95f - tab_style()->GetSelectedTabOpacity();
     const float opacity = GetHoverOpacity();
     const float offset =
         is_selected ? (kSelectedTabThrobScale * opacity) : opacity;
@@ -747,7 +739,7 @@
   return val;
 }
 
-int GM2TabStyle::GetStrokeThickness(bool should_paint_as_active) const {
+int GM2TabStyleViews::GetStrokeThickness(bool should_paint_as_active) const {
   CHECK(tab());
   absl::optional<tab_groups::TabGroupId> group = tab_->group();
   if (group.has_value() && tab_->IsActive())
@@ -759,7 +751,7 @@
   return 0;
 }
 
-bool GM2TabStyle::ShouldPaintTabBackgroundColor(
+bool GM2TabStyleViews::ShouldPaintTabBackgroundColor(
     TabActive active,
     bool has_custom_background) const {
   CHECK(tab());
@@ -777,7 +769,7 @@
       ThemeProperties::SHOULD_FILL_BACKGROUND_TAB_COLOR);
 }
 
-SkColor GM2TabStyle::GetTabBackgroundColor(TabActive active) const {
+SkColor GM2TabStyleViews::GetTabBackgroundColor(TabActive active) const {
   CHECK(tab());
   SkColor color = tab_->controller()->GetTabBackgroundColor(
       active, BrowserFrameActiveState::kUseCurrent);
@@ -785,7 +777,7 @@
   return color;
 }
 
-ShapeModifier GM2TabStyle::GetShapeModifier(
+ShapeModifier GM2TabStyleViews::GetShapeModifier(
     TabStyle::PathType path_type) const {
   CHECK(tab());
   ShapeModifier shape_modifier = kNone;
@@ -805,7 +797,7 @@
   return shape_modifier;
 }
 
-void GM2TabStyle::PaintInactiveTabBackground(gfx::Canvas* canvas) const {
+void GM2TabStyleViews::PaintInactiveTabBackground(gfx::Canvas* canvas) const {
   CHECK(tab());
   PaintTabBackground(canvas, TabActive::kInactive,
                      tab_->controller()->GetCustomBackgroundId(
@@ -813,10 +805,10 @@
                      0);
 }
 
-void GM2TabStyle::PaintTabBackground(gfx::Canvas* canvas,
-                                     TabActive active,
-                                     absl::optional<int> fill_id,
-                                     int y_inset) const {
+void GM2TabStyleViews::PaintTabBackground(gfx::Canvas* canvas,
+                                          TabActive active,
+                                          absl::optional<int> fill_id,
+                                          int y_inset) const {
   CHECK(tab());
   // |y_inset| is only set when |fill_id| is being used.
   DCHECK(!y_inset || fill_id.has_value());
@@ -838,11 +830,11 @@
   PaintSeparators(canvas);
 }
 
-void GM2TabStyle::PaintTabBackgroundFill(gfx::Canvas* canvas,
-                                         TabActive active,
-                                         bool paint_hover_effect,
-                                         absl::optional<int> fill_id,
-                                         int y_inset) const {
+void GM2TabStyleViews::PaintTabBackgroundFill(gfx::Canvas* canvas,
+                                              TabActive active,
+                                              bool paint_hover_effect,
+                                              absl::optional<int> fill_id,
+                                              int y_inset) const {
   CHECK(tab());
   const SkPath fill_path =
       GetPath(TabStyle::PathType::kFill, canvas->image_scale(),
@@ -875,15 +867,32 @@
     const SkScalar kMinHoverRadius = 16;
     const SkScalar radius =
         std::max(SkFloatToScalar(tab_->width() / 4.f), kMinHoverRadius);
-    DrawHighlight(canvas, hover_location, radius * scale,
-                  SkColorSetA(GetTabBackgroundColor(TabActive::kActive),
-                              hover_controller_->GetAlpha()));
+    PaintBackgroundHover(canvas, hover_location, radius * scale,
+                         SkColorSetA(GetTabBackgroundColor(TabActive::kActive),
+                                     hover_controller_->GetAlpha()));
   }
 }
 
-void GM2TabStyle::PaintBackgroundStroke(gfx::Canvas* canvas,
-                                        TabActive active,
-                                        SkColor stroke_color) const {
+void GM2TabStyleViews::PaintBackgroundHover(gfx::Canvas* canvas,
+                                            const SkPoint& p,
+                                            SkScalar radius,
+                                            SkColor color) const {
+  // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
+  const SkColor4f colors[2] = {
+      SkColor4f::FromColor(color),
+      SkColor4f::FromColor(SkColorSetA(color, SK_AlphaTRANSPARENT))};
+  cc::PaintFlags flags;
+  flags.setAntiAlias(true);
+  flags.setShader(cc::PaintShader::MakeRadialGradient(
+      p, radius, colors, nullptr, 2, SkTileMode::kClamp));
+  canvas->sk_canvas()->drawRect(
+      SkRect::MakeXYWH(p.x() - radius, p.y() - radius, radius * 2, radius * 2),
+      flags);
+}
+
+void GM2TabStyleViews::PaintBackgroundStroke(gfx::Canvas* canvas,
+                                             TabActive active,
+                                             SkColor stroke_color) const {
   CHECK(tab());
   const bool is_active = active == TabActive::kActive;
   const int stroke_thickness = GetStrokeThickness(is_active);
@@ -902,7 +911,7 @@
   canvas->DrawPath(outer_path, flags);
 }
 
-void GM2TabStyle::PaintSeparators(gfx::Canvas* canvas) const {
+void GM2TabStyleViews::PaintSeparators(gfx::Canvas* canvas) const {
   const auto separator_opacities = GetSeparatorOpacities(false);
   if (!separator_opacities.left && !separator_opacities.right)
     return;
@@ -928,10 +937,10 @@
   canvas->DrawRect(separator_bounds.trailing, flags);
 }
 
-float GM2TabStyle::GetTopCornerRadiusForWidth(int width) const {
+float GM2TabStyleViews::GetTopCornerRadiusForWidth(int width) const {
   // Get the width of the top of the tab by subtracting the width of the outer
   // corners.
-  const int ideal_radius = GetCornerRadius();
+  const int ideal_radius = tab_style()->GetCornerRadius();
   const int top_width = width - ideal_radius * 2;
 
   // To maintain a round-rect appearance, ensure at least one third of the top
@@ -940,20 +949,20 @@
   return std::clamp<float>(radius, 0, ideal_radius);
 }
 
-gfx::RectF GM2TabStyle::ScaleAndAlignBounds(const gfx::Rect& bounds,
-                                            float scale,
-                                            int stroke_thickness) const {
+gfx::RectF GM2TabStyleViews::ScaleAndAlignBounds(const gfx::Rect& bounds,
+                                                 float scale,
+                                                 int stroke_thickness) const {
   // Convert to layout bounds.  We must inset the width such that the right edge
   // of one tab's layout bounds is the same as the left edge of the next tab's;
   // this way the two tabs' separators will be drawn at the same coordinate.
   gfx::RectF aligned_bounds(bounds);
-  const int corner_radius = GetCornerRadius();
+  const int corner_radius = tab_style()->GetCornerRadius();
   // Note: This intentionally doesn't subtract TABSTRIP_TOOLBAR_OVERLAP from the
   // bottom inset, because we want to pixel-align the bottom of the stroke, not
   // the bottom of the overlap.
-  auto layout_insets =
-      gfx::InsetsF::TLBR(stroke_thickness, corner_radius, stroke_thickness,
-                         corner_radius + GetSeparatorSize().width());
+  auto layout_insets = gfx::InsetsF::TLBR(
+      stroke_thickness, corner_radius, stroke_thickness,
+      corner_radius + tab_style()->GetSeparatorSize().width());
   aligned_bounds.Inset(layout_insets);
 
   // Scale layout bounds from DIP to px.
@@ -974,16 +983,19 @@
   return aligned_bounds;
 }
 
-class GM3TabStyle : public GM2TabStyle {
+class ChromeRefresh2023TabStyleViews : public GM2TabStyleViews {
  public:
-  explicit GM3TabStyle(Tab* tab);
+  explicit ChromeRefresh2023TabStyleViews(Tab* tab);
+  ~ChromeRefresh2023TabStyleViews() override = default;
   SkColor GetTabBackgroundColor(TabActive active) const override;
   int GetStrokeThickness(bool should_paint_as_active = false) const override;
 };
 
-GM3TabStyle::GM3TabStyle(Tab* tab) : GM2TabStyle(tab) {}
+ChromeRefresh2023TabStyleViews::ChromeRefresh2023TabStyleViews(Tab* tab)
+    : GM2TabStyleViews(tab) {}
 
-SkColor GM3TabStyle::GetTabBackgroundColor(TabActive active) const {
+SkColor ChromeRefresh2023TabStyleViews::GetTabBackgroundColor(
+    TabActive active) const {
   CHECK(tab());
   const auto* cp = tab()->GetWidget()->GetColorProvider();
   DCHECK(cp);
@@ -1001,7 +1013,8 @@
       tab()->controller()->ShouldPaintAsActiveFrame())]);
 }
 
-int GM3TabStyle::GetStrokeThickness(bool should_paint_as_active) const {
+int ChromeRefresh2023TabStyleViews::GetStrokeThickness(
+    bool should_paint_as_active) const {
   CHECK(tab());
   if (tab()->group().has_value() && tab()->IsActive()) {
     return TabGroupUnderline::kStrokeThickness;
@@ -1054,17 +1067,19 @@
   return ValidStrings();
 }
 
-// TabStyle --------------------------------------------------------------------
+// TabStyleViews ---------------------------------------------------------------
+
+TabStyleViews::TabStyleViews() : tab_style_(TabStyle::Get()) {}
 
 TabStyleViews::~TabStyleViews() = default;
 
 // static
 std::unique_ptr<TabStyleViews> TabStyleViews::CreateForTab(Tab* tab) {
-  // If refresh is turned on use GM3 styling.
+  // If refresh is turned on use ChromeRefresh styling.
   if (features::IsChromeRefresh2023()) {
-    return std::make_unique<GM3TabStyle>(tab);
+    return std::make_unique<ChromeRefresh2023TabStyleViews>(tab);
   }
-  return std::make_unique<GM2TabStyle>(tab);
+  return std::make_unique<GM2TabStyleViews>(tab);
 }
 
 // static
@@ -1073,8 +1088,8 @@
 }
 
 int TabStyleViews::GetMinimumActiveWidth() const {
-  int min_active_width =
-      TabCloseButton::GetGlyphSize() + GetContentsHorizontalInsetSize() * 2;
+  int min_active_width = TabCloseButton::GetGlyphSize() +
+                         tab_style()->GetContentsHorizontalInsetSize() * 2;
   if (base::FeatureList::IsEnabled(features::kScrollableTabStrip)) {
     return std::max(
         min_active_width,
@@ -1091,8 +1106,9 @@
   constexpr int kInteriorWidth = 16;
   // The overlap contains the trailing separator that is part of the interior
   // width; avoid double-counting it.
-  int min_inactive_width =
-      kInteriorWidth - GetSeparatorSize().width() + GetTabOverlap();
+  int min_inactive_width = kInteriorWidth -
+                           tab_style()->GetSeparatorSize().width() +
+                           tab_style()->GetTabOverlap();
 
   if (base::FeatureList::IsEnabled(features::kScrollableTabStrip)) {
     return std::max(min_inactive_width,
diff --git a/chrome/browser/ui/views/tabs/tab_style_views.h b/chrome/browser/ui/views/tabs/tab_style_views.h
index d4d94e5..b780241 100644
--- a/chrome/browser/ui/views/tabs/tab_style_views.h
+++ b/chrome/browser/ui/views/tabs/tab_style_views.h
@@ -29,14 +29,15 @@
 }
 
 // Holds Views-specific logic for rendering and sizing tabs.
-class TabStyleViews : public TabStyle {
+class TabStyleViews {
  public:
   // Factory function allows to experiment with different variations on tab
   // style at runtime or via flag.
   static std::unique_ptr<TabStyleViews> CreateForTab(Tab* tab);
   static std::unique_ptr<TabStyleViews> Create();
 
-  ~TabStyleViews() override;
+  TabStyleViews();
+  virtual ~TabStyleViews();
 
   // Gets the specific |path_type| associated with the specific |tab|.
   // If |force_active| is true, applies an active appearance on the tab (usually
@@ -78,6 +79,9 @@
   // Hides the hover animation.
   virtual void HideHover(TabStyle::HideHoverStyle style) = 0;
 
+  // Returns the progress (0 to 1) of the hover animation.
+  virtual double GetHoverAnimationValue() const = 0;
+
   // Returns the minimum possible width of a selected Tab. Selected tabs must
   // always show a close button, and thus have a larger minimum size than
   // unselected tabs.
@@ -86,9 +90,10 @@
   // Returns the minimum possible width of a single unselected Tab.
   int GetMinimumInactiveWidth() const;
 
- protected:
-  // Avoid implicitly-deleted constructor.
-  TabStyleViews() = default;
+  const TabStyle* tab_style() const { return tab_style_; }
+
+ private:
+  const raw_ptr<const TabStyle> tab_style_;
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STYLE_VIEWS_H_
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc
index 3d635cc7..eb586a6 100644
--- a/chrome/browser/ui/views/tabs/tab_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -353,8 +353,8 @@
         } else {
           width = tab->tab_style()->GetStandardWidth();
           min_width = is_active_tab
-                          ? tab->tab_style()->GetMinimumActiveWidth()
-                          : tab->tab_style()->GetMinimumInactiveWidth();
+                          ? tab->tab_style_views()->GetMinimumActiveWidth()
+                          : tab->tab_style_views()->GetMinimumInactiveWidth();
         }
         const int height = GetLayoutConstant(TAB_HEIGHT);
         for (; width >= min_width; --width) {
@@ -534,7 +534,7 @@
   auto controller = std::make_unique<FakeTabSlotController>();
   std::unique_ptr<views::Widget> widget = CreateTestWidget();
   Tab* tab = widget->SetContentsView(std::make_unique<Tab>(controller.get()));
-  const int width = tab->tab_style()->GetContentsInsets().width() +
+  const int width = tab->tab_style_views()->GetContentsInsets().width() +
                     Tab::kMinimumContentsWidthForCloseButtons;
   tab->SetBounds(0, 0, width, 50);
   const views::View* close = GetCloseButton(tab);
diff --git a/chrome/browser/ui/views/tabs/z_orderable_tab_container_element.cc b/chrome/browser/ui/views/tabs/z_orderable_tab_container_element.cc
index d7290bf..33df73d9 100644
--- a/chrome/browser/ui/views/tabs/z_orderable_tab_container_element.cc
+++ b/chrome/browser/ui/views/tabs/z_orderable_tab_container_element.cc
@@ -54,6 +54,6 @@
   // The non-active tabs are painted next. They are ordered by their selected
   // or hovered state, which is animated and thus real-valued.
   const float tab_style_z_value =
-      tab ? tab->tab_style()->GetZValue() + 1.0f : 0.0f;
+      tab ? tab->tab_style_views()->GetZValue() + 1.0f : 0.0f;
   return z_value + tab_style_z_value;
 }
diff --git a/chrome/browser/ui/views/user_education/browser_user_education_service.cc b/chrome/browser/ui/views/user_education/browser_user_education_service.cc
index f4df27ba..42a948e 100644
--- a/chrome/browser/ui/views/user_education/browser_user_education_service.cc
+++ b/chrome/browser/ui/views/user_education/browser_user_education_service.cc
@@ -284,25 +284,25 @@
       IDS_PASSWORD_MANAGER_IPH_MANAGEMENT_BUBBLE_DURING_SIGNIN_SCREENREADER,
       FeaturePromoSpecification::AcceleratorInfo()));
 
-  // kIPHPasswordsWebAppProfileSwitchFeature:
-  registry.RegisterFeature(
-      std::move(FeaturePromoSpecification::CreateForSnoozePromo(
-                    feature_engagement::kIPHPasswordsWebAppProfileSwitchFeature,
-                    kAvatarButtonElementId,
-                    IDS_PASSWORD_MANAGER_IPH_BODY_WEB_APP_PROFILE_SWITCH)
-                    .SetBubbleIcon(&vector_icons::kLightbulbOutlineIcon)));
-
   // kIPHPowerBookmarksSidePanelFeature:
   registry.RegisterFeature(FeaturePromoSpecification::CreateForSnoozePromo(
       feature_engagement::kIPHPowerBookmarksSidePanelFeature,
       kSidePanelButtonElementId, IDS_POWER_BOOKMARKS_SIDE_PANEL_PROMO));
 
-  // kIPHSwitchProfileFeature:
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
+  // kIPHSwitchProfileFeature:
   registry.RegisterFeature(FeaturePromoSpecification::CreateForToastPromo(
       feature_engagement::kIPHProfileSwitchFeature, kAvatarButtonElementId,
       IDS_PROFILE_SWITCH_PROMO, IDS_PROFILE_SWITCH_PROMO_SCREENREADER,
       FeaturePromoSpecification::AcceleratorInfo(IDC_SHOW_AVATAR_MENU)));
+
+  // kIPHPasswordsWebAppProfileSwitchFeature:
+  registry.RegisterFeature(FeaturePromoSpecification::CreateForToastPromo(
+      feature_engagement::kIPHPasswordsWebAppProfileSwitchFeature,
+      kAvatarButtonElementId,
+      IDS_PASSWORD_MANAGER_IPH_BODY_WEB_APP_PROFILE_SWITCH,
+      IDS_PROFILE_SWITCH_PROMO_SCREENREADER,
+      FeaturePromoSpecification::AcceleratorInfo()));
 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
   // kIPHReadingListDiscoveryFeature:
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
index 3eb5371d..b1cfcf1 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
@@ -2251,7 +2251,7 @@
   base::RunLoop run_loop;
 
   UninstallCompleteWaiter uninstall_waiter(
-      profile(), policy_app->id, apps::Readiness::kUninstalledByMigration);
+      profile(), policy_app->id, apps::Readiness::kUninstalledByNonUser);
   WebAppInstallManagerObserverAdapter observer(profile());
   observer.SetWebAppUninstalledDelegate(
       base::BindLambdaForTesting([&](const AppId& app_id) {
@@ -3689,7 +3689,7 @@
                                                          const AppId& id) {
   base::RunLoop run_loop;
   AppReadinessWaiter app_registration_waiter(
-      profile, id, apps::Readiness::kUninstalledByMigration);
+      profile, id, apps::Readiness::kUninstalledByNonUser);
   WebAppInstallManagerObserverAdapter observer(profile);
   observer.SetWebAppUninstalledDelegate(
       base::BindLambdaForTesting([&](const AppId& app_id) {
diff --git a/chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.cc b/chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.cc
index fa56cf57..aa4aea82 100644
--- a/chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.cc
+++ b/chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.cc
@@ -33,8 +33,8 @@
 #include "content/public/common/content_features.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkEncodedImageFormat.h"
-#include "third_party/skia/include/core/SkImageEncoder.h"
+#include "third_party/skia/include/core/SkStream.h"
+#include "third_party/skia/include/encode/SkPngEncoder.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/gfx/geometry/rect.h"
 #include "url/gurl.h"
@@ -61,8 +61,10 @@
 
 std::string GetTestIconInString() {
   SkBitmap icon_bitmap = CreateSquareIcon(256, SK_ColorGREEN);
-  sk_sp<SkData> icon_skdata =
-      SkEncodeBitmap(icon_bitmap, SkEncodedImageFormat::kPNG, 100);
+  SkDynamicMemoryWStream stream;
+  bool success = SkPngEncoder::Encode(&stream, icon_bitmap.pixmap(), {});
+  CHECK(success);
+  sk_sp<SkData> icon_skdata = stream.detachAsData();
   return std::string(static_cast<const char*>(icon_skdata->data()),
                      icon_skdata->size());
 }
diff --git a/chrome/browser/ui/webui/ash/internet_detail_dialog.cc b/chrome/browser/ui/webui/ash/internet_detail_dialog.cc
index c2ed4c4..4b73dcc 100644
--- a/chrome/browser/ui/webui/ash/internet_detail_dialog.cc
+++ b/chrome/browser/ui/webui/ash/internet_detail_dialog.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/webui/ash/internet_detail_dialog.h"
 
 #include "ash/constants/ash_features.h"
+#include "ash/public/cpp/connectivity_services.h"
 #include "ash/public/cpp/network_config_service.h"
 #include "base/json/json_writer.h"
 #include "base/strings/utf_string_conversions.h"
@@ -202,6 +203,12 @@
       web_ui()->GetWebContents(), std::move(receiver));
 }
 
+void InternetDetailDialogUI::BindInterface(
+    mojo::PendingReceiver<chromeos::connectivity::mojom::PasspointService>
+        receiver) {
+  ash::GetPasspointService(std::move(receiver));
+}
+
 WEB_UI_CONTROLLER_TYPE_IMPL(InternetDetailDialogUI)
 
 }  // namespace ash
diff --git a/chrome/browser/ui/webui/ash/internet_detail_dialog.h b/chrome/browser/ui/webui/ash/internet_detail_dialog.h
index 47025ff..5748b06 100644
--- a/chrome/browser/ui/webui/ash/internet_detail_dialog.h
+++ b/chrome/browser/ui/webui/ash/internet_detail_dialog.h
@@ -7,6 +7,7 @@
 
 #include "chrome/browser/ui/webui/ash/system_web_dialog_delegate.h"
 #include "chrome/common/webui_url_constants.h"
+#include "chromeos/ash/services/connectivity/public/mojom/passpoint.mojom-forward.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-forward.h"
 #include "content/public/browser/webui_config.h"
 #include "content/public/common/url_constants.h"
@@ -89,6 +90,10 @@
       mojo::PendingReceiver<color_change_listener::mojom::PageHandler>
           receiver);
 
+  void BindInterface(
+      mojo::PendingReceiver<chromeos::connectivity::mojom::PasspointService>
+          receiver);
+
  private:
   std::unique_ptr<ui::ColorChangeHandler> color_provider_handler_;
   WEB_UI_CONTROLLER_TYPE_DECL();
diff --git a/chrome/browser/ui/webui/ash/network_ui.cc b/chrome/browser/ui/webui/ash/network_ui.cc
index 0b95deba..d2dbdfc4 100644
--- a/chrome/browser/ui/webui/ash/network_ui.cc
+++ b/chrome/browser/ui/webui/ash/network_ui.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "ash/constants/ash_features.h"
+#include "ash/public/cpp/connectivity_services.h"
 #include "ash/public/cpp/esim_manager.h"
 #include "ash/public/cpp/network_config_service.h"
 #include "ash/webui/network_ui/network_diagnostics_resource_provider.h"
@@ -1017,6 +1018,12 @@
   GetESimManager(std::move(receiver));
 }
 
+void NetworkUI::BindInterface(
+    mojo::PendingReceiver<chromeos::connectivity::mojom::PasspointService>
+        receiver) {
+  GetPasspointService(std::move(receiver));
+}
+
 WEB_UI_CONTROLLER_TYPE_IMPL(NetworkUI)
 
 }  // namespace ash
diff --git a/chrome/browser/ui/webui/ash/network_ui.h b/chrome/browser/ui/webui/ash/network_ui.h
index a937895..9cf575f 100644
--- a/chrome/browser/ui/webui/ash/network_ui.h
+++ b/chrome/browser/ui/webui/ash/network_ui.h
@@ -8,6 +8,7 @@
 #include "base/values.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chromeos/ash/services/cellular_setup/public/mojom/esim_manager.mojom-forward.h"
+#include "chromeos/ash/services/connectivity/public/mojom/passpoint.mojom-forward.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-forward.h"
 #include "chromeos/services/network_health/public/mojom/network_diagnostics.mojom-forward.h"
 #include "chromeos/services/network_health/public/mojom/network_health.mojom-forward.h"
@@ -64,6 +65,12 @@
   void BindInterface(
       mojo::PendingReceiver<cellular_setup::mojom::ESimManager> receiver);
 
+  // Instantiates the implementation of mojom::PasspointService mojo interface
+  // passing the pending receiver that will be internally bound.
+  void BindInterface(
+      mojo::PendingReceiver<chromeos::connectivity::mojom::PasspointService>
+          receiver);
+
  private:
   WEB_UI_CONTROLLER_TYPE_DECL();
 };
diff --git a/chrome/browser/ui/webui/bookmarks/bookmark_prefs.cc b/chrome/browser/ui/webui/bookmarks/bookmark_prefs.cc
index 9fea912..f6caf266 100644
--- a/chrome/browser/ui/webui/bookmarks/bookmark_prefs.cc
+++ b/chrome/browser/ui/webui/bookmarks/bookmark_prefs.cc
@@ -22,7 +22,7 @@
       static_cast<int>(side_panel::mojom::SortOrder::kNewest));
   registry->RegisterIntegerPref(
       prefs::kBookmarksViewType,
-      static_cast<int>(side_panel::mojom::ViewType::kCompact));
+      static_cast<int>(side_panel::mojom::ViewType::kExpanded));
 }
 
 }  // namespace bookmarks_webui
diff --git a/chrome/browser/ui/webui/browser_command/browser_command_handler_unittest.cc b/chrome/browser/ui/webui/browser_command/browser_command_handler_unittest.cc
index 78bce1c..8338fc1 100644
--- a/chrome/browser/ui/webui/browser_command/browser_command_handler_unittest.cc
+++ b/chrome/browser/ui/webui/browser_command/browser_command_handler_unittest.cc
@@ -520,37 +520,20 @@
 }
 
 TEST_F(BrowserCommandHandlerTest, OpenPerformanceSettings) {
-  {
-    // Can open the performance settings if battery saver is unavailable.
-    base::test::ScopedFeatureList high_efficiency;
-    high_efficiency.InitWithFeaturesAndParameters(
-        /*enabled_features=*/{},
-        /*disabled_features=*/{
-            {performance_manager::features::kBatterySaverModeAvailable}});
-    EXPECT_TRUE(CanExecuteCommand(Command::kOpenPerformanceSettings));
-  }
-  {
-    // Can open if battery saver is available.
-    base::test::ScopedFeatureList enabled;
-    enabled.InitWithFeaturesAndParameters(
-        /*enabled_features=*/
-        {{performance_manager::features::kBatterySaverModeAvailable, {}}},
-        /*disabled_features=*/{});
-    EXPECT_TRUE(CanExecuteCommand(Command::kOpenPerformanceSettings));
+  EXPECT_TRUE(CanExecuteCommand(Command::kOpenPerformanceSettings));
 
-    // Confirm executing the command works.
-    ClickInfoPtr info = ClickInfo::New();
-    info->middle_button = true;
-    info->meta_key = true;
-    // The OpenPassswordManager command opens a new settings window with the
-    // password manager and the correct disposition.
-    EXPECT_CALL(
-        *command_handler_,
-        NavigateToURL(GURL(chrome::GetSettingsUrl(chrome::kPerformanceSubPage)),
-                      DispositionFromClick(*info)));
-    EXPECT_TRUE(
-        ExecuteCommand(Command::kOpenPerformanceSettings, std::move(info)));
-  }
+  // Confirm executing the command works.
+  ClickInfoPtr info = ClickInfo::New();
+  info->middle_button = true;
+  info->meta_key = true;
+  // The OpenPerformanceSettings command opens a new settings window with the
+  // performance page open.
+  EXPECT_CALL(
+      *command_handler_,
+      NavigateToURL(GURL(chrome::GetSettingsUrl(chrome::kPerformanceSubPage)),
+                    DispositionFromClick(*info)));
+  EXPECT_TRUE(
+      ExecuteCommand(Command::kOpenPerformanceSettings, std::move(info)));
 }
 
 TEST_F(BrowserCommandHandlerTest,
diff --git a/chrome/browser/ui/webui/devtools_ui_data_source.cc b/chrome/browser/ui/webui/devtools_ui_data_source.cc
index 8119b63..c60d70f 100644
--- a/chrome/browser/ui/webui/devtools_ui_data_source.cc
+++ b/chrome/browser/ui/webui/devtools_ui_data_source.cc
@@ -127,6 +127,8 @@
   std::string stripped_path =
       StripDevToolsRevisionWithPrefix(path, "serve_rev/");
   stripped_path = StripDevToolsRevisionWithPrefix(stripped_path, "serve_file/");
+  stripped_path =
+      StripDevToolsRevisionWithPrefix(stripped_path, "serve_internal_file/");
   if (custom_devtools_frontend.SchemeIsFile()) {
     // Fetch from file system but strip all the params.
     StartFileRequest(PathWithoutParams(stripped_path), std::move(*callback));
diff --git a/chrome/browser/ui/webui/devtools_ui_data_source_unittest.cc b/chrome/browser/ui/webui/devtools_ui_data_source_unittest.cc
index cc70be2..b4f41411 100644
--- a/chrome/browser/ui/webui/devtools_ui_data_source_unittest.cc
+++ b/chrome/browser/ui/webui/devtools_ui_data_source_unittest.cc
@@ -255,6 +255,23 @@
   EXPECT_EQ(data(), "file: devtools_app.html");
 }
 
+TEST_F(DevToolsUIDataSourceTest,
+       TestDevToolsRemoteFileURLWithSwitchAndServeInternalFileParameters) {
+#if BUILDFLAG(IS_WIN)
+  const char* flag_value = "file://C:/tmp/";
+#else
+  const char* flag_value = "file://tmp/";
+#endif
+  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kCustomDevtoolsFrontend, flag_value);
+  const GURL path = DevToolsUrl().Resolve(DevToolsRemotePath(
+      "/serve_internal_file/@76e4c1bb2ab4671b8beba3444e61c0f17584b2fc/"
+      "devtools_app.html"));
+  StartRequest(path.path());
+  EXPECT_TRUE(data_received());
+  EXPECT_EQ(data(), "file: devtools_app.html");
+}
+
 TEST_F(DevToolsUIDataSourceTest, TestDevToolsRemoteURL) {
   const GURL path =
       DevToolsUrl().Resolve(DevToolsRemotePath(kDevToolsUITestFrontEndUrl));
diff --git a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
index 1540ee2..1a22f2a 100644
--- a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
+++ b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
@@ -185,6 +185,7 @@
      IDS_PASSWORD_MANAGER_UI_MUTED_COMPROMISED_PASSWORDS},
     {"notValidWebsite", IDS_PASSWORD_MANAGER_UI_NOT_VALID_WEB_ADDRESS},
     {"notesLabel", IDS_PASSWORD_MANAGER_UI_NOTES_LABEL},
+    {"noPasswordsFound", IDS_PASSWORD_MANAGER_UI_NO_PASSWORDS_FOUND},
     {"opensInNewTab", IDS_PASSWORD_MANAGER_UI_OPENS_IN_NEW_TAB},
     {"passwordCopiedToClipboard",
      IDS_PASSWORD_MANAGER_UI_PASSWORD_COPIED_TO_CLIPBOARD},
diff --git a/chrome/browser/ui/webui/settings/ash/DEPS b/chrome/browser/ui/webui/settings/ash/DEPS
index 9a67870..a4fb8ca 100644
--- a/chrome/browser/ui/webui/settings/ash/DEPS
+++ b/chrome/browser/ui/webui/settings/ash/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+ash/quick_pair",
   '+ash/shell.h',      # To use KeyboardCapability API in device_secion.
+  "+ash/system/power",  # To use AdaptiveChargingController API in device_secion
   "+components/account_manager_core",
   "+chrome/services/local_search_service",
   "+device/udev_linux/fake_udev_loader.h",      # For keyboard unit test.
diff --git a/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc
index 58dffc2..2db263ac 100644
--- a/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc
+++ b/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc
@@ -16,6 +16,7 @@
 #include "base/json/json_string_value_serializer.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/path_service.h"
 #include "base/ranges/algorithm.h"
@@ -76,6 +77,11 @@
 
 constexpr int kPpdMaxLineLength = 255;
 
+constexpr char kNearbyAutomaticPrintersHistogramName[] =
+    "Printing.CUPS.NearbyNetworkAutomaticPrintersCount";
+constexpr char kNearbyDiscoveredPrintersHistogramName[] =
+    "Printing.CUPS.NearbyNetworkDiscoveredPrintersCount";
+
 void OnRemovedPrinter(const Printer::PrinterProtocol& protocol, bool success) {
   if (success) {
     PRINTER_LOG(DEBUG) << "Printer removal succeeded.";
@@ -1137,6 +1143,11 @@
                     printers_manager_->GetPrinters(PrinterClass::kAutomatic));
   OnPrintersChanged(PrinterClass::kDiscovered,
                     printers_manager_->GetPrinters(PrinterClass::kDiscovered));
+
+  base::UmaHistogramCounts100(kNearbyAutomaticPrintersHistogramName,
+                              automatic_printers_.size());
+  base::UmaHistogramCounts100(kNearbyDiscoveredPrintersHistogramName,
+                              discovered_printers_.size());
   UMA_HISTOGRAM_COUNTS_100(
       "Printing.CUPS.PrintersDiscovered",
       discovered_printers_.size() + automatic_printers_.size());
diff --git a/chrome/browser/ui/webui/settings/ash/device_section.cc b/chrome/browser/ui/webui/settings/ash/device_section.cc
index 767262ee..250bbfb6 100644
--- a/chrome/browser/ui/webui/settings/ash/device_section.cc
+++ b/chrome/browser/ui/webui/settings/ash/device_section.cc
@@ -10,6 +10,7 @@
 #include "ash/public/cpp/night_light_controller.h"
 #include "ash/public/cpp/stylus_utils.h"
 #include "ash/shell.h"
+#include "ash/system/power/adaptive_charging_controller.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/metrics/histogram_functions.h"
@@ -1153,8 +1154,12 @@
         &DeviceSection::OnGotSwitchStates, weak_ptr_factory_.GetWeakPtr()));
 
     // Surface adaptive charging setting in search if the feature is enabled.
-    if (ash::features::IsAdaptiveChargingEnabled())
+    if (ash::features::IsAdaptiveChargingEnabled() &&
+        Shell::Get()
+            ->adaptive_charging_controller()
+            ->IsAdaptiveChargingSupported()) {
       updater.AddSearchTags(GetPowerWithAdaptiveChargingSearchConcepts());
+    }
   }
 
   // Keyboard/mouse search tags are added/removed dynamically.
@@ -1220,7 +1225,10 @@
   AddDevicePowerStrings(html_source);
 
   html_source->AddBoolean("isAdaptiveChargingEnabled",
-                          ash::features::IsAdaptiveChargingEnabled());
+                          ash::features::IsAdaptiveChargingEnabled() &&
+                              Shell::Get()
+                                  ->adaptive_charging_controller()
+                                  ->IsAdaptiveChargingSupported());
 }
 
 void DeviceSection::AddHandlers(content::WebUI* web_ui) {
diff --git a/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_notification_handler.mojom b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_notification_handler.mojom
index 308caf7..cc4de17 100644
--- a/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_notification_handler.mojom
+++ b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_notification_handler.mojom
@@ -16,7 +16,7 @@
   kTerminated,           // Renderer process crashed.
   kUninstalledByUser,
   kRemoved,
-  kUninstalledByMigration,
+  kUninstalledByNonUser,
 };
 
 // Implementation of App
diff --git a/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits.cc b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits.cc
index 0a433b0a..2f9ab9f 100644
--- a/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits.cc
+++ b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits.cc
@@ -25,8 +25,8 @@
       return Readiness::kUninstalledByUser;
     case apps::Readiness::kRemoved:
       return Readiness::kRemoved;
-    case apps::Readiness::kUninstalledByMigration:
-      return Readiness::kUninstalledByMigration;
+    case apps::Readiness::kUninstalledByNonUser:
+      return Readiness::kUninstalledByNonUser;
   }
 }
 
@@ -58,8 +58,8 @@
     case Readiness::kRemoved:
       *output = apps::Readiness::kRemoved;
       return true;
-    case Readiness::kUninstalledByMigration:
-      *output = apps::Readiness::kUninstalledByMigration;
+    case Readiness::kUninstalledByNonUser:
+      *output = apps::Readiness::kUninstalledByNonUser;
       return true;
   }
 }
diff --git a/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits_unittest.cc b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits_unittest.cc
index 0049c70..9333b4c 100644
--- a/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits_unittest.cc
+++ b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits_unittest.cc
@@ -19,7 +19,7 @@
       apps::Readiness::kTerminated,
       apps::Readiness::kUninstalledByUser,
       apps::Readiness::kRemoved,
-      apps::Readiness::kUninstalledByMigration};
+      apps::Readiness::kUninstalledByNonUser};
 
   for (auto readiness_in : kTestReadiness) {
     apps::Readiness readiness_out;
diff --git a/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc b/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc
index a862620..7a7ec31 100644
--- a/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc
@@ -9,6 +9,7 @@
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/audio_config_service.h"
 #include "ash/public/cpp/bluetooth_config_service.h"
+#include "ash/public/cpp/connectivity_services.h"
 #include "ash/public/cpp/esim_manager.h"
 #include "ash/public/cpp/hotspot_config_service.h"
 #include "ash/public/cpp/network_config_service.h"
@@ -309,6 +310,12 @@
           Profile::FromWebUI(web_ui()), std::move(receiver));
 }
 
+void OSSettingsUI::BindInterface(
+    mojo::PendingReceiver<chromeos::connectivity::mojom::PasspointService>
+        receiver) {
+  ash::GetPasspointService(std::move(receiver));
+}
+
 WEB_UI_CONTROLLER_TYPE_IMPL(OSSettingsUI)
 
 }  // namespace ash::settings
diff --git a/chrome/browser/ui/webui/settings/ash/os_settings_ui.h b/chrome/browser/ui/webui/settings/ash/os_settings_ui.h
index 25b56cf..a27bfde 100644
--- a/chrome/browser/ui/webui/settings/ash/os_settings_ui.h
+++ b/chrome/browser/ui/webui/settings/ash/os_settings_ui.h
@@ -24,6 +24,7 @@
 #include "chromeos/ash/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom-forward.h"
 #include "chromeos/ash/services/cellular_setup/public/mojom/cellular_setup.mojom-forward.h"
 #include "chromeos/ash/services/cellular_setup/public/mojom/esim_manager.mojom-forward.h"
+#include "chromeos/ash/services/connectivity/public/mojom/passpoint.mojom-forward.h"
 #include "chromeos/ash/services/hotspot_config/public/mojom/cros_hotspot_config.mojom-forward.h"
 #include "chromeos/ash/services/nearby/public/mojom/nearby_share_settings.mojom.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-forward.h"
@@ -169,6 +170,11 @@
   void BindInterface(
       mojo::PendingReceiver<google_drive::mojom::PageHandlerFactory> receiver);
 
+  // Binds to the cros Passpoint service.
+  void BindInterface(
+      mojo::PendingReceiver<chromeos::connectivity::mojom::PasspointService>
+          receiver);
+
  private:
   base::TimeTicks time_when_opened_;
 
diff --git a/chrome/browser/ui/webui/settings/performance_settings_interactive_uitest.cc b/chrome/browser/ui/webui/settings/performance_settings_interactive_uitest.cc
index 6799dd7..8a30468 100644
--- a/chrome/browser/ui/webui/settings/performance_settings_interactive_uitest.cc
+++ b/chrome/browser/ui/webui/settings/performance_settings_interactive_uitest.cc
@@ -31,9 +31,6 @@
 class PerformanceSettingsInteractiveTest : public InteractiveBrowserTest {
  public:
   void SetUp() override {
-    scoped_feature_list_.InitWithFeaturesAndParameters(
-        {{performance_manager::features::kBatterySaverModeAvailable, {}}}, {});
-
     ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
     SetUpFakeBatterySampler();
     InteractiveBrowserTest::SetUp();
@@ -127,7 +124,6 @@
     return WaitForStateChange(contents_id, element_renders);
   }
 
-  base::test::ScopedFeatureList scoped_feature_list_;
   raw_ptr<base::test::TestSamplingEventSource, DanglingUntriaged>
       sampling_source_;
   raw_ptr<base::test::TestBatteryLevelProvider, DanglingUntriaged>
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 2d591f20..b24d6f54 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -303,11 +303,6 @@
 #if BUILDFLAG(IS_MAC)
     {"aboutLearnMoreUpdating", IDS_SETTINGS_ABOUT_PAGE_LEARN_MORE_UPDATING},
 #endif
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
-    {"getTheMostOutOfChrome", IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME},
-    {"getTheMostOutOfChromeDescription",
-     IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_DESCRIPTION},
-#endif
   };
   html_source->AddLocalizedStrings(kLocalizedStrings);
 
@@ -349,9 +344,6 @@
   html_source->AddString("aboutTermsURL", chrome::kChromeUITermsURL);
   html_source->AddLocalizedString("aboutProductTos",
                                   IDS_ABOUT_TERMS_OF_SERVICE);
-  html_source->AddBoolean(
-      "showGetTheMostOutOfChromeSection",
-      base::FeatureList::IsEnabled(features::kGetTheMostOutOfChrome));
 #endif
 }
 
@@ -523,6 +515,26 @@
   html_source->AddLocalizedStrings(kLocalizedStrings);
 }
 
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+void AddGetTheMostOutOfChromeStrings(content::WebUIDataSource* html_source) {
+  static constexpr webui::LocalizedString kLocalizedStrings[] = {
+      {"getTheMostOutOfChrome", IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME},
+      {"getTheMostOutOfChromeDescription",
+       IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_DESCRIPTION},
+      {"getTheMostOutOfChromeIntro",
+       IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_INTRO},
+      {"getTheMostOutOfChromeMoreThanABrowser",
+       IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_MORE_THAN_A_BROWSER},
+      {"getTheMostOutOfChromeYourDataInChrome",
+       IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_YOUR_DATA_IN_CHROME},
+      {"getTheMostOutOfChromeBeyondCookies",
+       IDS_SETTINGS_GET_THE_MOST_OUT_OF_CHROME_BEYOND_COOKIES},
+  };
+
+  html_source->AddLocalizedStrings(kLocalizedStrings);
+}
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
+
 #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 void AddChromeCleanupStrings(content::WebUIDataSource* html_source) {
   const char16_t kUnwantedSoftwareProtectionWhitePaperUrl[] =
@@ -3612,6 +3624,10 @@
   AddAutofillStrings(html_source, profile, web_contents);
   AddAppearanceStrings(html_source, profile);
 
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  AddGetTheMostOutOfChromeStrings(html_source);
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
+
 #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   AddChromeCleanupStrings(html_source);
   AddIncompatibleApplicationsStrings(html_source);
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index f794183..c76632f 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -383,6 +383,12 @@
               g_browser_process->local_state()));
 #endif
 
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  html_source->AddBoolean(
+      "showGetTheMostOutOfChromeSection",
+      base::FeatureList::IsEnabled(features::kGetTheMostOutOfChrome));
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
+
   AddSettingsPageUIHandler(std::make_unique<AboutHandler>(profile));
   AddSettingsPageUIHandler(std::make_unique<ResetSettingsHandler>(profile));
 
diff --git a/chrome/browser/ui/webui/theme_source.cc b/chrome/browser/ui/webui/theme_source.cc
index 35e6c949..f0dab49 100644
--- a/chrome/browser/ui/webui/theme_source.cc
+++ b/chrome/browser/ui/webui/theme_source.cc
@@ -47,6 +47,8 @@
 #include "url/gurl.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/grit/cros_styles_resources.h"  // nogncheck crbug.com/1113869
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
@@ -120,6 +122,14 @@
     return;
   }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  constexpr char kTypographyCssPath[] = "typography.css";
+  if (parsed_path == kTypographyCssPath) {
+    SendTypographyCss(std::move(callback));
+    return;
+  }
+#endif
+
   int resource_id = -1;
   if (parsed_path == "current-channel-logo") {
     switch (chrome::GetChannel()) {
@@ -362,6 +372,22 @@
   return content::URLDataSource::GetAccessControlAllowOriginForOrigin(origin);
 }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+void ThemeSource::SendTypographyCss(
+    content::URLDataSource::GotDataCallback callback) {
+  if (!chromeos::features::IsJellyEnabled()) {
+    std::move(callback).Run(base::MakeRefCounted<base::RefCountedString>(
+        std::string("/* This file is intentionally blank */")));
+    return;
+  }
+
+  const ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  std::move(callback).Run(rb.LoadDataResourceBytesForScale(
+      IDR_CROS_STYLES_UI_CHROMEOS_STYLES_CROS_TYPOGRAPHY_CSS,
+      ui::kScaleFactorNone));
+}
+#endif
+
 std::string ThemeSource::GetContentSecurityPolicy(
     network::mojom::CSPDirectiveName directive) {
   if (directive == network::mojom::CSPDirectiveName::DefaultSrc &&
diff --git a/chrome/browser/ui/webui/theme_source.h b/chrome/browser/ui/webui/theme_source.h
index be3cd458..44abdcc 100644
--- a/chrome/browser/ui/webui/theme_source.h
+++ b/chrome/browser/ui/webui/theme_source.h
@@ -59,6 +59,10 @@
                      const content::WebContents::Getter& wc_getter,
                      content::URLDataSource::GotDataCallback callback);
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  void SendTypographyCss(content::URLDataSource::GotDataCallback callback);
+#endif
+
   // The profile this object was initialized with.
   raw_ptr<Profile, DanglingUntriaged> profile_;
 
diff --git a/chrome/browser/ui/webui/util/image_util.cc b/chrome/browser/ui/webui/util/image_util.cc
index 56ac34b..f41d026 100644
--- a/chrome/browser/ui/webui/util/image_util.cc
+++ b/chrome/browser/ui/webui/util/image_util.cc
@@ -6,9 +6,8 @@
 
 #include "base/base64.h"
 #include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkEncodedImageFormat.h"
-#include "third_party/skia/include/core/SkImageEncoder.h"
 #include "third_party/skia/include/core/SkStream.h"
+#include "third_party/skia/include/encode/SkPngEncoder.h"
 #include "ui/gfx/image/buffer_w_stream.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_rep.h"
@@ -28,7 +27,7 @@
   const SkBitmap& bitmap = image.GetRepresentation(scale_factor).GetBitmap();
   gfx::BufferWStream stream;
   const bool encoding_succeeded =
-      SkEncodeImage(&stream, bitmap, SkEncodedImageFormat::kPNG, 100);
+      SkPngEncoder::Encode(&stream, bitmap.pixmap(), {});
   DCHECK(encoding_succeeded);
   return MakeDataURIForImage(
       base::as_bytes(base::make_span(stream.TakeBuffer())), "png");
diff --git a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
index 062a4d3..f9ce353 100644
--- a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
+++ b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
@@ -298,7 +298,7 @@
     case webapps::WebappUninstallSource::kExternalPolicy:
     case webapps::WebappUninstallSource::kSystemPreinstalled:
     case webapps::WebappUninstallSource::kExternalLockScreen:
-      return apps::Readiness::kUninstalledByMigration;
+      return apps::Readiness::kUninstalledByNonUser;
   }
 }
 
diff --git a/chrome/build/lacros-arm.pgo.txt b/chrome/build/lacros-arm.pgo.txt
index a2292916..83de2b6 100644
--- a/chrome/build/lacros-arm.pgo.txt
+++ b/chrome/build/lacros-arm.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-arm-generic-main-1681156656-00cd78dfdf95a24443519a310b8e755d22168a6a.profdata
+chrome-chromeos-arm-generic-main-1681614346-415012d03c22233ac00d5c34a0a17d657a5fbd24.profdata
diff --git a/chrome/build/lacros64.pgo.txt b/chrome/build/lacros64.pgo.txt
index 53e21eb9..6e2a27c 100644
--- a/chrome/build/lacros64.pgo.txt
+++ b/chrome/build/lacros64.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-amd64-generic-main-1681473199-2166f7473b274ef3f7653c9db5c0b0621773490d.profdata
+chrome-chromeos-amd64-generic-main-1681614346-5b18450439c2ceb67f3261e8de6196acacfce9bd.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 7f6cf4c8..49be43dd 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1681473199-a05a56223b3e19c92cd02272c8eb354f00c06e41.profdata
+chrome-linux-main-1681624071-62fc11eadaa47c36575166eaecf977f9ffdaa3ee.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index fb05c19..87ca744 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1681480775-8cbae1e20fd5aa1245d119083c52b606b239261e.profdata
+chrome-mac-arm-main-1681624071-1757e068e2386988dd861b3b64b5dcf0e18d0f1a.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 4fa73ae..f40cece 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1681473199-d415bec8cc2a1e526b3cab70f031bfc59313bc30.profdata
+chrome-mac-main-1681602911-4d90d3542510d623c2153e32920b207615bc7105.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 0e57b80..2716f12 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1681473199-cdec970f222625024b1e1d79a63bdb868cdbed5e.profdata
+chrome-win32-main-1681613884-f768448c9e7536b0463f750a6c9dbda319a29e3d.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 1e1601d..9f6aece 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1681473199-4fa99eb7eee72210a706cae153ac8bf2444c361c.profdata
+chrome-win64-main-1681613884-3802caf37033ae83cbd0fe1b654314668705fa93.profdata
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index dfa978fc..4d750ac 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -293,6 +293,7 @@
         "$root_gen_dir/chrome/audio_resources.pak",
         "$root_gen_dir/chrome/bluetooth_pairing_dialog_resources.pak",
         "$root_gen_dir/chrome/cloud_upload_resources.pak",
+        "$root_gen_dir/chrome/cros_styles_resources.pak",
         "$root_gen_dir/chrome/desk_api_resources.pak",
         "$root_gen_dir/chrome/emoji_picker_resources.pak",
         "$root_gen_dir/chrome/enterprise_reporting_resources.pak",
@@ -397,6 +398,7 @@
         "//chrome/browser/resources/settings/chromeos:resources",
         "//chromeos/ash/resources",
         "//chromeos/resources",
+        "//ui/chromeos/styles:cros_styles_resources",
         "//ui/file_manager:file_manager_gen_resources",
         "//ui/file_manager:resources",
       ]
diff --git a/chrome/common/chrome_paths_internal.h b/chrome/common/chrome_paths_internal.h
index 8d13862..e7b5cc2 100644
--- a/chrome/common/chrome_paths_internal.h
+++ b/chrome/common/chrome_paths_internal.h
@@ -12,8 +12,6 @@
 #if BUILDFLAG(IS_MAC)
 #if defined(__OBJC__)
 @class NSBundle;
-#else
-class NSBundle;
 #endif
 #endif
 
@@ -63,6 +61,7 @@
 bool GetUserVideosDirectory(base::FilePath* result);
 
 #if BUILDFLAG(IS_MAC)
+
 // Most of the application is further contained within the framework, which
 // resides in the Frameworks directory of the top-level Contents folder. The
 // framework is versioned with the full product version. This function returns
@@ -76,20 +75,16 @@
 // Get the global Application Support directory (under /Library/).
 bool GetGlobalApplicationSupportDirectory(base::FilePath* result);
 
+#if defined(__OBJC__)
+
 // Returns the NSBundle for the outer browser application, even when running
 // inside the helper. In unbundled applications, such as tests, returns nil.
 NSBundle* OuterAppBundle();
 
-// Get the user data directory for the Chrome browser bundle at |bundle|.
-// |bundle| should be the same value that would be returned from +[NSBundle
-// mainBundle] if Chrome were launched normaly. This is used by app shims,
-// which run from a bundle which isn't Chrome itself, but which need access to
-// the user data directory to connect to a UNIX-domain socket therein.
-// Returns false if there was a problem fetching the app data directory.
-bool GetUserDataDirectoryForBrowserBundle(NSBundle* bundle,
-                                          base::FilePath* result);
+#endif  // __OBJC__
 
 #endif  // BUILDFLAG(IS_MAC)
+
 // Checks if the |process_type| has the rights to access the profile.
 bool ProcessNeedsProfileDir(const std::string& process_type);
 
diff --git a/chrome/common/chrome_paths_mac.mm b/chrome/common/chrome_paths_mac.mm
index 945c18d..2a03264 100644
--- a/chrome/common/chrome_paths_mac.mm
+++ b/chrome/common/chrome_paths_mac.mm
@@ -215,13 +215,6 @@
   return bundle;
 }
 
-bool GetUserDataDirectoryForBrowserBundle(NSBundle* bundle,
-                                          base::FilePath* result) {
-  std::unique_ptr<char, base::FreeDeleter> product_dir_name(
-      ProductDirNameForBundle(bundle));
-  return GetDefaultUserDataDirectoryForProduct(product_dir_name.get(), result);
-}
-
 bool ProcessNeedsProfileDir(const std::string& process_type) {
   // For now we have no reason to forbid this on other MacOS as we don't
   // have the roaming profile troubles there.
diff --git a/chrome/elevation_service/caller_validation_unittest.cc b/chrome/elevation_service/caller_validation_unittest.cc
index 55fb03a..58c8a89 100644
--- a/chrome/elevation_service/caller_validation_unittest.cc
+++ b/chrome/elevation_service/caller_validation_unittest.cc
@@ -35,7 +35,7 @@
   ASSERT_FALSE(data.empty());
 
   auto notepad_process =
-      base::LaunchProcess(L"notepad.exe", base::LaunchOptions());
+      base::LaunchProcess(L"calc.exe", base::LaunchOptions());
   ASSERT_TRUE(notepad_process.IsRunning());
 
   ASSERT_FALSE(ValidateData(notepad_process, data));
@@ -49,7 +49,7 @@
   // cares about the process path and not the process itself.
   {
     auto notepad_process =
-        base::LaunchProcess(L"notepad.exe", base::LaunchOptions());
+        base::LaunchProcess(L"calc.exe", base::LaunchOptions());
     ASSERT_TRUE(notepad_process.IsRunning());
 
     data = GenerateValidationData(ProtectionLevel::PATH_VALIDATION,
@@ -61,7 +61,7 @@
 
   {
     auto notepad_process =
-        base::LaunchProcess(L"notepad.exe", base::LaunchOptions());
+        base::LaunchProcess(L"calc.exe", base::LaunchOptions());
     ASSERT_TRUE(notepad_process.IsRunning());
 
     ASSERT_TRUE(ValidateData(notepad_process, data));
@@ -76,7 +76,7 @@
   ASSERT_FALSE(data.empty());
 
   auto notepad_process =
-      base::LaunchProcess(L"notepad.exe", base::LaunchOptions());
+      base::LaunchProcess(L"calc.exe", base::LaunchOptions());
   ASSERT_TRUE(notepad_process.IsRunning());
 
   // None validation should not care if the process is different.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 4cd5fd44..b3acae0 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3211,6 +3211,7 @@
         "../browser/extensions/service_worker_registration_apitest.cc",
         "../browser/extensions/shared_module_apitest.cc",
         "../browser/extensions/shared_worker_apitest.cc",
+        "../browser/extensions/site_permissions_helper_browsertest.cc",
         "../browser/extensions/startup_helper_browsertest.cc",
         "../browser/extensions/stubs_apitest.cc",
         "../browser/extensions/subscribe_page_action_browsertest.cc",
diff --git a/chrome/test/data/extensions/blocked_actions/content_script_at_idle/manifest.json b/chrome/test/data/extensions/blocked_actions/content_script_at_idle/manifest.json
new file mode 100644
index 0000000..422a80d
--- /dev/null
+++ b/chrome/test/data/extensions/blocked_actions/content_script_at_idle/manifest.json
@@ -0,0 +1,11 @@
+{
+  "name": "Blocked Actions Doc Idle",
+  "description": "An extension that wants to run at document idle on all urls.",
+  "version": "0.1",
+  "manifest_version": 3,
+  "content_scripts": [{
+    "matches": ["<all_urls>"],
+    "run_at": "document_idle",
+    "js": ["script.js"]
+  }]
+}
diff --git a/chrome/test/data/extensions/blocked_actions/content_script_at_idle/script.js b/chrome/test/data/extensions/blocked_actions/content_script_at_idle/script.js
new file mode 100644
index 0000000..eb157dc
--- /dev/null
+++ b/chrome/test/data/extensions/blocked_actions/content_script_at_idle/script.js
@@ -0,0 +1,10 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Set the title of the document to the success state (so that it's easily
+// readable from the C++ side).
+document.title = 'success';
+
+// Send a succeeded injection message that we can wait for in the test.
+chrome.test.sendMessage("injection succeeded");
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 3f284d1..f56f964 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -103,7 +103,6 @@
       "media_internals/media_internals_ui_browsertest.js",
       "metrics_internals/metrics_internals_ui_browsertest.js",
       "net_internals/net_internals_browsertest.js",
-      "ntp4.js",
       "password_manager/password_manager_browsertest.js",
       "privacy_sandbox/privacy_sandbox_dialog_a11y_browsertest.js",
       "privacy_sandbox/privacy_sandbox_dialog_browsertest.js",
diff --git a/chrome/test/data/webui/PRESUBMIT.py b/chrome/test/data/webui/PRESUBMIT.py
index 8dba259..f6d3a443 100644
--- a/chrome/test/data/webui/PRESUBMIT.py
+++ b/chrome/test/data/webui/PRESUBMIT.py
@@ -3,9 +3,10 @@
 # found in the LICENSE file.
 
 USE_PYTHON3 = True
+PRESUBMIT_VERSION = '2.0.0'
 
 
-def _CommonChecks(input_api, output_api):
+def CheckChange(input_api, output_api):
   results = []
   try:
     import sys
@@ -21,10 +22,19 @@
                                                          check_js=True)
   return results
 
+def CheckTestFilename(input_api, output_api):
+  results = []
 
-def CheckChangeOnUpload(input_api, output_api):
-  return _CommonChecks(input_api, output_api)
+  def IsNameInvalid(affected_file):
+    return affected_file.LocalPath().endswith('_tests.ts')
 
+  invalid_test_files = input_api.AffectedFiles(include_deletes=False,
+                                               file_filter=IsNameInvalid)
+  for f in invalid_test_files:
+    results += [
+        output_api.PresubmitError(
+            f'Disallowed \'_tests\' suffix found in \'{f}\'. WebUI test files '
+            'must end with "_test" suffix instead.')
+    ]
 
-def CheckChangeOnCommit(input_api, output_api):
-  return _CommonChecks(input_api, output_api)
+  return results
diff --git a/chrome/test/data/webui/chromeos/ash_common/BUILD.gn b/chrome/test/data/webui/chromeos/ash_common/BUILD.gn
index 13dc8e40..6c40a3a 100644
--- a/chrome/test/data/webui/chromeos/ash_common/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/ash_common/BUILD.gn
@@ -16,10 +16,10 @@
   in_files = [
     "cr_container_shadow_behavior_test.ts",
     "cr_deprecated_test.ts",
-    "cr_policy_indicator_behavior_tests.ts",
+    "cr_policy_indicator_behavior_test.ts",
     "cr_policy_strings.ts",
-    "cr_scrollable_behavior_tests.ts",
-    "list_property_update_behavior_tests.ts",
+    "cr_scrollable_behavior_test.ts",
+    "list_property_update_behavior_test.ts",
     "typescript_utils/strict_query_test.ts",
   ]
   deps = [
diff --git a/chrome/test/data/webui/chromeos/ash_common/ash_common_resources_browsertest.js b/chrome/test/data/webui/chromeos/ash_common/ash_common_resources_browsertest.js
index 383d7e3..034451e 100644
--- a/chrome/test/data/webui/chromeos/ash_common/ash_common_resources_browsertest.js
+++ b/chrome/test/data/webui/chromeos/ash_common/ash_common_resources_browsertest.js
@@ -37,7 +37,7 @@
     class extends AshCommonResourcesBrowserTest {
   /** @override */
   get browsePreload() {
-    return 'chrome://webui-test/test_loader.html?module=chromeos/ash_common/list_property_update_behavior_tests.js';
+    return 'chrome://webui-test/test_loader.html?module=chromeos/ash_common/list_property_update_behavior_test.js';
   }
 };
 
@@ -74,7 +74,7 @@
     class extends AshCommonResourcesBrowserTest {
   /** @override */
   get browsePreload() {
-    return 'chrome://webui-test/test_loader.html?module=chromeos/ash_common/cr_policy_indicator_behavior_tests.js';
+    return 'chrome://webui-test/test_loader.html?module=chromeos/ash_common/cr_policy_indicator_behavior_test.js';
   }
 };
 
@@ -86,7 +86,7 @@
     class extends AshCommonResourcesBrowserTest {
   /** @override */
   get browsePreload() {
-    return 'chrome://webui-test/test_loader.html?module=chromeos/ash_common/cr_scrollable_behavior_tests.js';
+    return 'chrome://webui-test/test_loader.html?module=chromeos/ash_common/cr_scrollable_behavior_test.js';
   }
 };
 
diff --git a/chrome/test/data/webui/chromeos/ash_common/cr_policy_indicator_behavior_tests.ts b/chrome/test/data/webui/chromeos/ash_common/cr_policy_indicator_behavior_test.ts
similarity index 100%
rename from chrome/test/data/webui/chromeos/ash_common/cr_policy_indicator_behavior_tests.ts
rename to chrome/test/data/webui/chromeos/ash_common/cr_policy_indicator_behavior_test.ts
diff --git a/chrome/test/data/webui/chromeos/ash_common/cr_scrollable_behavior_tests.ts b/chrome/test/data/webui/chromeos/ash_common/cr_scrollable_behavior_test.ts
similarity index 100%
rename from chrome/test/data/webui/chromeos/ash_common/cr_scrollable_behavior_tests.ts
rename to chrome/test/data/webui/chromeos/ash_common/cr_scrollable_behavior_test.ts
diff --git a/chrome/test/data/webui/chromeos/ash_common/list_property_update_behavior_tests.ts b/chrome/test/data/webui/chromeos/ash_common/list_property_update_behavior_test.ts
similarity index 100%
rename from chrome/test/data/webui/chromeos/ash_common/list_property_update_behavior_tests.ts
rename to chrome/test/data/webui/chromeos/ash_common/list_property_update_behavior_test.ts
diff --git a/chrome/test/data/webui/chromeos/personalization_app/dynamic_color_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/dynamic_color_element_test.ts
index a2fc0db6..30da249 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/dynamic_color_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/dynamic_color_element_test.ts
@@ -221,7 +221,8 @@
         'when the toggle is off, the static color buttons should be visible.');
     const checkedButton = getStaticColorSelector().querySelector(
                               'cr-button[aria-checked="true"]') as HTMLElement;
-    assertEquals(staticColorHex, checkedButton.dataset['staticColor']);
+    assertTrue(checkedButton.getElementsByTagName('circle')[0]!
+                   .getAttribute('style')!.includes(staticColorHex));
   });
 
   test('flips toggle', async () => {
@@ -335,9 +336,13 @@
         await personalizationStore.waitForAction(
             ThemeActionName.SET_STATIC_COLOR) as SetStaticColorAction;
     assertTrue(!!action.staticColor);
+    // Gets the style attribute of the circle, uses regex to search for the hex
+    // string, and then converts it to an SkColor.
+    const buttonSkColor = hexColorToSkColor(
+        button.getElementsByTagName('circle')[0]!.getAttribute('style')!.match(
+            '#.{6}')![0]);
     assertDeepEquals(
-        hexColorToSkColor(button.dataset['staticColor']!),
-        personalizationStore.data.theme.staticColorSelected);
+        buttonSkColor, personalizationStore.data.theme.staticColorSelected);
     assertEquals(button.getAttribute('aria-checked'), 'true');
   });
 
diff --git a/chrome/test/data/webui/chromeos/personalization_app/test_ambient_interface_provider.ts b/chrome/test/data/webui/chromeos/personalization_app/test_ambient_interface_provider.ts
index ae0f2487..e3bbfb6 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/test_ambient_interface_provider.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/test_ambient_interface_provider.ts
@@ -81,6 +81,7 @@
       'setAmbientModeEnabled',
       'setAnimationTheme',
       'setPageViewed',
+      'setScreenSaverDuration',
       'setTopicSource',
       'setTemperatureUnit',
       'setAlbumSelected',
@@ -125,6 +126,10 @@
     this.methodCalled('setAnimationTheme', animationTheme);
   }
 
+  setScreenSaverDuration(minutes: number): void {
+    this.methodCalled('setScreenSaverDuration', minutes);
+  }
+
   setTopicSource(topicSource: TopicSource) {
     this.methodCalled('setTopicSource', topicSource);
   }
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_view_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_view_test.ts
index d28245b2..451991b 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_view_test.ts
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_view_test.ts
@@ -9,7 +9,10 @@
 import {AcceleratorEditViewElement} from 'chrome://shortcut-customization/js/accelerator_edit_view.js';
 import {AcceleratorLookupManager} from 'chrome://shortcut-customization/js/accelerator_lookup_manager.js';
 import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/js/fake_data.js';
-import {AcceleratorSource, Modifier} from 'chrome://shortcut-customization/js/shortcut_types.js';
+import {FakeShortcutProvider} from 'chrome://shortcut-customization/js/fake_shortcut_provider.js';
+import {setShortcutProviderForTesting} from 'chrome://shortcut-customization/js/mojo_interface_provider.js';
+import {AcceleratorConfigResult, AcceleratorSource, Modifier} from 'chrome://shortcut-customization/js/shortcut_types.js';
+import {AcceleratorResultData} from 'chrome://shortcut-customization/mojom-webui/ash/webui/shortcut_customization_ui/mojom/shortcut_customization.mojom-webui.js';
 import {assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
 import {isVisible} from 'chrome://webui-test/test_util.js';
@@ -19,8 +22,12 @@
 suite('acceleratorEditViewTest', function() {
   let editViewElement: AcceleratorEditViewElement|null = null;
   let manager: AcceleratorLookupManager|null = null;
+  let provider: FakeShortcutProvider;
 
   setup(() => {
+    provider = new FakeShortcutProvider();
+    setShortcutProviderForTesting(provider);
+
     manager = AcceleratorLookupManager.getInstance();
     manager.setAcceleratorLookup(fakeAcceleratorConfig);
     manager.setAcceleratorLayoutLookup(fakeLayoutInfo);
@@ -72,8 +79,14 @@
     assertFalse(isVisible(getElementById('cancelButtonContainer')));
   });
 
-  // TODO(jimmyxgong): Re-enable test when ReplaceAcceleratorApi is implemented.
-  test.skip('DetectShortcutConflict', async () => {
+  test('DetectShortcutConflict', async () => {
+    const fakeResult: AcceleratorResultData = {
+      result: AcceleratorConfigResult.kConflict,
+      shortcutName: {data: [1]},
+    };
+
+    provider.setFakeReplaceAcceleratorResult(fakeResult);
+
     const acceleratorInfo = createStandardAcceleratorInfo(
         Modifier.ALT,
         /*key=*/ 221,
@@ -110,6 +123,12 @@
     await flushTasks();
     assertTrue(editViewElement!.hasError);
 
+    const fakeResult2: AcceleratorResultData = {
+      result: AcceleratorConfigResult.kSuccess,
+      shortcutName: undefined,
+    };
+
+    provider.setFakeReplaceAcceleratorResult(fakeResult2);
     // Press another shortcut, expect no error.
     viewElement!.dispatchEvent(new KeyboardEvent('keydown', {
       key: 'e',
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.ts
index fd8cd68..e6c3f2b 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.ts
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.ts
@@ -10,8 +10,11 @@
 import {AcceleratorLookupManager} from 'chrome://shortcut-customization/js/accelerator_lookup_manager.js';
 import {AcceleratorViewElement, ViewState} from 'chrome://shortcut-customization/js/accelerator_view.js';
 import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/js/fake_data.js';
+import {FakeShortcutProvider} from 'chrome://shortcut-customization/js/fake_shortcut_provider.js';
 import {InputKeyElement, KeyInputState} from 'chrome://shortcut-customization/js/input_key.js';
-import {AcceleratorSource, Modifier} from 'chrome://shortcut-customization/js/shortcut_types.js';
+import {setShortcutProviderForTesting} from 'chrome://shortcut-customization/js/mojo_interface_provider.js';
+import {AcceleratorConfigResult, AcceleratorSource, Modifier} from 'chrome://shortcut-customization/js/shortcut_types.js';
+import {AcceleratorResultData} from 'chrome://shortcut-customization/mojom-webui/ash/webui/shortcut_customization_ui/mojom/shortcut_customization.mojom-webui.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
 
@@ -28,8 +31,12 @@
   let viewElement: AcceleratorViewElement|null = null;
 
   let manager: AcceleratorLookupManager|null = null;
+  let provider: FakeShortcutProvider;
 
   setup(() => {
+    provider = new FakeShortcutProvider();
+    setShortcutProviderForTesting(provider);
+
     manager = AcceleratorLookupManager.getInstance();
     manager.setAcceleratorLookup(fakeAcceleratorConfig);
     manager.setAcceleratorLayoutLookup(fakeLayoutInfo);
@@ -109,6 +116,13 @@
     assertEquals(KeyInputState.NOT_SELECTED, pendingKey.keyState);
     assertEquals('key', pendingKey.key);
 
+    const fakeResult: AcceleratorResultData = {
+      result: AcceleratorConfigResult.kConflict,
+      shortcutName: {data: [1]},
+    };
+
+    provider.setFakeReplaceAcceleratorResult(fakeResult);
+
     // Simulate Ctrl + Alt + e.
     viewElement.dispatchEvent(new KeyboardEvent('keydown', {
       key: 'e',
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.ts
index 8d8db8b..bdae16e7 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.ts
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.ts
@@ -112,6 +112,13 @@
   });
 
   test('ReplaceAcceleratorFake', () => {
+    const fakeResult: AcceleratorResultData = {
+      result: AcceleratorConfigResult.kSuccess,
+      shortcutName: undefined,
+    };
+
+    getProvider().setFakeReplaceAcceleratorResult(fakeResult);
+
     // TODO(jimmyxgong): Remove this test once real data is ready.
     return getProvider()
         .replaceAccelerator(
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/search_box_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/search_box_test.ts
index 95deeb87..b129a23 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/search_box_test.ts
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/search_box_test.ts
@@ -15,6 +15,7 @@
 import {SearchResultRowElement} from 'chrome://shortcut-customization/js/search/search_result_row.js';
 import {setShortcutSearchHandlerForTesting} from 'chrome://shortcut-customization/js/search/shortcut_search_handler.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
 import {eventToPromise} from 'chrome://webui-test/test_util.js';
 
 suite('searchBoxTest', function() {
@@ -123,6 +124,18 @@
     assertTrue(!!searchBoxElement);
   });
 
+  test('Focus search input on open', async () => {
+    [searchBoxElement, searchFieldElement] = initSearchBoxElement();
+
+    waitAfterNextRender(searchBoxElement);
+    await flushTasks();
+
+    // The search input should be focused after the first render.
+    assertEquals(
+        searchFieldElement.shadowRoot?.activeElement,
+        searchFieldElement.getSearchInput());
+  });
+
   test('SearchResultsPopulated', async () => {
     [searchBoxElement, searchFieldElement, dropdownElement,
      resultsListElement] = initSearchBoxElement();
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts
index d394fc4..8cf8417 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts
@@ -270,9 +270,7 @@
     assertFalse(dialog.open);
   });
 
-  // TODO(jimmyxgong): Re-enable this test when ReplaceAccelerator api is
-  // used.
-  test.skip('ReplaceAccelerator', async () => {
+  test('ReplaceAccelerator', async () => {
     page = initShortcutCustomizationAppElement();
     await flushTasks();
 
@@ -298,6 +296,13 @@
     // Assert no error has occurred prior to pressing a shortcut.
     assertFalse(editView.hasError);
 
+    // Set the fake mojo return call.
+    const fakeResult: AcceleratorResultData = {
+      result: AcceleratorConfigResult.kConflictCanOverride,
+      shortcutName: strToMojoString16('TestConflictName'),
+    };
+    provider.setFakeReplaceAcceleratorResult(fakeResult);
+
     // Alt + ']' is a conflict, expect the error message to appear.
     accelViewElement!.dispatchEvent(new KeyboardEvent('keydown', {
       key: ']',
@@ -313,6 +318,12 @@
 
     assertTrue(editView.hasError);
 
+    const fakeResult2: AcceleratorResultData = {
+      result: AcceleratorConfigResult.kSuccess,
+      shortcutName: undefined,
+    };
+    provider.setFakeReplaceAcceleratorResult(fakeResult2);
+
     // Press the shortcut again, this time it will replace the preexsting
     // accelerator.
     accelViewElement!.dispatchEvent(new KeyboardEvent('keydown', {
@@ -326,40 +337,10 @@
     }));
 
     await flushTasks();
-
-    // Requery the view element.
-    const editViews =
+    const updatedEditView =
         editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
-            'accelerator-edit-view');
-    // Replacing a default accelerator will disable the default and add a new
-    // accelerator.
-    assertEquals(2, editViews!.length);
-
-    const accelViewElement1 =
-        editViews[0]!.shadowRoot!.querySelector('#acceleratorItem');
-    const acceleratorInfo1 =
-        (accelViewElement1 as AcceleratorViewElement).acceleratorInfo;
-    const actualAccelerator1 =
-        acceleratorInfo1.layoutProperties.standardAccelerator.accelerator;
-    assertEquals(
-        Modifier.COMMAND | Modifier.SHIFT, actualAccelerator1!.modifiers);
-    assertEquals(187, actualAccelerator1.keyCode);
-    assertEquals(
-        '+', acceleratorInfo1.layoutProperties.standardAccelerator.keyDisplay);
-    assertEquals(AcceleratorState.kDisabledByUser, acceleratorInfo1.state);
-
-    // Assert that the accelerator was updated with the new shortcut (Alt + ']')
-    const accelViewElement2 =
-        editViews[1]!.shadowRoot!.querySelector('#acceleratorItem');
-    const acceleratorInfo2 =
-        (accelViewElement2 as AcceleratorViewElement).acceleratorInfo;
-    const actualAccelerator2 =
-        acceleratorInfo2.layoutProperties.standardAccelerator.accelerator;
-    assertEquals(Modifier.ALT, actualAccelerator2!.modifiers);
-    assertEquals(221, actualAccelerator2.keyCode);
-    assertEquals(
-        ']', acceleratorInfo2.layoutProperties.standardAccelerator.keyDisplay);
-    assertEquals(AcceleratorState.kEnabled, acceleratorInfo2.state);
+            'accelerator-edit-view')[0] as AcceleratorEditViewElement;
+    assertFalse(updatedEditView.hasError);
   });
 
   test('AddAccelerator', async () => {
diff --git a/chrome/test/data/webui/ntp4.js b/chrome/test/data/webui/ntp4.js
deleted file mode 100644
index cd9a961..0000000
--- a/chrome/test/data/webui/ntp4.js
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2012 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-GEN('#include "build/build_config.h"');
-GEN('#include "chrome/test/data/webui/ntp4_browsertest.h"');
-GEN('#include "content/public/test/browser_test.h"');
-
-/**
- * TestFixture for NTP4 WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function NTP4WebUITest() {}
-
-NTP4WebUITest.prototype = {
-  __proto__: testing.Test.prototype,
-
-  /** @override */
-  browsePreload: 'chrome://newtab',
-};
-
-// Test loading new tab page and selecting each card doesn't have console
-// errors.
-// TODO(samarth): delete these tests along with the NTP4 code.
-TEST_F('NTP4WebUITest', 'DISABLED_TestBrowsePages', function() {
-  // This tests the ntp4 new tab page which is not used on touch builds.
-  const cardSlider = ntp.getCardSlider();
-  assertNotEquals(null, cardSlider);
-  for (let i = 0; i < cardSlider.cardCount; i++) {
-    cardSlider.selectCard(i);
-    expectEquals(i, cardSlider.currentCard);
-  }
-});
-
-// http://crbug.com/118944
-TEST_F('NTP4WebUITest', 'DISABLED_NTPHasThumbnails', function() {
-  const mostVisited = document.querySelectorAll('.most-visited');
-  assertEquals(8, mostVisited.length, 'There should be 8 most visited tiles.');
-
-  const apps = document.querySelectorAll('.app');
-  if (loadTimeData.getBoolean('showApps')) {
-    assertGE(apps.length, 1, 'There should be at least one app.');
-  } else {
-    assertEquals(0, apps.length, 'There should be no apps.');
-  }
-});
-
-TEST_F('NTP4WebUITest', 'DISABLED_NTPHasNavDots', function() {
-  const navDots = document.querySelectorAll('.dot');
-  if (loadTimeData.getBoolean('showApps')) {
-    assertGE(navDots.length, 2, 'There should be at least two navdots.');
-  } else {
-    assertEquals(1, navDots.length, 'There should be exactly one navdot.');
-  }
-});
-
-// http://crbug.com/118514
-TEST_F('NTP4WebUITest', 'DISABLED_NTPHasSelectedPageAndDot', function() {
-  const selectedDot = document.querySelectorAll('.dot.selected');
-  assertEquals(
-      1, selectedDot.length, 'There should be exactly one selected dot.');
-
-  const selectedTilePage =
-      document.querySelectorAll('.tile-page.selected-card');
-  assertEquals(
-      1, selectedTilePage.length,
-      'There should be exactly one selected tile page.');
-});
-
-TEST_F('NTP4WebUITest', 'DISABLED_NTPHasNoLoginNameWhenSignedOut', function() {
-  const userName = document.querySelector('#login-status-header .profile-name');
-  assertEquals(null, userName, 'Login name shouldn\'t exist when signed out.');
-});
-
-/**
- * Test fixture for NTP4 WebUI testing with login.
- * @extends {NTP4WebUITest}
- * @constructor
- */
-function NTP4LoggedInWebUITest() {}
-
-NTP4LoggedInWebUITest.prototype = {
-  __proto__: NTP4WebUITest.prototype,
-
-  /** @override */
-  typedefCppFixture: 'NTP4LoggedInWebUITest',
-
-  /** @override */
-  testGenPreamble: function() {
-    GEN('  SetLoginName("user@gmail.com");');
-  },
-};
-
-// The following test is irrelevant to Chrome on Chrome OS.
-GEN('#if !BUILDFLAG(IS_CHROMEOS)');
-
-TEST_F(
-    'NTP4LoggedInWebUITest', 'DISABLED_NTPHasLoginNameWhenSignedIn',
-    function() {
-      const userName =
-          document.querySelector('#login-status-header .profile-name');
-      assertNotEquals(
-          userName, null, 'The logged-in user name can\'t be found.');
-      assertEquals(
-          'user@gmail.com', userName.textContent,
-          'The user name should be present on the new tab.');
-    });
-
-GEN('#endif');
diff --git a/chrome/test/data/webui/password_manager/passwords_section_test.ts b/chrome/test/data/webui/password_manager/passwords_section_test.ts
index 0372129d..3275fdb 100644
--- a/chrome/test/data/webui/password_manager/passwords_section_test.ts
+++ b/chrome/test/data/webui/password_manager/passwords_section_test.ts
@@ -474,4 +474,95 @@
     assertTrue(!!movdeDialog);
     assertTrue(movdeDialog.$.dialog.open);
   });
+
+  test('description is hidden during search', async function() {
+    passwordManager.data.groups = [
+      createCredentialGroup({
+        name: 'foo.com',
+      }),
+      createCredentialGroup({
+        name: 'bar.com',
+      }),
+    ];
+
+    const section = await createPasswordsSection();
+
+    assertTrue(isVisible(section.$.descriptionLabel));
+
+    const query = new URLSearchParams();
+    query.set(UrlParam.SEARCH_TERM, 'bar');
+    Router.getInstance().updateRouterParams(query);
+    await flushTasks();
+
+    assertFalse(isVisible(section.$.descriptionLabel));
+  });
+
+  test('Move passwords is hidden during search', async function() {
+    passwordManager.data.isOptedInAccountStorage = true;
+    passwordManager.data.groups = [createCredentialGroup({
+      name: 'test.com',
+      credentials: [createPasswordEntry({
+        username: 'user',
+        id: 0,
+        inProfileStore: true,
+        affiliatedDomains: [createAffiliatedDomain('test.com')],
+      })],
+    })];
+    passwordManager.setRequestCredentialsDetailsResponse(
+        passwordManager.data.groups[0]!.entries);
+    syncProxy.syncInfo = {
+      isEligibleForAccountStorage: true,
+      isSyncingPasswords: false,
+    };
+
+    const section = await createPasswordsSection();
+
+    assertTrue(isVisible(section.$.movePasswords));
+
+    const query = new URLSearchParams();
+    query.set(UrlParam.SEARCH_TERM, 'bar');
+    Router.getInstance().updateRouterParams(query);
+    await flushTasks();
+
+    assertFalse(isVisible(section.$.movePasswords));
+  });
+
+  test('No password is shown when no matches', async function() {
+    passwordManager.data.groups = [
+      createCredentialGroup({
+        name: 'foo.com',
+      }),
+      createCredentialGroup({
+        name: 'bar.com',
+      }),
+    ];
+
+    const section = await createPasswordsSection();
+
+    assertFalse(isVisible(section.$.noPasswordsFound));
+
+    const query = new URLSearchParams();
+    query.set(UrlParam.SEARCH_TERM, 'bar');
+    Router.getInstance().updateRouterParams(query);
+    await flushTasks();
+    assertFalse(isVisible(section.$.noPasswordsFound));
+
+    query.set(UrlParam.SEARCH_TERM, 'bar.org');
+    Router.getInstance().updateRouterParams(query);
+    await flushTasks();
+    assertTrue(isVisible(section.$.noPasswordsFound));
+  });
+
+  test('No password is hidden when there are no passwords', async function() {
+    const section = await createPasswordsSection();
+
+    assertFalse(isVisible(section.$.noPasswordsFound));
+
+    const query = new URLSearchParams();
+    query.set(UrlParam.SEARCH_TERM, 'test');
+    Router.getInstance().updateRouterParams(query);
+    await flushTasks();
+
+    assertFalse(isVisible(section.$.noPasswordsFound));
+  });
 });
diff --git a/chrome/test/data/webui/settings/advanced_page_test.ts b/chrome/test/data/webui/settings/advanced_page_test.ts
index dd31556..983d15c 100644
--- a/chrome/test/data/webui/settings/advanced_page_test.ts
+++ b/chrome/test/data/webui/settings/advanced_page_test.ts
@@ -5,11 +5,11 @@
 /** @fileoverview Suite of tests for the Settings advanced page. */
 
 // clang-format off
-// <if expr="_google_chrome">
-import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
-// </if>
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {CrSettingsPrefs, SettingsBasicPageElement, SettingsSectionElement} from 'chrome://settings/settings.js';
+// <if expr="_google_chrome">
+import {loadTimeData} from 'chrome://settings/settings.js';
+// </if>
 import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
 
 import {getPage, getSection} from './settings_page_test_util.js';
diff --git a/chrome/test/data/webui/settings/chromeos/BUILD.gn b/chrome/test/data/webui/settings/chromeos/BUILD.gn
index 683e7c4d..4d26c0cc 100644
--- a/chrome/test/data/webui/settings/chromeos/BUILD.gn
+++ b/chrome/test/data/webui/settings/chromeos/BUILD.gn
@@ -69,7 +69,7 @@
     "internet_subpage_menu_test.js",
     "kerberos_accounts_test.js",
     "kerberos_page_test.js",
-    "lock_screen_subpage_tests.ts",
+    "lock_screen_subpage_test.ts",
     "manage_users_subpage_tests.js",
     "multidevice_feature_item_tests.js",
     "multidevice_feature_toggle_tests.js",
@@ -193,26 +193,26 @@
     "keyboard_shortcut_banner/keyboard_shortcut_banner_test.ts",
 
     "multidevice_page/multidevice_page_tests.js",
-    "multidevice_page/multidevice_combined_setup_item_tests.ts",
+    "multidevice_page/multidevice_combined_setup_item_test.ts",
     "multidevice_page/multidevice_notification_access_setup_dialog_tests.js",
     "multidevice_page/multidevice_permissions_setup_dialog_tests.js",
     "multidevice_page/multidevice_smartlock_item_test.ts",
     "multidevice_page/multidevice_subpage_tests.js",
-    "multidevice_page/multidevice_wifi_sync_item_tests.ts",
+    "multidevice_page/multidevice_wifi_sync_item_test.ts",
     "multidevice_page/test_multidevice_browser_proxy.ts",
 
     "nearby_share_page/nearby_share_confirm_page_test.ts",
     "nearby_share_page/nearby_share_high_visibility_page_test.ts",
 
-    "os_a11y_page/audio_and_captions_page_tests.ts",
-    "os_a11y_page/cursor_and_touchpad_page_tests.ts",
-    "os_a11y_page/display_and_magnification_page_tests.ts",
-    "os_a11y_page/keyboard_and_text_input_page_tests.ts",
-    "os_a11y_page/manage_accessibility_page_tests.ts",
-    "os_a11y_page/os_a11y_page_tests.ts",
+    "os_a11y_page/audio_and_captions_page_test.ts",
+    "os_a11y_page/cursor_and_touchpad_page_test.ts",
+    "os_a11y_page/display_and_magnification_page_test.ts",
+    "os_a11y_page/keyboard_and_text_input_page_test.ts",
+    "os_a11y_page/manage_accessibility_page_test.ts",
+    "os_a11y_page/os_a11y_page_test.ts",
     "os_a11y_page/test_os_a11y_page_browser_proxy.ts",
-    "os_a11y_page/text_to_speech_page_tests.ts",
-    "os_a11y_page/text_to_speech_subpage_tests.ts",
+    "os_a11y_page/text_to_speech_page_test.ts",
+    "os_a11y_page/text_to_speech_subpage_test.ts",
     "os_a11y_page/tts_subpage_test.ts",
 
     "os_bluetooth_page/os_bluetooth_change_device_name_dialog_tests.js",
@@ -227,15 +227,15 @@
     "os_files_page/google_drive_page_test.ts",
     "os_files_page/office_page_test.ts",
     "os_files_page/os_files_page_test.ts",
-    "os_files_page/smb_shares_page_tests.ts",
+    "os_files_page/smb_shares_page_test.ts",
 
     "os_languages_page/smart_inputs_page_test.ts",
 
-    "os_people_page/add_user_dialog_tests.ts",
+    "os_people_page/add_user_dialog_test.ts",
 
-    "os_printing_page/os_printing_page_tests.ts",
+    "os_printing_page/os_printing_page_test.ts",
 
-    "os_privacy_page/smart_privacy_subpage_tests.ts",
+    "os_privacy_page/smart_privacy_subpage_test.ts",
 
     "os_search_page/search_subpage_test.ts",
 
diff --git a/chrome/test/data/webui/settings/chromeos/lock_screen_subpage_tests.ts b/chrome/test/data/webui/settings/chromeos/lock_screen_subpage_test.ts
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/lock_screen_subpage_tests.ts
rename to chrome/test/data/webui/settings/chromeos/lock_screen_subpage_test.ts
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_page/multidevice_combined_setup_item_tests.ts b/chrome/test/data/webui/settings/chromeos/multidevice_page/multidevice_combined_setup_item_test.ts
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/multidevice_page/multidevice_combined_setup_item_tests.ts
rename to chrome/test/data/webui/settings/chromeos/multidevice_page/multidevice_combined_setup_item_test.ts
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_page/multidevice_wifi_sync_item_tests.ts b/chrome/test/data/webui/settings/chromeos/multidevice_page/multidevice_wifi_sync_item_test.ts
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/multidevice_page/multidevice_wifi_sync_item_tests.ts
rename to chrome/test/data/webui/settings/chromeos/multidevice_page/multidevice_wifi_sync_item_test.ts
diff --git a/chrome/test/data/webui/settings/chromeos/os_a11y_page/audio_and_captions_page_tests.ts b/chrome/test/data/webui/settings/chromeos/os_a11y_page/audio_and_captions_page_test.ts
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/os_a11y_page/audio_and_captions_page_tests.ts
rename to chrome/test/data/webui/settings/chromeos/os_a11y_page/audio_and_captions_page_test.ts
diff --git a/chrome/test/data/webui/settings/chromeos/os_a11y_page/cursor_and_touchpad_page_tests.ts b/chrome/test/data/webui/settings/chromeos/os_a11y_page/cursor_and_touchpad_page_test.ts
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/os_a11y_page/cursor_and_touchpad_page_tests.ts
rename to chrome/test/data/webui/settings/chromeos/os_a11y_page/cursor_and_touchpad_page_test.ts
diff --git a/chrome/test/data/webui/settings/chromeos/os_a11y_page/display_and_magnification_page_tests.ts b/chrome/test/data/webui/settings/chromeos/os_a11y_page/display_and_magnification_page_test.ts
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/os_a11y_page/display_and_magnification_page_tests.ts
rename to chrome/test/data/webui/settings/chromeos/os_a11y_page/display_and_magnification_page_test.ts
diff --git a/chrome/test/data/webui/settings/chromeos/os_a11y_page/keyboard_and_text_input_page_tests.ts b/chrome/test/data/webui/settings/chromeos/os_a11y_page/keyboard_and_text_input_page_test.ts
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/os_a11y_page/keyboard_and_text_input_page_tests.ts
rename to chrome/test/data/webui/settings/chromeos/os_a11y_page/keyboard_and_text_input_page_test.ts
diff --git a/chrome/test/data/webui/settings/chromeos/os_a11y_page/manage_accessibility_page_tests.ts b/chrome/test/data/webui/settings/chromeos/os_a11y_page/manage_accessibility_page_test.ts
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/os_a11y_page/manage_accessibility_page_tests.ts
rename to chrome/test/data/webui/settings/chromeos/os_a11y_page/manage_accessibility_page_test.ts
diff --git a/chrome/test/data/webui/settings/chromeos/os_a11y_page/os_a11y_page_tests.ts b/chrome/test/data/webui/settings/chromeos/os_a11y_page/os_a11y_page_test.ts
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/os_a11y_page/os_a11y_page_tests.ts
rename to chrome/test/data/webui/settings/chromeos/os_a11y_page/os_a11y_page_test.ts
diff --git a/chrome/test/data/webui/settings/chromeos/os_a11y_page/text_to_speech_page_tests.ts b/chrome/test/data/webui/settings/chromeos/os_a11y_page/text_to_speech_page_test.ts
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/os_a11y_page/text_to_speech_page_tests.ts
rename to chrome/test/data/webui/settings/chromeos/os_a11y_page/text_to_speech_page_test.ts
diff --git a/chrome/test/data/webui/settings/chromeos/os_a11y_page/text_to_speech_subpage_tests.ts b/chrome/test/data/webui/settings/chromeos/os_a11y_page/text_to_speech_subpage_test.ts
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/os_a11y_page/text_to_speech_subpage_tests.ts
rename to chrome/test/data/webui/settings/chromeos/os_a11y_page/text_to_speech_subpage_test.ts
diff --git a/chrome/test/data/webui/settings/chromeos/os_files_page/smb_shares_page_tests.ts b/chrome/test/data/webui/settings/chromeos/os_files_page/smb_shares_page_test.ts
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/os_files_page/smb_shares_page_tests.ts
rename to chrome/test/data/webui/settings/chromeos/os_files_page/smb_shares_page_test.ts
diff --git a/chrome/test/data/webui/settings/chromeos/os_people_page/add_user_dialog_tests.ts b/chrome/test/data/webui/settings/chromeos/os_people_page/add_user_dialog_test.ts
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/os_people_page/add_user_dialog_tests.ts
rename to chrome/test/data/webui/settings/chromeos/os_people_page/add_user_dialog_test.ts
diff --git a/chrome/test/data/webui/settings/chromeos/os_printing_page/os_printing_page_tests.ts b/chrome/test/data/webui/settings/chromeos/os_printing_page/os_printing_page_test.ts
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/os_printing_page/os_printing_page_tests.ts
rename to chrome/test/data/webui/settings/chromeos/os_printing_page/os_printing_page_test.ts
diff --git a/chrome/test/data/webui/settings/chromeos/os_privacy_page/smart_privacy_subpage_tests.ts b/chrome/test/data/webui/settings/chromeos/os_privacy_page/smart_privacy_subpage_test.ts
similarity index 100%
rename from chrome/test/data/webui/settings/chromeos/os_privacy_page/smart_privacy_subpage_tests.ts
rename to chrome/test/data/webui/settings/chromeos/os_privacy_page/smart_privacy_subpage_test.ts
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
index c2a2b7b..a23e0a01 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
@@ -359,7 +359,7 @@
    'KeyboardShortcutBanner',
    'keyboard_shortcut_banner/keyboard_shortcut_banner_test.js'
  ],
- ['LockScreenSubpage', 'lock_screen_subpage_tests.js'],
+ ['LockScreenSubpage', 'lock_screen_subpage_test.js'],
  ['ManageUsersSubpage', 'manage_users_subpage_tests.js'],
  // TODO(b/208932892): Re-enable once flakiness is fixed.
  // ['MultideviceFeatureItem', 'multidevice_feature_item_tests.js'],
@@ -383,11 +383,11 @@
  ],
  [
    'MultiDevicePageMultideviceCombinedSetupItem',
-   'multidevice_page/multidevice_combined_setup_item_tests.js'
+   'multidevice_page/multidevice_combined_setup_item_test.js'
  ],
  [
    'MultidevicePageMultideviceWifiSyncItem',
-   'multidevice_page/multidevice_wifi_sync_item_tests.js'
+   'multidevice_page/multidevice_wifi_sync_item_test.js'
  ],
  [
    'MultideviceTaskContinuationItem',
@@ -421,37 +421,37 @@
  ['OncMojoTest', 'onc_mojo_test.js'],
  [
    'OsA11yPage',
-   'os_a11y_page/os_a11y_page_tests.js',
+   'os_a11y_page/os_a11y_page_test.js',
    {enabled: ['features::kPdfOcr']},
  ],
  [
    'OsA11yPageAudioAndCaptionsPage',
-   'os_a11y_page/audio_and_captions_page_tests.js',
+   'os_a11y_page/audio_and_captions_page_test.js',
  ],
  [
    'OsA11yPageCursorAndTouchpadPage',
-   'os_a11y_page/cursor_and_touchpad_page_tests.js',
+   'os_a11y_page/cursor_and_touchpad_page_test.js',
  ],
  [
    'OsA11yPageDisplayAndMagnificationPage',
-   'os_a11y_page/display_and_magnification_page_tests.js',
+   'os_a11y_page/display_and_magnification_page_test.js',
  ],
  [
    'OsA11yPageKeyboardAndTextInputPage',
-   'os_a11y_page/keyboard_and_text_input_page_tests.js',
+   'os_a11y_page/keyboard_and_text_input_page_test.js',
  ],
  [
    'OsA11yPageManageAccessibilityPage',
-   'os_a11y_page/manage_accessibility_page_tests.js'
+   'os_a11y_page/manage_accessibility_page_test.js'
  ],
  [
    'OsA11yPageTextToSpeechPage',
-   'os_a11y_page/text_to_speech_page_tests.js',
+   'os_a11y_page/text_to_speech_page_test.js',
    {enabled: ['features::kPdfOcr']},
  ],
  [
    'OsA11yPageTextToSpeechSubpage',
-   'os_a11y_page/text_to_speech_subpage_tests.js',
+   'os_a11y_page/text_to_speech_subpage_test.js',
  ],
  ['OsA11yPageTtsSubpage', 'os_a11y_page/tts_subpage_test.js'],
  ['OsBluetoothPage', 'os_bluetooth_page/os_bluetooth_page_tests.js'],
@@ -483,7 +483,7 @@
  ['OsFilesPage', 'os_files_page/os_files_page_test.js'],
  ['OsFilesPageGoogleDrivePage', 'os_files_page/google_drive_page_test.js'],
  ['OsFilesPageOfficePage', 'os_files_page/office_page_test.js'],
- ['OsFilesPageSmbSharesPage', 'os_files_page/smb_shares_page_tests.js'],
+ ['OsFilesPageSmbSharesPage', 'os_files_page/smb_shares_page_test.js'],
  [
    'OsLanguagesPageSmartInputsPage',
    'os_languages_page/smart_inputs_page_test.js'
@@ -491,11 +491,11 @@
  ['OsLanguagesPageV2', 'os_languages_page_v2_tests.js'],
  ['OsPairedBluetoothList', 'os_paired_bluetooth_list_tests.js'],
  ['OsPairedBluetoothListItem', 'os_paired_bluetooth_list_item_tests.js'],
- ['OsPeoplePageAddUserDialog', 'os_people_page/add_user_dialog_tests.js'],
- ['OsPrintingPage', 'os_printing_page/os_printing_page_tests.js'],
+ ['OsPeoplePageAddUserDialog', 'os_people_page/add_user_dialog_test.js'],
+ ['OsPrintingPage', 'os_printing_page/os_printing_page_test.js'],
  [
    'OsPrivacyPageSmartPrivacySubpage',
-   'os_privacy_page/smart_privacy_subpage_tests.js'
+   'os_privacy_page/smart_privacy_subpage_test.js'
  ],
  ['OsSearchPageSearchSubpage', 'os_search_page/search_subpage_test.js'],
  ['OsSettingsHatsUi', 'os_settings_ui/os_settings_hats_ui_test.js'],
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index 58b4e89d..28df66f 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -466,15 +466,6 @@
   get browsePreload() {
     return 'chrome://settings/test_loader.html?module=settings/settings_performance_menu_test.js';
   }
-
-  /** @override */
-  get featureListInternal() {
-    return {
-      enabled: [
-        'performance_manager::features::kBatterySaverModeAvailable',
-      ],
-    };
-  }
 };
 
 TEST_F('CrSettingsPerformanceMenuTest', 'All', function() {
@@ -497,15 +488,6 @@
   get browsePreload() {
     return 'chrome://settings/test_loader.html?module=settings/battery_page_test.js';
   }
-
-  /** @override */
-  get featureListInternal() {
-    return {
-      enabled: [
-        'performance_manager::features::kBatterySaverModeAvailable',
-      ],
-    };
-  }
 };
 
 TEST_F('CrSettingsBatteryPageTest', 'All', function() {
diff --git a/chrome/test/data/webui/settings/get_most_chrome_page_test.ts b/chrome/test/data/webui/settings/get_most_chrome_page_test.ts
index 68cafbb..81d45f7 100644
--- a/chrome/test/data/webui/settings/get_most_chrome_page_test.ts
+++ b/chrome/test/data/webui/settings/get_most_chrome_page_test.ts
@@ -5,8 +5,8 @@
 import 'chrome://settings/lazy_load.js';
 
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {SettingsGetMostChromePageElement} from 'chrome://settings/lazy_load.js';
-import {assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {IronCollapseElement, SettingsGetMostChromePageElement} from 'chrome://settings/lazy_load.js';
+import {assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 
 /** @fileoverview Suite of tests for get_most_chrome_page. */
 suite('GetMostChromePage', function() {
@@ -20,7 +20,15 @@
   });
 
   test('Basic', function() {
-    assertTrue(!!testElement);
-    // TODO(crbug.com/143278): Expand this test as the element gets implemented.
+    const rows = testElement.shadowRoot!.querySelectorAll('cr-expand-button');
+    assertTrue(rows.length > 0);
+    rows.forEach((row) => {
+      const ironCollapse = row.nextElementSibling as IronCollapseElement;
+      assertTrue(!!ironCollapse);
+
+      assertFalse(ironCollapse.opened);
+      row.click();
+      assertTrue(ironCollapse.opened);
+    });
   });
 });
diff --git a/chrome/test/data/webui/settings/passwords_import_dialog_test.ts b/chrome/test/data/webui/settings/passwords_import_dialog_test.ts
index 89dd873..8e75c55 100644
--- a/chrome/test/data/webui/settings/passwords_import_dialog_test.ts
+++ b/chrome/test/data/webui/settings/passwords_import_dialog_test.ts
@@ -57,6 +57,28 @@
   assertEquals(0, selectedIds.length);
 }
 
+async function continueImportWithConflictsHelper(
+    importDialog: PasswordsImportDialogElement,
+    passwordManager: TestPasswordManagerProxy,
+    expectedSelectedIdsCount: number) {
+  assertTrue(isVisible(importDialog.$.replace));
+  assertFalse(importDialog.$.replace.disabled);
+  importDialog.$.replace.click();
+  flush();
+
+  // In progress state after the click.
+  const spinner = importDialog.shadowRoot!.querySelector('paper-spinner-lite');
+  assertTrue(!!spinner);
+  assertTrue(spinner.active);
+  assertTrue(importDialog.$.skip.disabled);
+  assertTrue(importDialog.$.close.disabled);
+  assertTrue(importDialog.$.replace.disabled);
+
+  // Import flow should have been triggered.
+  const selectedIds = await passwordManager.whenCalled('continueImport');
+  assertEquals(expectedSelectedIdsCount, selectedIds.length);
+}
+
 function assertIntialStatePartsAndClose(
     importDialog: PasswordsImportDialogElement, expectedDescription: string) {
   assertEquals(ImportDialogState.START, importDialog.dialogState);
@@ -321,6 +343,59 @@
     await eventToPromise('close', importDialog);
   });
 
+  test('canContinueImportWithConflicts', async function() {
+    loadTimeData.overrideValues({enablePasswordsImportM2: true});
+    const importDialog = elementFactory.createPasswordsImportDialog();
+    assertEquals(ImportDialogState.START, importDialog.dialogState);
+    passwordManager.setImportResults({
+      status: chrome.passwordsPrivate.ImportResultsStatus.CONFLICTS,
+      numberImported: 0,
+      displayedEntries: [
+        {
+          status: chrome.passwordsPrivate.ImportEntryStatus.VALID,
+          username: 'username',
+          url: 'https://google.com',
+          password: 'pwd',
+          id: 0,
+        },
+        {
+          status: chrome.passwordsPrivate.ImportEntryStatus.VALID,
+          username: 'username',
+          url: 'https://test.com',
+          password: 'pwd',
+          id: 1,
+        },
+      ],
+      fileName: 'test.csv',
+    });
+
+    await triggerImportHelper(importDialog, passwordManager);
+    await pluralString.whenCalled('getPluralString');
+    flush();
+    // After the import attempt, the dialog should switch to CONFLICTS state.
+    assertEquals(ImportDialogState.CONFLICTS, importDialog.dialogState);
+
+    passwordManager.setImportResults({
+      status: chrome.passwordsPrivate.ImportResultsStatus.SUCCESS,
+      numberImported: 42,
+      displayedEntries: [],
+      fileName: 'test.csv',
+    });
+
+    importDialog.$.conflictsList.querySelectorAll('cr-checkbox')
+        .forEach(checkbox => {
+          checkbox.click();
+          flush();
+        });
+
+    await continueImportWithConflictsHelper(
+        importDialog, passwordManager, /*expectedSelectedIdsCount=*/ 2);
+    await pluralString.whenCalled('getPluralString');
+    flush();
+    // After the import, the dialog should switch to SUCCESS state.
+    assertEquals(ImportDialogState.SUCCESS, importDialog.dialogState);
+  });
+
   test('canSkipConflicts', async function() {
     loadTimeData.overrideValues({enablePasswordsImportM2: true});
     const importDialog = elementFactory.createPasswordsImportDialog();
@@ -346,8 +421,6 @@
       ],
       fileName: 'test.csv',
     });
-    const expectedTitle = '2 existing passwords found';
-    pluralString.text = expectedTitle;
 
     await triggerImportHelper(importDialog, passwordManager);
     await pluralString.whenCalled('getPluralString');
diff --git a/chrome/test/data/webui/settings/settings_menu_test.ts b/chrome/test/data/webui/settings/settings_menu_test.ts
index 03584a72..92d2eaac 100644
--- a/chrome/test/data/webui/settings/settings_menu_test.ts
+++ b/chrome/test/data/webui/settings/settings_menu_test.ts
@@ -7,7 +7,13 @@
 // clang-format off
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {pageVisibility, Router, routes, SettingsMenuElement} from 'chrome://settings/settings.js';
+// <if expr="_google_chrome">
+import {loadTimeData} from 'chrome://settings/settings.js';
+// </if>
 import {assertEquals, assertFalse} from 'chrome://webui-test/chai_assert.js';
+// <if expr="_google_chrome">
+import {assertTrue} from 'chrome://webui-test/chai_assert.js';
+// </if>
 
 // clang-format on
 
@@ -48,6 +54,9 @@
   let settingsMenu: SettingsMenuElement;
 
   setup(function() {
+    // <if expr="_google_chrome">
+    loadTimeData.overrideValues({showGetTheMostOutOfChromeSection: true});
+    // </if>
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
     Router.getInstance().navigateTo(routes.RESET, undefined);
     settingsMenu = document.createElement('settings-menu');
@@ -89,6 +98,20 @@
     assertFalse(!!selector.selected);
   });
 
+  // <if expr="_google_chrome">
+  // TODO(crbug.com/1433405): Fix and re-enable.
+  test.skip('navigateToGetMostChrome', function() {
+    Router.getInstance().navigateTo(routes.GET_MOST_CHROME, undefined);
+    flush();
+
+    // GET_MOST_CHROME should select the 'About Chrome' entry.
+    const selector = settingsMenu.$.menu;
+    assertTrue(!!selector.selected);
+    const path = new window.URL(selector.selected.toString()).pathname;
+    assertEquals('/help', path);
+  });
+  // </if>
+
   test('pageVisibility', function() {
     function assertPagesHidden(expectedHidden: boolean) {
       const ids = [
diff --git a/chrome/utility/safe_browsing/mac/dmg_iterator.cc b/chrome/utility/safe_browsing/mac/dmg_iterator.cc
index a42ab7a..750fb9b 100644
--- a/chrome/utility/safe_browsing/mac/dmg_iterator.cc
+++ b/chrome/utility/safe_browsing/mac/dmg_iterator.cc
@@ -23,26 +23,19 @@
 DMGIterator::~DMGIterator() {}
 
 bool DMGIterator::Open() {
-  bool udif_success = udif_.Parse();
-  base::UmaHistogramBoolean("SBClientDownload.DmgParsedUdif", udif_success);
-  if (!udif_success)
+  if (!udif_.Parse()) {
     return false;
+  }
 
   // Collect all the HFS partitions up-front. The data are accessed lazily, so
   // this is relatively inexpensive.
-  bool has_apfs = false;
   for (size_t i = 0; i < udif_.GetNumberOfPartitions(); ++i) {
     std::unique_ptr<ReadStream> partition = udif_.GetPartitionReadStream(i);
     HFSIterator hfs(partition.get());
     if (hfs.Open()) {
       partitions_.push_back(std::move(partition));
     }
-
-    if (udif_.GetPartitionType(i) == "Apple_APFS") {
-      has_apfs = true;
-    }
   }
-  base::UmaHistogramBoolean("SBClientDownload.DmgHasAPFS", has_apfs);
 
   return true;
 }
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 62c4c47..faa8a99 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-15419.0.0
\ No newline at end of file
+15424.0.0
\ No newline at end of file
diff --git a/chromeos/ash/components/nearby/presence/BUILD.gn b/chromeos/ash/components/nearby/presence/BUILD.gn
index 1fdabd7..762da12 100644
--- a/chromeos/ash/components/nearby/presence/BUILD.gn
+++ b/chromeos/ash/components/nearby/presence/BUILD.gn
@@ -13,6 +13,8 @@
     "nearby_presence_service.h",
     "nearby_presence_service_impl.cc",
     "nearby_presence_service_impl.h",
+    "prefs/nearby_presence_prefs.cc",
+    "prefs/nearby_presence_prefs.h",
   ]
 
   deps = [
@@ -26,6 +28,7 @@
     "//components/keyed_service/core",
     "//components/pref_registry:pref_registry",
     "//components/prefs",
+    "//content/public/browser",
   ]
 }
 
@@ -42,6 +45,9 @@
     "//base/test:test_support",
     "//chromeos/ash/components/nearby/presence:presence",
     "//chromeos/ash/components/nearby/presence/credentials:unit_tests",
+    "//components/prefs:prefs",
+    "//components/prefs:test_support",
+    "//content/public/browser",
     "//mojo/public/cpp/bindings:bindings",
     "//testing/gtest",
   ]
diff --git a/chromeos/ash/components/nearby/presence/nearby_presence_service_impl.cc b/chromeos/ash/components/nearby/presence/nearby_presence_service_impl.cc
index 52994129..f12b2d2 100644
--- a/chromeos/ash/components/nearby/presence/nearby_presence_service_impl.cc
+++ b/chromeos/ash/components/nearby/presence/nearby_presence_service_impl.cc
@@ -3,11 +3,19 @@
 // found in the LICENSE file.
 
 #include "chromeos/ash/components/nearby/presence/nearby_presence_service_impl.h"
+
 #include "base/check.h"
+#include "base/logging.h"
+#include "chromeos/ash/components/nearby/presence/prefs/nearby_presence_prefs.h"
+#include "components/prefs/pref_service.h"
 
 namespace ash::nearby::presence {
 
-NearbyPresenceServiceImpl::NearbyPresenceServiceImpl() = default;
+NearbyPresenceServiceImpl::NearbyPresenceServiceImpl(PrefService* pref_service)
+    : pref_service_(pref_service) {
+  CHECK(pref_service_);
+}
+
 NearbyPresenceServiceImpl::~NearbyPresenceServiceImpl() = default;
 
 std::unique_ptr<NearbyPresenceService::ScanSession>
diff --git a/chromeos/ash/components/nearby/presence/nearby_presence_service_impl.h b/chromeos/ash/components/nearby/presence/nearby_presence_service_impl.h
index 3e2dfc5..6cce4cc 100644
--- a/chromeos/ash/components/nearby/presence/nearby_presence_service_impl.h
+++ b/chromeos/ash/components/nearby/presence/nearby_presence_service_impl.h
@@ -8,15 +8,14 @@
 #include "chromeos/ash/components/nearby/presence/nearby_presence_service.h"
 #include "components/keyed_service/core/keyed_service.h"
 
-#include <memory>
-#include <string>
+class PrefService;
 
 namespace ash::nearby::presence {
 
 class NearbyPresenceServiceImpl : public NearbyPresenceService,
                                   public KeyedService {
  public:
-  NearbyPresenceServiceImpl();
+  explicit NearbyPresenceServiceImpl(PrefService* pref_service);
   NearbyPresenceServiceImpl(const NearbyPresenceServiceImpl&) = delete;
   NearbyPresenceServiceImpl& operator=(const NearbyPresenceServiceImpl&) =
       delete;
@@ -29,6 +28,8 @@
  private:
   // KeyedService:
   void Shutdown() override;
+
+  PrefService* pref_service_ = nullptr;
 };
 
 }  // namespace ash::nearby::presence
diff --git a/chromeos/ash/components/nearby/presence/nearby_presence_service_impl_unittest.cc b/chromeos/ash/components/nearby/presence/nearby_presence_service_impl_unittest.cc
index f014ef0..38fbe8d 100644
--- a/chromeos/ash/components/nearby/presence/nearby_presence_service_impl_unittest.cc
+++ b/chromeos/ash/components/nearby/presence/nearby_presence_service_impl_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "chromeos/ash/components/nearby/presence/nearby_presence_service_impl.h"
 
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -50,10 +52,14 @@
 
   // testing::Test:
   void SetUp() override {
-    nearby_presence_service = std::make_unique<NearbyPresenceServiceImpl>();
+    pref_service_ = std::make_unique<TestingPrefServiceSimple>();
+
+    nearby_presence_service =
+        std::make_unique<NearbyPresenceServiceImpl>(pref_service_.get());
   }
 
   std::unique_ptr<NearbyPresenceServiceImpl> nearby_presence_service;
+  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
 };
 
 TEST_F(NearbyPresenceServiceImplTest, StartScan) {
diff --git a/chromeos/ash/components/nearby/presence/prefs/nearby_presence_prefs.cc b/chromeos/ash/components/nearby/presence/prefs/nearby_presence_prefs.cc
new file mode 100644
index 0000000..12db09f9
--- /dev/null
+++ b/chromeos/ash/components/nearby/presence/prefs/nearby_presence_prefs.cc
@@ -0,0 +1,14 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/ash/components/nearby/presence/prefs/nearby_presence_prefs.h"
+
+#include "components/prefs/pref_registry.h"
+#include "components/prefs/pref_registry_simple.h"
+
+namespace ash::nearby::presence {
+
+void RegisterNearbyPresencePrefs(PrefRegistrySimple* registry) {}
+
+}  // namespace ash::nearby::presence
diff --git a/chromeos/ash/components/nearby/presence/prefs/nearby_presence_prefs.h b/chromeos/ash/components/nearby/presence/prefs/nearby_presence_prefs.h
new file mode 100644
index 0000000..779b556
--- /dev/null
+++ b/chromeos/ash/components/nearby/presence/prefs/nearby_presence_prefs.h
@@ -0,0 +1,16 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_ASH_COMPONENTS_NEARBY_PRESENCE_PREFS_NEARBY_PRESENCE_PREFS_H_
+#define CHROMEOS_ASH_COMPONENTS_NEARBY_PRESENCE_PREFS_NEARBY_PRESENCE_PREFS_H_
+
+class PrefRegistrySimple;
+
+namespace ash::nearby::presence {
+
+void RegisterNearbyPresencePrefs(PrefRegistrySimple* registry);
+
+}  // namespace ash::nearby::presence
+
+#endif  // CHROMEOS_ASH_COMPONENTS_NEARBY_PRESENCE_PREFS_NEARBY_PRESENCE_PREFS_H_
diff --git a/chromeos/ash/services/connectivity/public/cpp/BUILD.gn b/chromeos/ash/services/connectivity/public/cpp/BUILD.gn
new file mode 100644
index 0000000..4c5dbca
--- /dev/null
+++ b/chromeos/ash/services/connectivity/public/cpp/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/chromeos/ui_mode.gni")
+
+assert(is_chromeos_ash)
+
+source_set("cpp") {
+  sources = [
+    "connectivity_services.cc",
+    "connectivity_services.h",
+  ]
+  deps = [
+    "//base",
+    "//chromeos/ash/components/mojo_service_manager",
+    "//chromeos/ash/services/connectivity/public/mojom",
+  ]
+}
diff --git a/chromeos/ash/services/connectivity/public/cpp/OWNERS b/chromeos/ash/services/connectivity/public/cpp/OWNERS
new file mode 100644
index 0000000..ffbc06b5
--- /dev/null
+++ b/chromeos/ash/services/connectivity/public/cpp/OWNERS
@@ -0,0 +1,2 @@
+file://chromeos/services/network_config/OWNERS
+damiendejean@google.com
diff --git a/chromeos/ash/services/connectivity/public/cpp/connectivity_services.cc b/chromeos/ash/services/connectivity/public/cpp/connectivity_services.cc
new file mode 100644
index 0000000..f1c2cef
--- /dev/null
+++ b/chromeos/ash/services/connectivity/public/cpp/connectivity_services.cc
@@ -0,0 +1,23 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/ash/services/connectivity/public/cpp/connectivity_services.h"
+
+#include <utility>
+
+#include "base/check.h"
+#include "chromeos/ash/components/mojo_service_manager/connection.h"
+#include "third_party/cros_system_api/mojo/service_constants.h"
+
+namespace ash::connectivity {
+
+void BindToPasspointService(
+    mojo::PendingReceiver<chromeos::connectivity::mojom::PasspointService>
+        receiver) {
+  mojo_service_manager::GetServiceManagerProxy()->Request(
+      chromeos::mojo_services::kCrosPasspointService, absl::nullopt,
+      std::move(receiver).PassPipe());
+}
+
+}  // namespace ash::connectivity
diff --git a/chromeos/ash/services/connectivity/public/cpp/connectivity_services.h b/chromeos/ash/services/connectivity/public/cpp/connectivity_services.h
new file mode 100644
index 0000000..3fadfb0
--- /dev/null
+++ b/chromeos/ash/services/connectivity/public/cpp/connectivity_services.h
@@ -0,0 +1,20 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_ASH_SERVICES_CONNECTIVITY_PUBLIC_CPP_CONNECTIVITY_SERVICES_H_
+#define CHROMEOS_ASH_SERVICES_CONNECTIVITY_PUBLIC_CPP_CONNECTIVITY_SERVICES_H_
+
+#include "chromeos/ash/services/connectivity/public/mojom/passpoint.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+
+namespace ash::connectivity {
+
+void BindToPasspointService(
+    mojo::PendingReceiver<chromeos::connectivity::mojom::PasspointService>
+        receiver);
+
+}  // namespace ash::connectivity
+
+#endif  // CHROMEOS_ASH_SERVICES_CONNECTIVITY_PUBLIC_CPP_CONNECTIVITY_SERVICES_H_
diff --git a/chromeos/ash/services/connectivity/public/mojom/BUILD.gn b/chromeos/ash/services/connectivity/public/mojom/BUILD.gn
new file mode 100644
index 0000000..9025670
--- /dev/null
+++ b/chromeos/ash/services/connectivity/public/mojom/BUILD.gn
@@ -0,0 +1,16 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/chromeos/ui_mode.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
+
+assert(is_chromeos_ash, "Non-ChromeOS builds cannot depend on //chromeos/ash")
+
+mojom("mojom") {
+  sources = [ "passpoint.mojom" ]
+  public_deps = [ "//mojo/public/mojom/base" ]
+  webui_module_path =
+      "chrome://resources/mojo/chromeos/ash/services/connectivity/public/mojom"
+  use_typescript_sources = true
+}
diff --git a/chromeos/ash/services/connectivity/public/mojom/OWNERS b/chromeos/ash/services/connectivity/public/mojom/OWNERS
new file mode 100644
index 0000000..977ca80
--- /dev/null
+++ b/chromeos/ash/services/connectivity/public/mojom/OWNERS
@@ -0,0 +1,3 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *.mojom=file://chromeos/SECURITY_OWNERS
diff --git a/chromeos/ash/services/connectivity/public/mojom/passpoint.mojom b/chromeos/ash/services/connectivity/public/mojom/passpoint.mojom
new file mode 100644
index 0000000..a0ce6e9
--- /dev/null
+++ b/chromeos/ash/services/connectivity/public/mojom/passpoint.mojom
@@ -0,0 +1,65 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module chromeos.connectivity.mojom;
+
+// PasspointSubscription describes a set of credentials installed in Shill.
+struct PasspointSubscription {
+  // Subscription unique identifier. This is a Shill identifier that can be
+  // used to match with the passpointID service property.
+  string id;
+
+  // List of the domains compatible with the service provider. Domains are Fully
+  // Qualified Domain Name (like "passpoint.myprovider.com").
+  array<string> domains;
+
+  // Human readable name of the service provider.
+  string friendly_name;
+
+  // Source of the credentials: an application package name when provisioned
+  // through an ARC application, or a string that describes the provisioning
+  // method otherwise.
+  string provisioning_source;
+
+  // Certificate authority trusted to validate server identity in PEM format. It
+  // is an ascii string that contains the PEM header, the certificate content in
+  // base64 string and the PEM footer.
+  string? trusted_ca;
+
+  // Time before the expiration of the set of credentials, in milliseconds since
+  // January 1, 1970, 00:00:00 GMT. The min value of int64_t means the field is
+  // unset.
+  int64 expiration_epoch_ms;
+};
+
+// Listener to the changes in Passpoint credentials set and list.
+interface PasspointEventsListener {
+  // Called when a new set of Passpoint credentials has been added.
+  // `subscription` is the subscription added.
+  OnPasspointSubscriptionAdded(PasspointSubscription subscription);
+
+  // Called when the subscription represented by `subscription` has been
+  // removed.
+  OnPasspointSubscriptionRemoved(PasspointSubscription subscription);
+};
+
+// Interface used by any service that wants to access Passpoint subscriptions
+// and follow their changes. The expected client is the network settings UI.
+interface PasspointService {
+  // Obtain the details of a Passpoint subscription designated by its unique
+  // identifier `id`.
+  GetPasspointSubscription(string id) => (PasspointSubscription? result);
+
+  // Obtain all the Passpoint subscriptions registered for the current Shill
+  // user profile.
+  ListPasspointSubscriptions() => (array<PasspointSubscription> result);
+
+  // Delete the Passpoint subscription designed by id.
+  DeletePasspointSubscription(string id) => (bool success);
+
+  // Register a listener to be notified of any changes on Passpoint credentials
+  // for the current Shill user profile. It must be registered before calling
+  // ListPasspointSubscriptions to avoid missing updates.
+  RegisterPasspointListener(pending_remote<PasspointEventsListener> listener);
+};
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index 9f98690..46b652c3 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -3849,6 +3849,9 @@
         <message name="IDS_SHORTCUT_CUSTOMIZATION_SEARCH_ACCELERATOR_TEXT_DIVIDER" desc="The text shown between multiple shortcut keys in search results." translateable="false">
           or
         </message>
+        <message name="IDS_SHORTCUT_CUSTOMIZATION_SEARCH_RESULT_ROW_A11Y_RESULT_SELECTED" desc="ChromeVox alert to indicate the position number of a selected result in a list of search results and the selected result text itself, and that the user can press enter to navigate to section described by the search result." translateable="false">
+          Search result <ph name="LIST_POSITION">$1<ex>1</ex></ph> of <ph name="LIST_SIZE">$2<ex>2</ex></ph>: <ph name="SEARCH_RESULT_TEXT">$3<ex>Open new tab</ex></ph>. Press Enter to navigate to shortcut.
+        </message>
         <message name="IDS_SHORTCUT_CUSTOMIZATION_CATEGORY_GENERAL" desc="Category named 'General' shown on the navigation sidebar">
           General
         </message>
diff --git a/chromeos/crosapi/mojom/app_service_types.mojom b/chromeos/crosapi/mojom/app_service_types.mojom
index febb01c2..6b95956 100644
--- a/chromeos/crosapi/mojom/app_service_types.mojom
+++ b/chromeos/crosapi/mojom/app_service_types.mojom
@@ -134,7 +134,8 @@
   // apps, so publishers must set the app as uninstalled before
   // removing it.
   kRemoved,
-  [MinVersion=1] kUninstalledByMigration,
+  // This is used for all non-user initiated uninstallation.
+  [MinVersion=1] kUninstalledByNonUser,
 };
 
 // The reason why the app was installed.
diff --git a/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc b/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc
index f1f6a92b..91c5007 100644
--- a/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc
+++ b/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc
@@ -378,8 +378,8 @@
       return crosapi::mojom::Readiness::kUninstalledByUser;
     case apps::Readiness::kRemoved:
       return crosapi::mojom::Readiness::kRemoved;
-    case apps::Readiness::kUninstalledByMigration:
-      return crosapi::mojom::Readiness::kUninstalledByMigration;
+    case apps::Readiness::kUninstalledByNonUser:
+      return crosapi::mojom::Readiness::kUninstalledByNonUser;
   }
 
   NOTREACHED();
@@ -413,8 +413,8 @@
     case crosapi::mojom::Readiness::kRemoved:
       *output = apps::Readiness::kRemoved;
       return true;
-    case crosapi::mojom::Readiness::kUninstalledByMigration:
-      *output = apps::Readiness::kUninstalledByMigration;
+    case crosapi::mojom::Readiness::kUninstalledByNonUser:
+      *output = apps::Readiness::kUninstalledByNonUser;
       return true;
   }
 
diff --git a/chromeos/profiles/arm-exp.afdo.newest.txt b/chromeos/profiles/arm-exp.afdo.newest.txt
index b950ee7d..9e445b40 100644
--- a/chromeos/profiles/arm-exp.afdo.newest.txt
+++ b/chromeos/profiles/arm-exp.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-none-114-5650.0-1680521657-benchmark-114.0.5702.0-r1-redacted.afdo.xz
+chromeos-chrome-arm-none-114-5672.21-1681131358-benchmark-114.0.5715.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/arm.afdo.newest.txt b/chromeos/profiles/arm.afdo.newest.txt
index b950ee7d..9e445b40 100644
--- a/chromeos/profiles/arm.afdo.newest.txt
+++ b/chromeos/profiles/arm.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-none-114-5650.0-1680521657-benchmark-114.0.5702.0-r1-redacted.afdo.xz
+chromeos-chrome-arm-none-114-5672.21-1681131358-benchmark-114.0.5715.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt
index 760ea2c2..b3b5e2b 100644
--- a/chromeos/profiles/atom.afdo.newest.txt
+++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-atom-114-5692.0-1681124563-benchmark-114.0.5713.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-atom-114-5692.0-1681124563-benchmark-114.0.5715.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index 1f609891..c2d587c 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-114-5672.21-1681120054-benchmark-114.0.5713.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-114-5672.21-1681120054-benchmark-114.0.5715.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/orderfile.newest.txt b/chromeos/profiles/orderfile.newest.txt
index 629698e..c0763b191 100644
--- a/chromeos/profiles/orderfile.newest.txt
+++ b/chromeos/profiles/orderfile.newest.txt
@@ -1 +1 @@
-chromeos-chrome-orderfile-field-114-5672.6-1680517341-benchmark-114.0.5703.0-r1.orderfile.xz
+chromeos-chrome-orderfile-field-114-5692.0-1681124563-benchmark-114.0.5712.0-r1.orderfile.xz
diff --git a/chromeos/strings/chromeos_strings_bn.xtb b/chromeos/strings/chromeos_strings_bn.xtb
index f1e682d..4aef8a4 100644
--- a/chromeos/strings/chromeos_strings_bn.xtb
+++ b/chromeos/strings/chromeos_strings_bn.xtb
@@ -573,6 +573,7 @@
 <translation id="5931523347251946569">ফাইল পাওয়া যায়নি</translation>
 <translation id="5939518447894949180">রিসেট করুন</translation>
 <translation id="594552776027197022">র‍্যান্ডম কী পেয়ার জেনারেট করুন</translation>
+<translation id="5946538341867151940">আপনি এখনও কানেক্ট হননি। যদি আপনার মোবাইল পরিষেবা প্রদানকারী একটি কাস্টম APN প্রস্তাব করে, "+ নতুন APN" বেছে নিন এবং APN তথ্য লিখুন</translation>
 <translation id="5972388717451707488">Update Engine</translation>
 <translation id="5984145644188835034">ডিফল্ট ওয়ালপেপার</translation>
 <translation id="6017514345406065928">সবুজ</translation>
diff --git a/chromeos/strings/chromeos_strings_cs.xtb b/chromeos/strings/chromeos_strings_cs.xtb
index 3018328..e94f690 100644
--- a/chromeos/strings/chromeos_strings_cs.xtb
+++ b/chromeos/strings/chromeos_strings_cs.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Další užitečné zdroje:</translation>
 <translation id="1905710495812624430">Byl překročen maximální povolený počet pokusů.</translation>
 <translation id="1908234395526491708">Selhání požadavků UDP</translation>
+<translation id="1923388006036088459">Barvy zvýraznění</translation>
 <translation id="1947737735496445907">Vytištěno</translation>
 <translation id="1951012854035635156">Asistent</translation>
 <translation id="1962550982027027473">Výchozí APN je povinný</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Stahování bylo dokončeno</translation>
 <translation id="3969602104473960991">Heslo ChromeOS byla aktualizováno</translation>
 <translation id="397105322502079400">Probíhá výpočet…</translation>
+<translation id="3974175076798940554">Jsou k dispozici exkluzivní položky pro Chromebooky Plus</translation>
 <translation id="39823212440917567">Tiskové úlohy starší než <ph name="NUMBER_OF_DAYS" /> dní budou odstraněny</translation>
 <translation id="3993704782688964914">Zařízení <ph name="DEVICE_NAME" /> je aktualizované</translation>
 <translation id="4003384961948020559">Tisk selhal – výstupní zásobník je plný</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Přidat účet do vícenásobného přihlášení. Ke všem přihlášeným účtům lze přistupovat bez zadání hesla, proto byste tuto funkci měli používat pouze s důvěryhodnými účty.</translation>
 <translation id="8364946094152050673">Prázdné názvové servery</translation>
 <translation id="8372477600026034341">Extra hostitelské servery</translation>
+<translation id="8373046809163484087">Použijte sady barev odpovídající vaší tapetě</translation>
 <translation id="8380114448424469341">Ukotvit okno na polovinu obrazovky <ph name="DIRECTION" /></translation>
 <translation id="8395584934117017006">Toto zařízení <ph name="DEVICE_TYPE" /> spravuje podnik</translation>
 <translation id="8398927464629426868">Rychlost, s jakou se zařízení momentálně nabíjí nebo vybíjí</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Uživatelské jméno</translation>
 <translation id="8503836310948963452">Ještě pár minut…</translation>
 <translation id="8508640263392900755">Podrobnosti o APN</translation>
+<translation id="8522687886059337719">Nyní máte přístup k novým <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />tapetám<ph name="END_LINK_WALLPAPER_SUBPAGE" /> a <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />spořiči obrazovky<ph name="END_LINK_SCREENSAVER_SUBPAGE" /></translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Někteří operátoři k připojení k síti vyžadují tuto možnost. Na podrobnosti se zeptejte mobilního operátora.</translation>
diff --git a/chromeos/strings/chromeos_strings_da.xtb b/chromeos/strings/chromeos_strings_da.xtb
index d61ade9..33acb68 100644
--- a/chromeos/strings/chromeos_strings_da.xtb
+++ b/chromeos/strings/chromeos_strings_da.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Her er nogle andre nyttige ressourcer:</translation>
 <translation id="1905710495812624430">Det maksimale antal forsøg er overskredet.</translation>
 <translation id="1908234395526491708">Mislykkede UDP-anmodninger</translation>
+<translation id="1923388006036088459">Kontrastfarver</translation>
 <translation id="1947737735496445907">Udskrevet</translation>
 <translation id="1951012854035635156">Assistent</translation>
 <translation id="1962550982027027473">Et standard-APN er påkrævet</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Download fuldført</translation>
 <translation id="3969602104473960991">ChromeOS-adgangskoden er opdateret</translation>
 <translation id="397105322502079400">Beregner...</translation>
+<translation id="3974175076798940554">Eksklusive Chromebook Plus-aktiver er nu tilgængelige</translation>
 <translation id="39823212440917567">Udskriftsjobs, der er ældre end <ph name="NUMBER_OF_DAYS" /> dage, fjernes</translation>
 <translation id="3993704782688964914">Din <ph name="DEVICE_NAME" /> er nu opdateret</translation>
 <translation id="4003384961948020559">Handlingen mislykkedes – Fuld udskriftsbakke</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Føj en konto til samlet login fra flere konti. Det er muligt at få adgang til alle de konti, der er logget ind på, uden en adgangskode, så denne funktion bør kun bruges til de konti, du har tillid til.</translation>
 <translation id="8364946094152050673">Navneserverne er ikke angivet</translation>
 <translation id="8372477600026034341">Ekstra hosts</translation>
+<translation id="8373046809163484087">Brug farvesæt, der matcher din baggrund</translation>
 <translation id="8380114448424469341">Fastgør vinduet på halvdelen af skærmen (<ph name="DIRECTION" />)</translation>
 <translation id="8395584934117017006">Denne <ph name="DEVICE_TYPE" /> administreres af en virksomhed</translation>
 <translation id="8398927464629426868">Den aktuelle hastighed for opladning eller afladning på enheden</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Brugernavn</translation>
 <translation id="8503836310948963452">Det tager kun et par minutter mere...</translation>
 <translation id="8508640263392900755">Oplysninger om adgangspunkt</translation>
+<translation id="8522687886059337719">Du har nu adgang til nye <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />baggrunde<ph name="END_LINK_WALLPAPER_SUBPAGE" /> og <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />pauseskærme<ph name="END_LINK_SCREENSAVER_SUBPAGE" /></translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Dit mobilselskab kræver muligvis denne tilladelse, for at du kan oprette forbindelse til mobilnetværket. Kontakt dit mobilselskab for at få flere oplysninger.</translation>
diff --git a/chromeos/strings/chromeos_strings_en-GB.xtb b/chromeos/strings/chromeos_strings_en-GB.xtb
index cd7ceb53..db8036d6 100644
--- a/chromeos/strings/chromeos_strings_en-GB.xtb
+++ b/chromeos/strings/chromeos_strings_en-GB.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Here are some other helpful resources:</translation>
 <translation id="1905710495812624430">Maximum allowed attempts exceeded.</translation>
 <translation id="1908234395526491708">UDP request failures</translation>
+<translation id="1923388006036088459">Accent colours</translation>
 <translation id="1947737735496445907">Printed</translation>
 <translation id="1951012854035635156">Assistant</translation>
 <translation id="1962550982027027473">A default APN is required</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Download complete</translation>
 <translation id="3969602104473960991">Chrome OS password updated</translation>
 <translation id="397105322502079400">Calculating...</translation>
+<translation id="3974175076798940554">Exclusive Chromebook Plus assets now available</translation>
 <translation id="39823212440917567">Print jobs older than <ph name="NUMBER_OF_DAYS" /> days will be removed</translation>
 <translation id="3993704782688964914">Your <ph name="DEVICE_NAME" /> is now up to date</translation>
 <translation id="4003384961948020559">Failed – Output full</translation>
@@ -847,6 +849,7 @@
 <translation id="8352772353338965963">Add an account to multiple sign-in. All signed-in accounts can be accessed without a password, so this feature should only be used with trusted accounts.</translation>
 <translation id="8364946094152050673">Empty name servers</translation>
 <translation id="8372477600026034341">Extra hosts</translation>
+<translation id="8373046809163484087">Use colour sets that match your wallpaper</translation>
 <translation id="8380114448424469341">Dock window on the <ph name="DIRECTION" /> half of the screen</translation>
 <translation id="8395584934117017006">This <ph name="DEVICE_TYPE" /> is enterprise managed</translation>
 <translation id="8398927464629426868">The rate at which the device is currently charging or discharging</translation>
@@ -866,6 +869,7 @@
 <translation id="8503813439785031346">Username</translation>
 <translation id="8503836310948963452">Just a few more minutes…</translation>
 <translation id="8508640263392900755">APN details</translation>
+<translation id="8522687886059337719">You now have access to new <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />wallpapers<ph name="END_LINK_WALLPAPER_SUBPAGE" /> and <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />screen savers<ph name="END_LINK_SCREENSAVER_SUBPAGE" /></translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Your operator may require this option to connect to their network. Contact your operator for details.</translation>
diff --git a/chromeos/strings/chromeos_strings_es-419.xtb b/chromeos/strings/chromeos_strings_es-419.xtb
index c210add..7781dc77 100644
--- a/chromeos/strings/chromeos_strings_es-419.xtb
+++ b/chromeos/strings/chromeos_strings_es-419.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">A continuación, se incluyen otros recursos útiles:</translation>
 <translation id="1905710495812624430">Se superó la cantidad máxima de intentos permitidos.</translation>
 <translation id="1908234395526491708">Fallos de solicitudes de UDP</translation>
+<translation id="1923388006036088459">Colores de los elementos destacados</translation>
 <translation id="1947737735496445907">Impreso</translation>
 <translation id="1951012854035635156">Asistente</translation>
 <translation id="1962550982027027473">Debes ingresar un APN predeterminado</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Descarga completa</translation>
 <translation id="3969602104473960991">Se actualizó la contraseña de Chrome OS</translation>
 <translation id="397105322502079400">Calculando...</translation>
+<translation id="3974175076798940554">Ya están disponibles los recursos exclusivos para Chromebook Plus</translation>
 <translation id="39823212440917567">Se quitarán los trabajos de impresión que tengan más de <ph name="NUMBER_OF_DAYS" /> días</translation>
 <translation id="3993704782688964914">Tu <ph name="DEVICE_NAME" /> está actualizado</translation>
 <translation id="4003384961948020559">Error: La bandeja de salida está llena</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Agrega una cuenta para el acceso múltiple. Puedes acceder a todas las cuentas abiertas sin una contraseña, por lo que esta función solo debe utilizarse con cuentas de confianza.</translation>
 <translation id="8364946094152050673">los servidores de nombres están vacíos</translation>
 <translation id="8372477600026034341">Hosts adicionales</translation>
+<translation id="8373046809163484087">Usa combinaciones de colores que combinen con tu fondo de pantalla</translation>
 <translation id="8380114448424469341">Anclar la ventana en la mitad <ph name="DIRECTION" /> de la pantalla</translation>
 <translation id="8395584934117017006">Una empresa administra el dispositivo <ph name="DEVICE_TYPE" /></translation>
 <translation id="8398927464629426868">La tasa a la que el dispositivo se está cargando o descargando</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Nombre de usuario</translation>
 <translation id="8503836310948963452">Solo unos minutos más…</translation>
 <translation id="8508640263392900755">Detalles del APN</translation>
+<translation id="8522687886059337719">Ahora tienes acceso a <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />fondos de pantalla<ph name="END_LINK_WALLPAPER_SUBPAGE" /> y <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />protectores de pantalla<ph name="END_LINK_SCREENSAVER_SUBPAGE" /> nuevos</translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Es posible que tu proveedor necesite que esta opción esté habilitada para que puedas conectarte a su red. Comunícate con el proveedor para obtener más detalles.</translation>
diff --git a/chromeos/strings/chromeos_strings_eu.xtb b/chromeos/strings/chromeos_strings_eu.xtb
index 17bbccba..ea876be9 100644
--- a/chromeos/strings/chromeos_strings_eu.xtb
+++ b/chromeos/strings/chromeos_strings_eu.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Hona hemen beste baliabide lagungarri batzuk:</translation>
 <translation id="1905710495812624430">Saiakera-muga gainditu da.</translation>
 <translation id="1908234395526491708">UDP bidezko eskaeren hutsegiteak</translation>
+<translation id="1923388006036088459">Nabarmentzeko koloreak</translation>
 <translation id="1947737735496445907">Inprimatuta</translation>
 <translation id="1951012854035635156">Laguntzailea</translation>
 <translation id="1962550982027027473">APN lehenetsi bat behar da</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Deskargatzen amaitu da</translation>
 <translation id="3969602104473960991">Eguneratu da Chrome OS-ko pasahitza</translation>
 <translation id="397105322502079400">Kalkulatzen…</translation>
+<translation id="3974175076798940554">Chromebook Plus-en baliabide esklusiboak eskuragai</translation>
 <translation id="39823212440917567"><ph name="NUMBER_OF_DAYS" /> egun baino gehiagoko inprimatze-lanak kendu egingo dira</translation>
 <translation id="3993704782688964914"><ph name="DEVICE_NAME" /> eguneratuta dago</translation>
 <translation id="4003384961948020559">Hutsegitea - Irteera-erretilua beteta dago</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Gehitu kontu bat saio-hasiera anitzean. Saioa hasita daukaten kontu guztiak pasahitzik gabe atzi daitezkeenez, kontu fidagarriekin soilik erabili behar da eginbide hori.</translation>
 <translation id="8364946094152050673">Izenen zerbitzariak hutsik daude</translation>
 <translation id="8372477600026034341">Ostalari gehigarriak</translation>
+<translation id="8373046809163484087">Erabili horma-paperarekin bat datozen kolore sortak</translation>
 <translation id="8380114448424469341">Ainguratu leihoa pantailaren <ph name="DIRECTION" /> erdian</translation>
 <translation id="8395584934117017006">Enpresa batek kudeatzen du <ph name="DEVICE_TYPE" /> gailua</translation>
 <translation id="8398927464629426868">Gailua zer abiaduratan kargatzen edo deskargatzen ari den</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Erabiltzaile-izena</translation>
 <translation id="8503836310948963452">Minutu gutxi batzuk baino ez…</translation>
 <translation id="8508640263392900755">APNaren xehetasunak</translation>
+<translation id="8522687886059337719">Orain, <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />horma-paper<ph name="END_LINK_WALLPAPER_SUBPAGE" /> eta <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />pantaila-babesle<ph name="END_LINK_SCREENSAVER_SUBPAGE" /> berriak erabil ditzakezu</translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Baliteke zure operadoreak aukera hau eskatzea haren sarera konektatzeko. Horri buruzko xehetasunak lortzeko, jarri operadorearekin harremanetan.</translation>
diff --git a/chromeos/strings/chromeos_strings_fa.xtb b/chromeos/strings/chromeos_strings_fa.xtb
index c0264893..1ef581a 100644
--- a/chromeos/strings/chromeos_strings_fa.xtb
+++ b/chromeos/strings/chromeos_strings_fa.xtb
@@ -517,6 +517,7 @@
 <translation id="5423849171846380976">فعال شد</translation>
 <translation id="5430931332414098647">اشتراک‌گذاری اینترنت فوری</translation>
 <translation id="5431318178759467895">رنگ</translation>
+<translation id="5456936324019847994">‏نمی‌توان به هیچ‌یک از نام‌های APN سفارشی فعال متصل شد. برای کسب اطلاعات بیشتر با شرکت مخابراتی‌تان تماس بگیرید.</translation>
 <translation id="5457599981699367932">مرور کردن به‌عنوان یک مهمان</translation>
 <translation id="54609108002486618">مدیریت شده</translation>
 <translation id="5478289488939624992">{ATTEMPTS_LEFT,plural, =1{{0} فرصت باقی مانده است}one{{0} فرصت باقی مانده است}other{{0} فرصت باقی مانده است}}</translation>
diff --git a/chromeos/strings/chromeos_strings_fr-CA.xtb b/chromeos/strings/chromeos_strings_fr-CA.xtb
index 333ff02..9921402 100644
--- a/chromeos/strings/chromeos_strings_fr-CA.xtb
+++ b/chromeos/strings/chromeos_strings_fr-CA.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Voici quelques autres ressources utiles :</translation>
 <translation id="1905710495812624430">Nombre maximal autorisé de tentatives atteint.</translation>
 <translation id="1908234395526491708">Échecs des demandes UDP</translation>
+<translation id="1923388006036088459">Couleurs de mise en évidence</translation>
 <translation id="1947737735496445907">Imprimée</translation>
 <translation id="1951012854035635156">Assistant</translation>
 <translation id="1962550982027027473">Un APN par défaut est requis</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Téléchargement terminé</translation>
 <translation id="3969602104473960991">Mot de passe de Chrome OS mis à jour</translation>
 <translation id="397105322502079400">Calcul en cours...</translation>
+<translation id="3974175076798940554">Éléments Chromebook Plus exclusifs maintenant offerts</translation>
 <translation id="39823212440917567">Les tâches d'impression datant de plus de <ph name="NUMBER_OF_DAYS" /> jours seront supprimées</translation>
 <translation id="3993704782688964914">Votre <ph name="DEVICE_NAME" /> est maintenant à jour</translation>
 <translation id="4003384961948020559">Échec : bac de sortie plein</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Ajouter un compte à la connexion multicompte. Tous les comptes connectés sont accessibles sans mot de passe. Nous vous recommandons donc de n'utiliser cette fonctionnalité qu'avec des comptes fiables.</translation>
 <translation id="8364946094152050673">Le champ des serveurs de nom est vide</translation>
 <translation id="8372477600026034341">Hôtes supplémentaires</translation>
+<translation id="8373046809163484087">Utiliser des ensembles de couleurs qui correspondent à votre fond d'écran</translation>
 <translation id="8380114448424469341">Ancrer la fenêtre sur la moitié <ph name="DIRECTION" /> de l'écran</translation>
 <translation id="8395584934117017006">Cet appareil <ph name="DEVICE_TYPE" /> est géré par l'entreprise</translation>
 <translation id="8398927464629426868">La vitesse à laquelle l'appareil se charge ou se décharge actuellement</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Nom d'utilisateur</translation>
 <translation id="8503836310948963452">Il ne reste que quelques minutes…</translation>
 <translation id="8508640263392900755">Détails de l'APN</translation>
+<translation id="8522687886059337719">Vous avez maintenant accès aux nouveaux <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />fonds d'écran<ph name="END_LINK_WALLPAPER_SUBPAGE" /> et à l'<ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />écran de veille<ph name="END_LINK_SCREENSAVER_SUBPAGE" /></translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Votre fournisseur de services peut exiger l'activation de cette option pour vous connecter à son réseau. Communiquez avec votre fournisseur de services pour en savoir davantage.</translation>
diff --git a/chromeos/strings/chromeos_strings_gl.xtb b/chromeos/strings/chromeos_strings_gl.xtb
index ca164f5..ed0a63c3 100644
--- a/chromeos/strings/chromeos_strings_gl.xtb
+++ b/chromeos/strings/chromeos_strings_gl.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Aquí tes outros recursos útiles:</translation>
 <translation id="1905710495812624430">Superouse o número máximo de intentos.</translation>
 <translation id="1908234395526491708">Erros nas solicitudes de UDP</translation>
+<translation id="1923388006036088459">Cores para destacar</translation>
 <translation id="1947737735496445907">Impreso</translation>
 <translation id="1951012854035635156">Asistente</translation>
 <translation id="1962550982027027473">Requírese un APN predeterminado</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Descarga completa</translation>
 <translation id="3969602104473960991">Modificouse o contrasinal de Chrome OS</translation>
 <translation id="397105322502079400">Calculando...</translation>
+<translation id="3974175076798940554">Os recursos exclusivos de Chromebook Plus xa están dispoñibles</translation>
 <translation id="39823212440917567">Quitaranse os traballos de impresión de máis de <ph name="NUMBER_OF_DAYS" /> días</translation>
 <translation id="3993704782688964914">O dispositivo (<ph name="DEVICE_NAME" />) xa está actualizado</translation>
 <translation id="4003384961948020559">Produciuse un erro: a saída da impresora está chea</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Engade unha conta ao inicio de sesión múltiple. É posible acceder a todas as contas en que iniciaches sesión sen necesidade de inserir un contrasinal, polo que esta función só se debe utilizar coas contas de confianza.</translation>
 <translation id="8364946094152050673">Os servidores de nomes están baleiros</translation>
 <translation id="8372477600026034341">Hosts extra</translation>
+<translation id="8373046809163484087">Usa conxuntos de cores que combinen co teu fondo de pantalla</translation>
 <translation id="8380114448424469341">Fixar ventá na seguinte metade da pantalla: <ph name="DIRECTION" /></translation>
 <translation id="8395584934117017006">Este dispositivo (<ph name="DEVICE_TYPE" />) está xestionado por unha empresa</translation>
 <translation id="8398927464629426868">O ritmo actual de carga ou descarga da batería do dispositivo</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Nome de usuario</translation>
 <translation id="8503836310948963452">Só faltan uns minutos…</translation>
 <translation id="8508640263392900755">Detalles do APN</translation>
+<translation id="8522687886059337719">Xa podes acceder a novos <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />fondos<ph name="END_LINK_WALLPAPER_SUBPAGE" /> e <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />protectores de pantalla<ph name="END_LINK_SCREENSAVER_SUBPAGE" /></translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">É posible que sexa obrigatorio activar esta opción para conectarte á rede do teu operador. Para obter máis detalles, ponte en contacto con el.</translation>
diff --git a/chromeos/strings/chromeos_strings_gu.xtb b/chromeos/strings/chromeos_strings_gu.xtb
index f69f84d..ca19aa9f 100644
--- a/chromeos/strings/chromeos_strings_gu.xtb
+++ b/chromeos/strings/chromeos_strings_gu.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">અહીં કેટલાક અન્ય સહાયરૂપ સંસાધનો આપવામાં આવ્યા છે:</translation>
 <translation id="1905710495812624430">મહત્તમ મંજૂર પ્રયત્નોની સંખ્યા ઓળંગાઈ.</translation>
 <translation id="1908234395526491708">UDP વિનંતી નિષ્ફળ થઈ</translation>
+<translation id="1923388006036088459">ઍક્સેન્ટના રંગ</translation>
 <translation id="1947737735496445907">પ્રિન્ટ થઈ ગયું</translation>
 <translation id="1951012854035635156">Assistant</translation>
 <translation id="1962550982027027473">ડિફૉલ્ટ APN આવશ્યક છે</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">ડાઉનલોડ પૂર્ણ</translation>
 <translation id="3969602104473960991">ChromeOSનો પાસવર્ડ અપડેટ કરવામાં આવ્યો</translation>
 <translation id="397105322502079400">ગણના કરી રહ્યું છે...</translation>
+<translation id="3974175076798940554">અસેટ માત્ર Chromebook Plus માટે ઉપલબ્ધ છે</translation>
 <translation id="39823212440917567"><ph name="NUMBER_OF_DAYS" /> દિવસ કરતાં જૂના પ્રિન્ટ કાર્યો કાઢી નાખવામાં આવશે</translation>
 <translation id="3993704782688964914">તમારું <ph name="DEVICE_NAME" /> હવે અપ ટૂ ડેટ છે</translation>
 <translation id="4003384961948020559">નિષ્ફળ થયું - પ્રિન્ટરનું આઉટપુટ ભરાઈ ગયું છે</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">એકથી વધુ સાઇન ઇન કરવા એક એકાઉન્ટ ઉમેરો. બધા સાઇન ઇન એકાઉન્ટ પાસવર્ડ વગર ઉપયોગ કરી શકાય છે, તેથી આ સુવિધા માત્ર વિશ્વસનીય એકાઉન્ટ સાથે ઉપયોગમાં આવવી જોઇએ.</translation>
 <translation id="8364946094152050673">સર્વરના કોઈ નામ આપવામાં આવ્યા નથી</translation>
 <translation id="8372477600026034341">અતિરિક્ત હોસ્ટ</translation>
+<translation id="8373046809163484087">તમારા વૉલપેપરથી મેળ થતા કલર સેટનો ઉપયોગ કરો</translation>
 <translation id="8380114448424469341">વિન્ડોને સ્ક્રીનના <ph name="DIRECTION" /> અડધા ભાગ પર ડૉક કરો</translation>
 <translation id="8395584934117017006">આ <ph name="DEVICE_TYPE" /> એન્ટરપ્રાઇઝ દ્વારા મેનેજ થાય છે</translation>
 <translation id="8398927464629426868">ડિવાઇસ હાલમાં જે ઝડપથી ચાર્જ કે ડિસ્ચાર્જ થઈ રહ્યું છે તે ઝડપ</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">વપરાશકર્તાનામ</translation>
 <translation id="8503836310948963452">બસ થોડો વધુ સમય...</translation>
 <translation id="8508640263392900755">APNની વિગતો</translation>
+<translation id="8522687886059337719">તમે હવે નવા <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />વૉલપેપર<ph name="END_LINK_WALLPAPER_SUBPAGE" /> અને <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />સ્ક્રીન સેવર<ph name="END_LINK_SCREENSAVER_SUBPAGE" />નો ઍક્સેસ ધરાવો છો</translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">તમારા મોબાઇલ ઑપરેટરને તેમના નેટવર્ક સાથે કનેક્ટ કરવા માટે, આ વિકલ્પની જરૂર પડી શકે છે. વિગતો માટે તમારા મોબાઇલ ઑપરેટરનો સંપર્ક કરો.</translation>
diff --git a/chromeos/strings/chromeos_strings_hi.xtb b/chromeos/strings/chromeos_strings_hi.xtb
index bfdf01a7..ea0aa3d 100644
--- a/chromeos/strings/chromeos_strings_hi.xtb
+++ b/chromeos/strings/chromeos_strings_hi.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">यहां आपकी मदद के लिए कुछ अन्य संसाधन दिए गए हैं:</translation>
 <translation id="1905710495812624430">अधिकतम स्वीकार्य प्रयासों की सीमा पार हो गई है.</translation>
 <translation id="1908234395526491708">यूडीपी अनुरोध पूरे नहीं हो पाए</translation>
+<translation id="1923388006036088459">एक्सेंट के रंग</translation>
 <translation id="1947737735496445907">प्रिंट किया गया</translation>
 <translation id="1951012854035635156">Assistant</translation>
 <translation id="1962550982027027473">डिफ़ॉल्ट एपीएन चालू करना ज़रूरी है</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">डाउनलोड पूरा हुआ</translation>
 <translation id="3969602104473960991">ChromeOS का पासवर्ड बदला गया</translation>
 <translation id="397105322502079400">गणना की जा रही है...</translation>
+<translation id="3974175076798940554">Chromebook Plus के खास ऐसेट अब उपलब्ध हैं</translation>
 <translation id="39823212440917567"><ph name="NUMBER_OF_DAYS" /> से ज़्यादा पुरानी, प्रिंट की गई फ़ाइलों को हटा दिया जाएगा</translation>
 <translation id="3993704782688964914">अब आपका <ph name="DEVICE_NAME" /> अप-टू-डेट है</translation>
 <translation id="4003384961948020559">प्रिंट नहीं हो पाया - प्रिंटर आउटपुट फ़ुल है</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">एक से ज़्यादा साइन-इन के लिए कोई खाता जोड़ें. सभी साइन इन किए गए खातों को पासवर्ड के बिना एक्सेस किया जा सकता है, इसलिए इस सुविधा का इस्तेमाल सिर्फ़ विश्वसनीय खातों के साथ किया जाना चाहिए.</translation>
 <translation id="8364946094152050673">ये नाम सर्वर खाली हैं</translation>
 <translation id="8372477600026034341">कुछ और होस्ट</translation>
+<translation id="8373046809163484087">अपने वॉलपेपर से मेल खाने वाले रंग के सेट का इस्तेमाल करें</translation>
 <translation id="8380114448424469341">डॉक विंडो को <ph name="DIRECTION" /> ओर स्क्रीन के आधे हिस्से पर रखें</translation>
 <translation id="8395584934117017006">इस <ph name="DEVICE_TYPE" /> को एंटरप्राइज़ मैनेज करता है</translation>
 <translation id="8398927464629426868">वह दर जिस पर डिवाइस अभी चार्ज या डिस्चार्ज हो रहा है</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">उपयोगकर्ता नाम</translation>
 <translation id="8503836310948963452">बस कुछ मिनट और...</translation>
 <translation id="8508640263392900755">एपीएन की जानकारी</translation>
+<translation id="8522687886059337719">अब आपके पास नए <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />वॉलपेपर<ph name="END_LINK_WALLPAPER_SUBPAGE" /> और <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />स्क्रीन सेवर<ph name="END_LINK_SCREENSAVER_SUBPAGE" /> का ऐक्सेस है</translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">मोबाइल और इंटरनेट सेवा देने वाली आपकी कंपनी को, अपने नेटवर्क से कनेक्ट करने लिए इस विकल्प की ज़रूरत पड़ सकती है. ज़्यादा जानकारी के लिए, उस कंपनी से संपर्क करें जो आपको मोबाइल और इंटरनेट सेवा देती है.</translation>
diff --git a/chromeos/strings/chromeos_strings_hu.xtb b/chromeos/strings/chromeos_strings_hu.xtb
index 47ed730..ace501d 100644
--- a/chromeos/strings/chromeos_strings_hu.xtb
+++ b/chromeos/strings/chromeos_strings_hu.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Íme néhány további hasznos forrás:</translation>
 <translation id="1905710495812624430">Elérte az engedélyezett kísérletek maximális számát.</translation>
 <translation id="1908234395526491708">Hibás UDP-kérelmek.</translation>
+<translation id="1923388006036088459">Kiemelés színei</translation>
 <translation id="1947737735496445907">Sikeres nyomtatás</translation>
 <translation id="1951012854035635156">Segéd</translation>
 <translation id="1962550982027027473">Szükség van alapértelmezett APN-re</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">A letöltés sikeres</translation>
 <translation id="3969602104473960991">ChromeOS-jelszó módosítva</translation>
 <translation id="397105322502079400">Számítás…</translation>
+<translation id="3974175076798940554">Mostantól exkluzív Chromebook Plus-eszközök állnak rendelkezésre</translation>
 <translation id="39823212440917567">A(z) <ph name="NUMBER_OF_DAYS" /> napnál régebbi nyomtatási feladatokat eltávolítja a rendszer</translation>
 <translation id="3993704782688964914"><ph name="DEVICE_NAME" /> eszköze most már naprakész</translation>
 <translation id="4003384961948020559">Sikertelen – Megtelt a kimenet</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Adjon hozzá egy fiókot a többfiókos bejelentkezéshez. Az összes bejelentkezett fiók elérhető a jelszó megadása nélkül, ezért ezt a funkciót csak megbízható fiókokkal használja.</translation>
 <translation id="8364946094152050673">Üres névszerverek</translation>
 <translation id="8372477600026034341">További gazdagépek</translation>
+<translation id="8373046809163484087">A háttérképhez illeszkedő színkészletek használata</translation>
 <translation id="8380114448424469341">Ablak dokkolása a képernyő <ph name="DIRECTION" /> oldali felén</translation>
 <translation id="8395584934117017006">Ezt a(z) <ph name="DEVICE_TYPE" /> eszközt a vállalat felügyeli</translation>
 <translation id="8398927464629426868">Az eszköz jelenlegi töltésének vagy merülésének sebessége</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Felhasználónév</translation>
 <translation id="8503836310948963452">Már csak néhány perc…</translation>
 <translation id="8508640263392900755">APN részletei</translation>
+<translation id="8522687886059337719">Mostantól új <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />háttérképekhez<ph name="END_LINK_WALLPAPER_SUBPAGE" /> és <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />képernyővédőhöz<ph name="END_LINK_SCREENSAVER_SUBPAGE" /> férhet hozzá.</translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Szolgáltatója előírhatja ennek a beállításnak a használatát a hálózathoz való csatlakozás érdekében. További információért forduljon a szolgáltatójához.</translation>
diff --git a/chromeos/strings/chromeos_strings_hy.xtb b/chromeos/strings/chromeos_strings_hy.xtb
index 1102e68..f32c465 100644
--- a/chromeos/strings/chromeos_strings_hy.xtb
+++ b/chromeos/strings/chromeos_strings_hy.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Ահա մի քանի այլ օգտակար ռեսուրսներ՝</translation>
 <translation id="1905710495812624430">Փորձերի առավելագույն թույլատրելի քանակը սպառվել է:</translation>
 <translation id="1908234395526491708">Ձախողված UDP հարցումներ</translation>
+<translation id="1923388006036088459">Ակցենտային գույներ</translation>
 <translation id="1947737735496445907">Տպված է</translation>
 <translation id="1951012854035635156">Օգնական</translation>
 <translation id="1962550982027027473">Պահանջվում է կանխադրված APN</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Ներբեռնումն ավարտվեց</translation>
 <translation id="3969602104473960991">ChromeOS-ի գաղտնաբառը փոխվել է</translation>
 <translation id="397105322502079400">Հաշվարկում…</translation>
+<translation id="3974175076798940554">Բացառիկ բովանդակություն Chromebook Plus-ի համար</translation>
 <translation id="39823212440917567">Տպման առաջադրանքները, որոնք <ph name="NUMBER_OF_DAYS" /> օրից հին են, կհեռացվեն</translation>
 <translation id="3993704782688964914">Ձեր <ph name="DEVICE_NAME" /> սարքն այժմ թարմացված է</translation>
 <translation id="4003384961948020559">Չհաջողվեց տպել – Ելքը լցված է</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Ավելացնել հաշիվ բազմակի մուտքի համակարգում: Բոլոր մուտք գործած հաշիվները մատչելի են առանց գաղտնաբառի մուտքագրման, ուստի այս գործառույթը պետք է միայն օգտագործվի վստահելի հաշիվների հետ:</translation>
 <translation id="8364946094152050673">DNS սերվերները դատարկ են</translation>
 <translation id="8372477600026034341">Լրացուցիչ հանգույցներ</translation>
+<translation id="8373046809163484087">Օգտագործեք գունային հավաքածուներ, որոնք համապատասխանում են ձեր պաստառին</translation>
 <translation id="8380114448424469341">Ամրացնել պատուհանը էկրանի <ph name="DIRECTION" />ի կեսում</translation>
 <translation id="8395584934117017006">Այս <ph name="DEVICE_TYPE" /> սարքը կառավարվում է կազմակերպության կողմից</translation>
 <translation id="8398927464629426868">Սարքի ընթացիկ լիցքավորման կամ լիցքաթափման արագությունը</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Օգտանուն</translation>
 <translation id="8503836310948963452">Սպասեք ևս մի քանի րոպե…</translation>
 <translation id="8508640263392900755">APN-ի մանրամասներ</translation>
+<translation id="8522687886059337719">Այժմ ձեզ հասանելի են նոր <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />պաստառներ<ph name="END_LINK_WALLPAPER_SUBPAGE" /> և <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />էկրանապահ<ph name="END_LINK_SCREENSAVER_SUBPAGE" /></translation>
 <translation id="8528615187455571738">CrosVm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Ձեր օպերատորի ցանցին միանալու համար կարող է պահանջվել, որ միացնեք այս կարգավորումը։ Մանրամասների համար դիմեք ձեր օպերատորին։</translation>
diff --git a/chromeos/strings/chromeos_strings_id.xtb b/chromeos/strings/chromeos_strings_id.xtb
index 8ec2f002..ed7b729a 100644
--- a/chromeos/strings/chromeos_strings_id.xtb
+++ b/chromeos/strings/chromeos_strings_id.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Berikut beberapa referensi berguna lainnya:</translation>
 <translation id="1905710495812624430">Melebihi batas percobaan maksimum yang diizinkan.</translation>
 <translation id="1908234395526491708">Kegagalan permintaan UDP</translation>
+<translation id="1923388006036088459">Warna aksen</translation>
 <translation id="1947737735496445907">Tercetak</translation>
 <translation id="1951012854035635156">Asisten</translation>
 <translation id="1962550982027027473">APN default diperlukan</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Download selesai</translation>
 <translation id="3969602104473960991">Sandi ChromeOS diperbarui</translation>
 <translation id="397105322502079400">Menghitung...</translation>
+<translation id="3974175076798940554">Aset Chromebook Plus eksklusif kini tersedia</translation>
 <translation id="39823212440917567">Tugas pencetakan yang sudah lebih dari <ph name="NUMBER_OF_DAYS" /> hari akan dihapus</translation>
 <translation id="3993704782688964914"><ph name="DEVICE_NAME" /> Anda sekarang sudah diupdate</translation>
 <translation id="4003384961948020559">Gagal - Baki hasil cetak penuh</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Tambahkan akun ke fitur masuk banyak akun. Semua akun yang masuk dapat diakses tanpa menggunakan sandi, sebaiknya hanya gunakan akun ini dengan akun tepercaya.</translation>
 <translation id="8364946094152050673">Server nama kosong</translation>
 <translation id="8372477600026034341">Host tambahan</translation>
+<translation id="8373046809163484087">Gunakan kumpulan warna yang cocok dengan wallpaper Anda</translation>
 <translation id="8380114448424469341">Kaitkan jendela di paruh <ph name="DIRECTION" /> layar</translation>
 <translation id="8395584934117017006"><ph name="DEVICE_TYPE" /> ini dikelola perusahaan</translation>
 <translation id="8398927464629426868">Kecepatan pengisian atau pemakaian daya perangkat saat ini</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Nama Pengguna</translation>
 <translation id="8503836310948963452">Tinggal beberapa menit lagi...</translation>
 <translation id="8508640263392900755">Detail APN</translation>
+<translation id="8522687886059337719">Sekarang Anda memiliki akses ke <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />wallpaper<ph name="END_LINK_WALLPAPER_SUBPAGE" /> dan <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />screensaver<ph name="END_LINK_SCREENSAVER_SUBPAGE" /> baru</translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Operator Anda mungkin memerlukan opsi ini untuk terhubung ke jaringan. Hubungi operator untuk mengetahui detailnya.</translation>
diff --git a/chromeos/strings/chromeos_strings_is.xtb b/chromeos/strings/chromeos_strings_is.xtb
index 86110e3..f91c78b 100644
--- a/chromeos/strings/chromeos_strings_is.xtb
+++ b/chromeos/strings/chromeos_strings_is.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Hér eru fleiri gagnleg úrræði:</translation>
 <translation id="1905710495812624430">Farið var yfir hámarksfjölda tilrauna.</translation>
 <translation id="1908234395526491708">UDP-beiðnir mistókust</translation>
+<translation id="1923388006036088459">Áherslulitir</translation>
 <translation id="1947737735496445907">Prentað</translation>
 <translation id="1951012854035635156">Aðstoðarmaður</translation>
 <translation id="1962550982027027473">Sjálfgefinn aðgangsstaður er nauðsynlegur</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Niðurhali lokið</translation>
 <translation id="3969602104473960991">Aðgangsorð ChromeOS var uppfært</translation>
 <translation id="397105322502079400">Reiknar...</translation>
+<translation id="3974175076798940554">Nú eru sérvaldar Chromebook Plus-eignir í boði</translation>
 <translation id="39823212440917567">Prentverk sem eru eldri en <ph name="NUMBER_OF_DAYS" /> verða fjarlægð</translation>
 <translation id="3993704782688964914"><ph name="DEVICE_NAME" /> er nú uppfært</translation>
 <translation id="4003384961948020559">Mistókst – úttakið er fullt</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Bæta reikningi við innskráningu á marga reikninga. Hægt er að fá aðgang að öllum innskráðum reikningum án aðgangsorðs og því ætti aðeins að nota þennan eiginleika með traustum reikningum.</translation>
 <translation id="8364946094152050673">Auðir nafnaþjónar</translation>
 <translation id="8372477600026034341">Aukahýslar</translation>
+<translation id="8373046809163484087">Notaðu liti sem passa við veggfóðrið</translation>
 <translation id="8380114448424469341">Festa glugga til <ph name="DIRECTION" /> á skjánum</translation>
 <translation id="8395584934117017006">Þessu <ph name="DEVICE_TYPE" /> tæki er stjórnað af fyrirtæki</translation>
 <translation id="8398927464629426868">Núverandi hleðslu- eða afhleðsluhraði tækisins</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Notandanafn</translation>
 <translation id="8503836310948963452">Aðeins nokkrar mínútur í viðbót…</translation>
 <translation id="8508640263392900755">Upplýsingar um aðgangsstað</translation>
+<translation id="8522687886059337719">Nú hefurðu aðgang að nýjum <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />veggfóðrum<ph name="END_LINK_WALLPAPER_SUBPAGE" /> og <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />skjávörum<ph name="END_LINK_SCREENSAVER_SUBPAGE" /></translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Símafyrirtæki kunna að biðja þig um slíkt til að tengjast neti þeirra. Hafðu samband við símafyrirtækið til að fá frekari upplýsingar.</translation>
diff --git a/chromeos/strings/chromeos_strings_kn.xtb b/chromeos/strings/chromeos_strings_kn.xtb
index 2009449..adbfae14 100644
--- a/chromeos/strings/chromeos_strings_kn.xtb
+++ b/chromeos/strings/chromeos_strings_kn.xtb
@@ -517,6 +517,7 @@
 <translation id="5423849171846380976">ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ</translation>
 <translation id="5430931332414098647">ತತ್‌ಕ್ಷಣದ ಟೆಥರಿಂಗ್‌</translation>
 <translation id="5431318178759467895">ಬಣ್ಣ</translation>
+<translation id="5456936324019847994">ಯಾವುದೇ ಸಕ್ರಿಯಗೊಳಿಸಿದ ಕಸ್ಟಮ್ APN ಗಳಿಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ ನಿಮ್ಮ ಮೊಬೈಲ್ ಕ್ಯಾರಿಯರ್ ಅನ್ನು ಸಂಪರ್ಕಿಸಿ.</translation>
 <translation id="5457599981699367932">ಅತಿಥಿಯಾಗಿ ಬ್ರೌಸ್ ಮಾಡಿ</translation>
 <translation id="54609108002486618">ನಿರ್ವಹಿಸಲಾಗಿದೆ</translation>
 <translation id="5478289488939624992">{ATTEMPTS_LEFT,plural, =1{{0} ಪ್ರಯತ್ನ ಬಾಕಿ ಉಳಿದಿದೆ}one{{0} ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}other{{0} ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}}</translation>
@@ -572,6 +573,7 @@
 <translation id="5931523347251946569">ಫೈಲ್ ಕಂಡುಬಂದಿಲ್ಲ</translation>
 <translation id="5939518447894949180">ಮರುಹೊಂದಿಸು</translation>
 <translation id="594552776027197022">ರ‍್ಯಾಂಡಮ್ ಕೀ ಜೋಡಿಯನ್ನು ರಚಿಸಿ</translation>
+<translation id="5946538341867151940">ನೀವು ಇನ್ನೂ ಕನೆಕ್ಟ್ ಮಾಡಿಲ್ಲ. ನಿಮ್ಮ ಮೊಬೈಲ್ ಕ್ಯಾರಿಯರ್ ಕಸ್ಟಮ್ APN ಅನ್ನು ಶಿಫಾರಸು ಮಾಡಿದರೆ, "+ ಹೊಸ APN" ಅನ್ನು ಆಯ್ಕೆಮಾಡುವ ಮೂಲಕ APN ಮಾಹಿತಿಯನ್ನು ನಮೂದಿಸಿ</translation>
 <translation id="5972388717451707488">ಎಂಜಿನ್ ಅಪ್‌ಡೇಟ್ ಮಾಡಿ</translation>
 <translation id="5984145644188835034">ಡೀಫಾಲ್ಟ್ ವಾಲ್‌ಪೇಪರ್</translation>
 <translation id="6017514345406065928">ಹಸಿರು</translation>
diff --git a/chromeos/strings/chromeos_strings_ko.xtb b/chromeos/strings/chromeos_strings_ko.xtb
index c085fa55..01eec64 100644
--- a/chromeos/strings/chromeos_strings_ko.xtb
+++ b/chromeos/strings/chromeos_strings_ko.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">다음은 몇 가지 유용한 리소스입니다.</translation>
 <translation id="1905710495812624430">허용되는 최대 시도 횟수를 초과했습니다.</translation>
 <translation id="1908234395526491708">UDP 요청 실패</translation>
+<translation id="1923388006036088459">강조 색상</translation>
 <translation id="1947737735496445907">인쇄됨</translation>
 <translation id="1951012854035635156">어시스턴트</translation>
 <translation id="1962550982027027473">기본 APN이 필요합니다.</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">다운로드 완료</translation>
 <translation id="3969602104473960991">ChromeOS 비밀번호 업데이트됨</translation>
 <translation id="397105322502079400">계산 중...</translation>
+<translation id="3974175076798940554">독점 Chromebook Plus 애셋 사용 가능</translation>
 <translation id="39823212440917567"><ph name="NUMBER_OF_DAYS" />일 이상 경과한 인쇄 작업은 삭제됩니다.</translation>
 <translation id="3993704782688964914"><ph name="DEVICE_NAME" /> 버전이 최신임</translation>
 <translation id="4003384961948020559">실패 - 출력 가득 참</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">멀티 로그인에 계정을 추가하세요. 비밀번호를 입력하지 않고 모든 로그인 계정에 액세스할 수 있으므로 이 기능은 신뢰할 수 있는 계정에만 사용해야 합니다.</translation>
 <translation id="8364946094152050673">네임서버가 비어 있습니다.</translation>
 <translation id="8372477600026034341">추가 호스트</translation>
+<translation id="8373046809163484087">배경화면에 어울리는 색상 조합을 사용하세요.</translation>
 <translation id="8380114448424469341">화면의 <ph name="DIRECTION" /> 절반에 창 고정</translation>
 <translation id="8395584934117017006"><ph name="DEVICE_TYPE" /> 기기는 기업에서 관리합니다.</translation>
 <translation id="8398927464629426868">기기가 현재 충전 또는 방전되는 속도</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">사용자 이름</translation>
 <translation id="8503836310948963452">몇 분 정도밖에 남지 않았습니다...</translation>
 <translation id="8508640263392900755">APN 세부정보</translation>
+<translation id="8522687886059337719">이제 새로운 <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />배경화면<ph name="END_LINK_WALLPAPER_SUBPAGE" /> 및 <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />화면 보호기<ph name="END_LINK_SCREENSAVER_SUBPAGE" />에 액세스할 수 있습니다.</translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">이동통신사에서 네트워크에 연결하기 위해 이 옵션을 요구할 수 있습니다. 자세한 내용은 이동통신사에 문의하세요.</translation>
diff --git a/chromeos/strings/chromeos_strings_ky.xtb b/chromeos/strings/chromeos_strings_ky.xtb
index 53134a8..dea23b45 100644
--- a/chromeos/strings/chromeos_strings_ky.xtb
+++ b/chromeos/strings/chromeos_strings_ky.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Бул жерде башка пайдалуу булактар келтирилди:</translation>
 <translation id="1905710495812624430">Аракеттер уруксат берилген чегинен ашты.</translation>
 <translation id="1908234395526491708">Ишке ашпай калган UDP сурамдары</translation>
+<translation id="1923388006036088459">Негизги түстөр</translation>
 <translation id="1947737735496445907">Басып чыгарылды</translation>
 <translation id="1951012854035635156">Жардамчы</translation>
 <translation id="1962550982027027473">Демейки APN талап кылынат</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Жүктөп алуу аяктады</translation>
 <translation id="3969602104473960991">ChromeOS сырсөзү өзгөрдү</translation>
 <translation id="397105322502079400">Эсептелүүдө…</translation>
+<translation id="3974175076798940554">Эми эксклюзивдүү Chromebook Plus объекттери жеткиликтүү</translation>
 <translation id="39823212440917567"><ph name="NUMBER_OF_DAYS" /> күндөн мурунку басып чыгаруу тапшырмалары өчүрүлөт</translation>
 <translation id="3993704782688964914"><ph name="DEVICE_NAME" /> түзмөгүңүз жаңыртылды</translation>
 <translation id="4003384961948020559">Басылып чыгарылган жок - Барактар тактасы толук</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Бир нече профиль менен кирүү үчүн каттоо эсебин кошуңуз. Катталган бардык аккаунттарына кирүүдө сырсөз талап кылынбагандыктан, бул мүмкүнчүлүктү ишенимдүү каттоо эсептери гана колдонушу керек.</translation>
 <translation id="8364946094152050673">Ысым серверлери бош</translation>
 <translation id="8372477600026034341">Кошумча башкы түйүндөр</translation>
+<translation id="8373046809163484087">Тушкагазыңызга туура келген түстөрдүн топтомдорун колдонуңуз</translation>
 <translation id="8380114448424469341">Терезени экрандын <ph name="DIRECTION" /> жактагы жарымына бекитүү</translation>
 <translation id="8395584934117017006">Бул <ph name="DEVICE_TYPE" /> түзмөгүн ишкана башкарат</translation>
 <translation id="8398927464629426868">Түзмөк кубатталган же кубатталышы токтотулган деңгээл</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Колдонуучунун ысымы</translation>
 <translation id="8503836310948963452">Дагы бир нече мүнөт калды...</translation>
 <translation id="8508640263392900755">APN тууралуу маалымат</translation>
+<translation id="8522687886059337719">Эми жаңы <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />тушкагаздарды<ph name="END_LINK_WALLPAPER_SUBPAGE" /> жана <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />көшөгөнү<ph name="END_LINK_SCREENSAVER_SUBPAGE" /> колдоно аласыз</translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Тармакка туташуу үчүн байланыш оператору бул параметрди талап кылышы мүмкүн. Кеңири маалымат үчүн байланыш операторуңузга кайрылыңыз</translation>
diff --git a/chromeos/strings/chromeos_strings_lt.xtb b/chromeos/strings/chromeos_strings_lt.xtb
index a0c91272..60c7d268 100644
--- a/chromeos/strings/chromeos_strings_lt.xtb
+++ b/chromeos/strings/chromeos_strings_lt.xtb
@@ -517,6 +517,7 @@
 <translation id="5423849171846380976">Suaktyvinta</translation>
 <translation id="5430931332414098647">Momentinis įrenginio kaip modemo naudojimas</translation>
 <translation id="5431318178759467895">Spalva</translation>
+<translation id="5456936324019847994">Nepavyksta prisijungti prie jokių įgalintų tinkintų APN. Susisiekite su mobiliojo ryšio operatoriumi, kad gautumėte daugiau informacijos.</translation>
 <translation id="5457599981699367932">Naršyti kaip svečiui</translation>
 <translation id="54609108002486618">Valdoma</translation>
 <translation id="5478289488939624992">{ATTEMPTS_LEFT,plural, =1{Liko {0} bandymas}one{Liko {0} bandymas}few{Liko {0} bandymai}many{Liko {0} bandymo}other{Liko {0} bandymų}}</translation>
diff --git a/chromeos/strings/chromeos_strings_lv.xtb b/chromeos/strings/chromeos_strings_lv.xtb
index e26df95b..dcae2a2 100644
--- a/chromeos/strings/chromeos_strings_lv.xtb
+++ b/chromeos/strings/chromeos_strings_lv.xtb
@@ -517,6 +517,7 @@
 <translation id="5423849171846380976">Aktivizēts</translation>
 <translation id="5430931332414098647">Tūlītēja piesaiste</translation>
 <translation id="5431318178759467895">Krāsās</translation>
+<translation id="5456936324019847994">Nevar izveidot savienojumu ne ar vienu iespējoto pielāgoto APN. Lai iegūtu plašāku informāciju, sazinieties ar savu mobilo sakaru operatoru.</translation>
 <translation id="5457599981699367932">Pārlūkot kā viesim</translation>
 <translation id="54609108002486618">Pārvaldītais</translation>
 <translation id="5478289488939624992">{ATTEMPTS_LEFT,plural, =1{Atlicis {0} mēģinājums.}zero{Atlikuši {0} mēģinājumi.}one{Atlicis {0} mēģinājums.}other{Atlikuši {0} mēģinājumi.}}</translation>
diff --git a/chromeos/strings/chromeos_strings_mk.xtb b/chromeos/strings/chromeos_strings_mk.xtb
index 72aaf202b..92c643d4 100644
--- a/chromeos/strings/chromeos_strings_mk.xtb
+++ b/chromeos/strings/chromeos_strings_mk.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Еве неколку други корисни ресурси:</translation>
 <translation id="1905710495812624430">Максималниот број дозволени обиди е надминат.</translation>
 <translation id="1908234395526491708">Неуспешни UDP-барања</translation>
+<translation id="1923388006036088459">Бои за истакнување</translation>
 <translation id="1947737735496445907">Отпечатено</translation>
 <translation id="1951012854035635156">Помошник</translation>
 <translation id="1962550982027027473">Стандардна APN е задолжителна</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Преземањето е завршено</translation>
 <translation id="3969602104473960991">Лозинката за Chrome OS е ажурирана</translation>
 <translation id="397105322502079400">Се пресметува…</translation>
+<translation id="3974175076798940554">Сега се достапни ексклузивни средства на Chromebook Plus</translation>
 <translation id="39823212440917567">Задачите за печатење постари од <ph name="NUMBER_OF_DAYS" /> дена ќе се отстранат</translation>
 <translation id="3993704782688964914">Уредот <ph name="DEVICE_NAME" /> сега е ажуриран</translation>
 <translation id="4003384961948020559">Неуспешно - излезната фиока е полна</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Додајте сметка за повеќекратно најавување. Сите најавени сметки се достапни без лозинка, така што оваа можност треба да се користи само со сметки на кои им се верува.</translation>
 <translation id="8364946094152050673">Празни сервери за име</translation>
 <translation id="8372477600026034341">Дополнителни хостови</translation>
+<translation id="8373046809163484087">Користете комплети бои што се совпаѓаат со вашиот тапет</translation>
 <translation id="8380114448424469341">Приклучи го прозорецот на док на половината <ph name="DIRECTION" /> на екранот</translation>
 <translation id="8395584934117017006">Организација управува со овој <ph name="DEVICE_TYPE" /></translation>
 <translation id="8398927464629426868">Брзината со која уредот се полни или празни во моментов</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Корисничко име</translation>
 <translation id="8503836310948963452">Само уште неколку минути…</translation>
 <translation id="8508640263392900755">Детали за APN</translation>
+<translation id="8522687886059337719">Сега имате пристап до нови <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />тапети<ph name="END_LINK_WALLPAPER_SUBPAGE" /> и <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />заштитник на екран<ph name="END_LINK_SCREENSAVER_SUBPAGE" /></translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Оваа опција може да е задолжителна за да се поврзете на мрежата на операторот. Контактирајте со операторот за детали.</translation>
diff --git a/chromeos/strings/chromeos_strings_ml.xtb b/chromeos/strings/chromeos_strings_ml.xtb
index 56ddcd9..305a3cd 100644
--- a/chromeos/strings/chromeos_strings_ml.xtb
+++ b/chromeos/strings/chromeos_strings_ml.xtb
@@ -517,6 +517,7 @@
 <translation id="5423849171846380976">സജീവമാക്കി</translation>
 <translation id="5430931332414098647">തൽക്ഷണ ടെതറിംഗ്</translation>
 <translation id="5431318178759467895">വര്‍ണ്ണം</translation>
+<translation id="5456936324019847994">പ്രവർത്തനക്ഷമമാക്കിയ ഇഷ്ടാനുസൃത APN-കളിലേക്കൊന്നും കണക്റ്റ് ചെയ്യാനാകുന്നില്ല. കൂടുതൽ വിവരങ്ങൾക്ക് നിങ്ങളുടെ മൊബൈൽ സേവനദാതാവിനെ ബന്ധപ്പെടുക.</translation>
 <translation id="5457599981699367932">അതിഥിയായി ബ്രൗസ് ചെയ്യുക</translation>
 <translation id="54609108002486618">നിയന്ത്രിതം</translation>
 <translation id="5478289488939624992">{ATTEMPTS_LEFT,plural, =1{{0} ശ്രമം ശേഷിക്കുന്നു}other{{0} ശ്രമങ്ങൾ ശേഷിക്കുന്നു}}</translation>
@@ -572,6 +573,7 @@
 <translation id="5931523347251946569">ഫയൽ കണ്ടെത്തിയില്ല</translation>
 <translation id="5939518447894949180">റീസെറ്റ് ചെയ്യുക</translation>
 <translation id="594552776027197022">ക്രമരഹിതമായ കീ ജോടി സൃഷ്‌ടിക്കുക</translation>
+<translation id="5946538341867151940">നിങ്ങൾ ഇതുവരെ കണക്റ്റ് ചെയ്‌തിട്ടില്ല. നിങ്ങളുടെ മൊബൈൽ സേവനദാതാവ് ഒരു ഇഷ്‌ടാനുസൃത APN നിർദ്ദേശിക്കുന്നുവെങ്കിൽ, "+ പുതിയ APN" തിരഞ്ഞെടുത്ത് APN വിവരങ്ങൾ നൽകുക</translation>
 <translation id="5972388717451707488">Update Engine</translation>
 <translation id="5984145644188835034">ഡിഫോൾട്ട് വാൾപേപ്പർ</translation>
 <translation id="6017514345406065928">പച്ച</translation>
diff --git a/chromeos/strings/chromeos_strings_ne.xtb b/chromeos/strings/chromeos_strings_ne.xtb
index 87466fd..53e6f71 100644
--- a/chromeos/strings/chromeos_strings_ne.xtb
+++ b/chromeos/strings/chromeos_strings_ne.xtb
@@ -517,6 +517,7 @@
 <translation id="5423849171846380976">सक्रिय भयो</translation>
 <translation id="5430931332414098647">तात्कालिक टेदरिङ</translation>
 <translation id="5431318178759467895">रङ्ग</translation>
+<translation id="5456936324019847994">अन गरिएको कुनै पनि कस्टम APN सँग कनेक्ट गर्न सकिएन। तपाईं यस सम्बन्धमा थप जानकारी प्राप्त गर्न चाहनुहुन्छ भने आफ्नो मोबाइलको सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।</translation>
 <translation id="5457599981699367932">पाहुनाको रूपमा ब्राउज गर्नुहोस्</translation>
 <translation id="54609108002486618">व्यवस्थापन गरिएको</translation>
 <translation id="5478289488939624992">{ATTEMPTS_LEFT,plural, =1{अब {0} पटक प्रयास गर्न मिल्छ}other{अब {0} पटक प्रयास गर्न मिल्छ}}</translation>
diff --git a/chromeos/strings/chromeos_strings_nl.xtb b/chromeos/strings/chromeos_strings_nl.xtb
index f6e661f..e3660c82 100644
--- a/chromeos/strings/chromeos_strings_nl.xtb
+++ b/chromeos/strings/chromeos_strings_nl.xtb
@@ -517,6 +517,7 @@
 <translation id="5423849171846380976">Geactiveerd</translation>
 <translation id="5430931332414098647">Instant-tethering</translation>
 <translation id="5431318178759467895">Kleur</translation>
+<translation id="5456936324019847994">Kan geen verbinding maken met aangezette aangepaste APN's. Neem contact op met je mobiele provider voor meer informatie.</translation>
 <translation id="5457599981699367932">Gebruiken als gast</translation>
 <translation id="54609108002486618">Beheerd</translation>
 <translation id="5478289488939624992">{ATTEMPTS_LEFT,plural, =1{Nog {0} poging}other{Nog {0} pogingen}}</translation>
diff --git a/chromeos/strings/chromeos_strings_or.xtb b/chromeos/strings/chromeos_strings_or.xtb
index a356ba1..c171223 100644
--- a/chromeos/strings/chromeos_strings_or.xtb
+++ b/chromeos/strings/chromeos_strings_or.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">ଏଠାରେ ଅନ୍ୟ କିଛି ଉପଯୋଗୀ ରିସୋର୍ସ ଅଛି:</translation>
 <translation id="1905710495812624430">ସର୍ବାଧିକ ଅନୁମୋଦିତ ପ୍ରଚେଷ୍ଟା ସୀମା ଅତିକ୍ରମ କଲା।</translation>
 <translation id="1908234395526491708">UDP ଅନୁରୋଧ ବିଫଳ</translation>
+<translation id="1923388006036088459">ଆକ୍ସେଣ୍ଟ ରଙ୍ଗଗୁଡ଼ିକ</translation>
 <translation id="1947737735496445907">ପ୍ରିଣ୍ଟ କରାଯାଇଛି</translation>
 <translation id="1951012854035635156">Assistant</translation>
 <translation id="1962550982027027473">ଏକ ଡିଫଲ୍ଟ APN ଆବଶ୍ୟକ</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">ଡାଉନ୍‍‍‍ଲୋଡ୍ ଶେଷ ହୋଇଛି</translation>
 <translation id="3969602104473960991">ChromeOSର ପାସୱାର୍ଡ ଅପଡେଟ ହୋଇଛି</translation>
 <translation id="397105322502079400">ଗଣନା କରାଯାଉଛି…</translation>
+<translation id="3974175076798940554">ଏକ୍ସକ୍ଲୁସିଭ Chromebook Plus ଆସେଟ୍ସ ବର୍ତ୍ତମାନ ଉପଲବ୍ଧ ଅଛି</translation>
 <translation id="39823212440917567"><ph name="NUMBER_OF_DAYS" /> ଦିନରୁ ଅଧିକ ପୁରୁଣା ପ୍ରିଣ୍ଟ କାର୍ଯ୍ୟଗୁଡ଼ିକୁ କାଢ଼ି ଦିଆଯିବ</translation>
 <translation id="3993704782688964914">ଆପଣଙ୍କ <ph name="DEVICE_NAME" /> ବର୍ତ୍ତମାନ ଅପଟୁଡେଟ ଅଛି</translation>
 <translation id="4003384961948020559">ବିଫଳ ହୋଇଛି - ଆଉଟପୁଟ୍ ଟ୍ରେ ପୂର୍ଣ୍ଣ ଅଛି</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">ଏକାଧିକ ସାଇନ୍-ଇନ୍ କରିବାକୁ ଏକ ଆକାଉଣ୍ଟ ଯୋଗ କରନ୍ତୁ। ସାଇନ୍-ଇନ୍ ହୋଇଥିବା ସମସ୍ତ ଆକାଉଣ୍ଟ ବିନା ପାସ୍‌ୱର୍ଡରେ ଆକ୍ସେସ୍ କରାଯାଇପାରିବ, ତେଣୁ ଏହି ସୁବିଧା କେବଳ ବିଶ୍ୱସ୍ତ ଆକାଉଣ୍ଟ ସହ ବ୍ୟବହାର କରାଯିବା ଉଚିତ୍।</translation>
 <translation id="8364946094152050673">ନେମ୍ ସର୍ଭର୍ ଖାଲି ଅଛି</translation>
 <translation id="8372477600026034341">ଅତିରିକ୍ତ ହୋଷ୍ଟଗୁଡ଼ିକ</translation>
+<translation id="8373046809163484087">ଆପଣଙ୍କ ୱାଲପେପର ସହ ମେଳ ହେଉଥିବା ରଙ୍ଗ ସେଟଗୁଡ଼ିକୁ ବ୍ୟବହାର କରନ୍ତୁ</translation>
 <translation id="8380114448424469341">ସ୍କ୍ରିନର <ph name="DIRECTION" /> ଅଧା ଅଂଶରେ ୱିଣ୍ଡୋକୁ ଡକ କରନ୍ତୁ</translation>
 <translation id="8395584934117017006">ଏହି <ph name="DEVICE_TYPE" /> ଏଣ୍ଟରପ୍ରାଇଜ୍ ଦ୍ୱାରା ପରିଚାଳିତ ହେଉଛି</translation>
 <translation id="8398927464629426868">ଡିଭାଇସଟି ବର୍ତ୍ତମାନ ଯେଉଁ ହାରରେ ଚାର୍ଜ କିମ୍ବା ଡିସଚାର୍ଜ ହେଉଛି</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">ଉପଯୋଗକର୍ତ୍ତାନାମ</translation>
 <translation id="8503836310948963452">ଆଉ ଅଳ୍ପ କିଛି ମିନିଟ୍ ଅଛି…</translation>
 <translation id="8508640263392900755">APN ବିବରଣୀ</translation>
+<translation id="8522687886059337719">ବର୍ତ୍ତମାନ ନୂଆ <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />ୱାଲପେପର<ph name="END_LINK_WALLPAPER_SUBPAGE" /> ଏବଂ <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />ସ୍କ୍ରିନ ସେଭର<ph name="END_LINK_SCREENSAVER_SUBPAGE" />କୁ ଆପଣଙ୍କର ଆକ୍ସେସ ଅଛି</translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">ଆପଣଙ୍କ କ୍ୟାରିଅର୍ ଏହାର ନେଟୱାର୍କ ସହ ସଂଯୋଗ କରିବାକୁ ଏହି ବିକଳ୍ପ ଆବଶ୍ୟକ କରିପାରେ। ବିବରଣୀ ପାଇଁ ଆପଣଙ୍କ କ୍ୟାରିଅର୍ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।</translation>
diff --git a/chromeos/strings/chromeos_strings_pt-PT.xtb b/chromeos/strings/chromeos_strings_pt-PT.xtb
index 6064b39..29dc286d 100644
--- a/chromeos/strings/chromeos_strings_pt-PT.xtb
+++ b/chromeos/strings/chromeos_strings_pt-PT.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Seguem-se outros recursos úteis:</translation>
 <translation id="1905710495812624430">Foi excedido o número máximo de tentativas permitidas.</translation>
 <translation id="1908234395526491708">Falhas de pedidos de UDP.</translation>
+<translation id="1923388006036088459">Cores de destaque</translation>
 <translation id="1947737735496445907">Impressão concluída</translation>
 <translation id="1951012854035635156">Assistente</translation>
 <translation id="1962550982027027473">É necessário um APN predefinido</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Transferência concluída</translation>
 <translation id="3969602104473960991">A palavra-passe do ChromeOS foi atualizada</translation>
 <translation id="397105322502079400">A calcular...</translation>
+<translation id="3974175076798940554">Recursos exclusivos do Chromebook Plus já disponíveis</translation>
 <translation id="39823212440917567">As tarefas de impressão com mais de <ph name="NUMBER_OF_DAYS" /> dias serão removidas.</translation>
 <translation id="3993704782688964914">O dispositivo <ph name="DEVICE_NAME" /> está agora atualizado</translation>
 <translation id="4003384961948020559">Falha – Saída cheia</translation>
@@ -846,6 +848,7 @@
 <translation id="8352772353338965963">Adicione uma conta para início de sessão integrado. É possível aceder a todas as contas com a sessão iniciada sem uma palavra-passe, por isso, só deve usar esta funcionalidade com contas fidedignas.</translation>
 <translation id="8364946094152050673">Os servidores de nomes estão vazios.</translation>
 <translation id="8372477600026034341">Anfitriões adicionais</translation>
+<translation id="8373046809163484087">Use conjuntos de cores que combinem com a sua imagem de fundo</translation>
 <translation id="8380114448424469341">Ancorar a janela na metade <ph name="DIRECTION" /> do ecrã</translation>
 <translation id="8395584934117017006">Este <ph name="DEVICE_TYPE" /> é gerido pela empresa.</translation>
 <translation id="8398927464629426868">A velocidade de carregamento ou descarregamento atual do dispositivo.</translation>
@@ -865,6 +868,7 @@
 <translation id="8503813439785031346">Nome de utilizador</translation>
 <translation id="8503836310948963452">Só mais alguns minutos…</translation>
 <translation id="8508640263392900755">Detalhes do APN (Nome do Ponto de Acesso)</translation>
+<translation id="8522687886059337719">Agora, tem acesso a novas <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />imagens de fundo<ph name="END_LINK_WALLPAPER_SUBPAGE" /> e <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />proteção de ecrã<ph name="END_LINK_SCREENSAVER_SUBPAGE" /></translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">O operador pode exigir esta opção para estabelecer ligação à respetiva rede. Contacte o seu operador para obter mais detalhes.</translation>
diff --git a/chromeos/strings/chromeos_strings_ru.xtb b/chromeos/strings/chromeos_strings_ru.xtb
index 92191ab..15bdbf87 100644
--- a/chromeos/strings/chromeos_strings_ru.xtb
+++ b/chromeos/strings/chromeos_strings_ru.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Вот некоторые источники полезной информации:</translation>
 <translation id="1905710495812624430">Превышено максимально допустимое число попыток.</translation>
 <translation id="1908234395526491708">Невыполненные запросы UDP.</translation>
+<translation id="1923388006036088459">Акцентные цвета</translation>
 <translation id="1947737735496445907">Напечатано</translation>
 <translation id="1951012854035635156">Ассистент</translation>
 <translation id="1962550982027027473">Укажите точку доступа по умолчанию</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Скачивание завершено.</translation>
 <translation id="3969602104473960991">Пароль Chrome OS изменен</translation>
 <translation id="397105322502079400">Вычисление…</translation>
+<translation id="3974175076798940554">Эксклюзивный контент для Chromebook Plus</translation>
 <translation id="39823212440917567">Задания печати, хранящиеся дольше <ph name="NUMBER_OF_DAYS" /> дн., будут удалены</translation>
 <translation id="3993704782688964914"><ph name="DEVICE_NAME" />: установлено актуальное ПО</translation>
 <translation id="4003384961948020559">Сбой: выходной лоток заполнен</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Добавить аккаунт в систему множественного входа. Для доступа к аккаунтам, в которые выполнен вход, пароль не требуется, поэтому эту функцию следует использовать только для надежных аккаунтов.</translation>
 <translation id="8364946094152050673">Не указаны серверы доменных имен.</translation>
 <translation id="8372477600026034341">Дополнительные хосты</translation>
+<translation id="8373046809163484087">Используйте цвета в тон обоев</translation>
 <translation id="8380114448424469341">Закрепить окно <ph name="DIRECTION" /> на половину экрана</translation>
 <translation id="8395584934117017006">Этим устройством <ph name="DEVICE_TYPE" /> управляет организация.</translation>
 <translation id="8398927464629426868">Скорость, с которой устройство заряжается или разряжается в настоящее время</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Имя пользователя</translation>
 <translation id="8503836310948963452">Осталось несколько минут…</translation>
 <translation id="8508640263392900755">Сведения о точке доступа</translation>
+<translation id="8522687886059337719">Вам доступны новые <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />обои<ph name="END_LINK_WALLPAPER_SUBPAGE" /> и <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />заставка<ph name="END_LINK_SCREENSAVER_SUBPAGE" />.</translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Возможно, вам потребуется установить этот параметр, чтобы подключиться к сети. За подробными сведениями обращайтесь к своему оператору связи.</translation>
diff --git a/chromeos/strings/chromeos_strings_si.xtb b/chromeos/strings/chromeos_strings_si.xtb
index 544efaff..a99952e 100644
--- a/chromeos/strings/chromeos_strings_si.xtb
+++ b/chromeos/strings/chromeos_strings_si.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">මෙන්න තවත් උපකාරී සම්පත් කිහිපයක්:</translation>
 <translation id="1905710495812624430">ඉඩ දෙන උපරිම උත්සාහයන් ගණන ඉක්මවා ඇත.</translation>
 <translation id="1908234395526491708">UDP ඉල්ලීම් අසාර්ථක වීම්</translation>
+<translation id="1923388006036088459">අවධාරණ වර්ණ</translation>
 <translation id="1947737735496445907">මුද්‍රණය කරන ලදි</translation>
 <translation id="1951012854035635156">සහායක</translation>
 <translation id="1962550982027027473">පෙරනිමි APN එකක් අවශ්‍යයි</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">බාගැනීම සම්පූර්ණයි</translation>
 <translation id="3969602104473960991">ChromeOS මුරපදය යාවත්කාලීන කරන ලදි</translation>
 <translation id="397105322502079400">ගණනය කරමින්...</translation>
+<translation id="3974175076798940554">සුවිශේෂී Chromebook Plus වත්කම් දැන් තිබේ</translation>
 <translation id="39823212440917567">දින <ph name="NUMBER_OF_DAYS" />කට වඩා පැරණි මුද්‍රණ කාර්ය ඉවත් කරනු ඇත</translation>
 <translation id="3993704782688964914">ඔබගේ <ph name="DEVICE_NAME" /> දැන් යාවත්කාලීනයි</translation>
 <translation id="4003384961948020559">අසාර්ථක විය - ප්‍රතිදානය පිරී ඇත</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">බහු පිවිසුම් සඳහා ගිනුමක් එක් කරන්න. සියළු පිවිසි ගිනුම් වෙත මුරපදයක් නොමැතිව පිවිසිය හැක. එම නිසා මෙම විශේෂාංගය භාවිත කළ යුත්තේ විශ්වාසී ගිනුම් සමඟ පමණි.</translation>
 <translation id="8364946094152050673">හිස් නම් සේවාදායක</translation>
 <translation id="8372477600026034341">අතිරේක සංග්‍රාහක</translation>
+<translation id="8373046809163484087">ඔබේ වෝල්පේපරයට ගැළපෙන වර්ණ කට්ටල භාවිතා කරන්න</translation>
 <translation id="8380114448424469341">කවුළුව තිරයෙහි <ph name="DIRECTION" /> අර්ධයෙහි ඈඳන්න</translation>
 <translation id="8395584934117017006">මෙම <ph name="DEVICE_TYPE" /> ව්‍යවසාය කළමනාකරණය කෙරේ</translation>
 <translation id="8398927464629426868">උපාංගය දැනට ආරෝපණය වන හෝ විසර්ජනය වන වේගය</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">පරිශීලක නාමය</translation>
 <translation id="8503836310948963452">හුදෙක් තව මිනිත්තු කීපයකි...</translation>
 <translation id="8508640263392900755">APN විස්තර</translation>
+<translation id="8522687886059337719">ඔබට දැන් නව <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />වෝල්පේපර<ph name="END_LINK_WALLPAPER_SUBPAGE" /> සහ <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />තිර සුරැකුම<ph name="END_LINK_SCREENSAVER_SUBPAGE" /> වෙත ප්‍රවේශය ඇත</translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">ඔබගේ වාහකයට ඔවුන්ගේ ජාලයට සම්බන්ධ වීමට මෙම විකල්පය අවශ්‍ය විය හැකිය. විස්තර සඳහා ඔබගේ වාහකය අමතන්න.</translation>
diff --git a/chromeos/strings/chromeos_strings_sk.xtb b/chromeos/strings/chromeos_strings_sk.xtb
index b5fe4f4..ed9918f 100644
--- a/chromeos/strings/chromeos_strings_sk.xtb
+++ b/chromeos/strings/chromeos_strings_sk.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Tu je niekoľko ďalších užitočných zdrojov:</translation>
 <translation id="1905710495812624430">Maximálny počet povolených pokusov bol prekročený.</translation>
 <translation id="1908234395526491708">Neúspešné žiadosti UDP</translation>
+<translation id="1923388006036088459">Zvýrazňujúce farby</translation>
 <translation id="1947737735496445907">Vytlačené</translation>
 <translation id="1951012854035635156">Asistent</translation>
 <translation id="1962550982027027473">Vyžaduje sa predvolený názov prístupového bodu (APN)</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Sťahovanie dokončené</translation>
 <translation id="3969602104473960991">Heslo systému Chrome OS bolo aktualizované</translation>
 <translation id="397105322502079400">Prebieha výpočet...</translation>
+<translation id="3974175076798940554">K dispozícii sú exkluzívne podklady pre Chromebooku Plus</translation>
 <translation id="39823212440917567">Tlačové úlohy staršie ako <ph name="NUMBER_OF_DAYS" /> d. budú odstránené</translation>
 <translation id="3993704782688964914">Vaše zariadenie <ph name="DEVICE_NAME" /> je teraz aktuálne</translation>
 <translation id="4003384961948020559">Nepodarilo sa – výstup je plný</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Pridanie účtu pre viacnásobné prihlásenie. Ku všetkým prihláseným účtom môžete pristupovať bez hesla, takže táto funkcia by mala byť použitá iba s dôveryhodnými účtami.</translation>
 <translation id="8364946094152050673">Prázdne DNS servery</translation>
 <translation id="8372477600026034341">Ďalší hostitelia</translation>
+<translation id="8373046809163484087">Použite skupiny farieb, ktoré zodpovedajú vašej tapete</translation>
 <translation id="8380114448424469341">Ukotviť okno na <ph name="DIRECTION" /> polovici obrazovky</translation>
 <translation id="8395584934117017006">Toto zariadenie <ph name="DEVICE_TYPE" /> spravuje podnik</translation>
 <translation id="8398927464629426868">Rýchlosť, akou sa zariadenie momentálne nabíja či vybíja</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Meno používateľa</translation>
 <translation id="8503836310948963452">Už iba niekoľko minút…</translation>
 <translation id="8508640263392900755">Podrobnosti názvu prístupového bodu (APN)</translation>
+<translation id="8522687886059337719">Teraz máte prístup k novým <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />tapetám<ph name="END_LINK_WALLPAPER_SUBPAGE" /> a <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />šetriču obrazovky<ph name="END_LINK_SCREENSAVER_SUBPAGE" /></translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Váš operátor môže túto možnosť vyžadovať na pripojenie k jeho sieti. Podrobnosti vám poskytne operátor.</translation>
diff --git a/chromeos/strings/chromeos_strings_sq.xtb b/chromeos/strings/chromeos_strings_sq.xtb
index f2a4bfa..e041622 100644
--- a/chromeos/strings/chromeos_strings_sq.xtb
+++ b/chromeos/strings/chromeos_strings_sq.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Këtu janë disa burime të tjera të dobishme:</translation>
 <translation id="1905710495812624430">U kaluan përpjekjet maksimale të lejuara.</translation>
 <translation id="1908234395526491708">Dështimet e kërkesave UDP</translation>
+<translation id="1923388006036088459">Ngjyrat e theksimit</translation>
 <translation id="1947737735496445907">Printuar</translation>
 <translation id="1951012854035635156">Asistenti</translation>
 <translation id="1962550982027027473">Kërkohet një APN e parazgjedhur</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Shkarkimi përfundoi</translation>
 <translation id="3969602104473960991">Fjalëkalimi i ChromeOS u përditësua</translation>
 <translation id="397105322502079400">Po llogarit...</translation>
+<translation id="3974175076798940554">Tani ofrohen elemente ekskluzive të Chromebook Plus</translation>
 <translation id="39823212440917567">Printimet më të vjetra se <ph name="NUMBER_OF_DAYS" /> ditë do të hiqen</translation>
 <translation id="3993704782688964914"><ph name="DEVICE_NAME" /> tani është përditësuar</translation>
 <translation id="4003384961948020559">Dështoi - Dalja është plot</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Shto një llogari në identifikimin e shumëfishtë. Të gjitha llogaritë e identifikuara mund të qasen pa fjalëkalim, prandaj ky funksion duhet të përdoret vetëm me llogari të besuara.</translation>
 <translation id="8364946094152050673">Serverët DNS janë bosh</translation>
 <translation id="8372477600026034341">Pritësit e tjerë</translation>
+<translation id="8373046809163484087">Përdor paketat e ngjyrave që përputhen me imazhin tënd të sfondit</translation>
 <translation id="8380114448424469341">Dritarja e stacionit në gjysmën <ph name="DIRECTION" /> të ekranit</translation>
 <translation id="8395584934117017006">Kjo pajisje <ph name="DEVICE_TYPE" /> menaxhohet nga ndërmarrja</translation>
 <translation id="8398927464629426868">Shpejtësia me të cilën pajisja aktualisht po karikohet ose po shkarkohet</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Emri i përdoruesit</translation>
 <translation id="8503836310948963452">Edhe vetëm pak minuta...</translation>
 <translation id="8508640263392900755">Detajet e APN-së</translation>
+<translation id="8522687886059337719">Tani ke qasje tek <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />imazhet e reja të sfondit<ph name="END_LINK_WALLPAPER_SUBPAGE" /> dhe te <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />mbrojtësit e rinj të ekranit<ph name="END_LINK_SCREENSAVER_SUBPAGE" /></translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Operatori celular mund të kërkojë këtë opsion për t'u lidhur me rrjetin e tij. Kontakto me operatorin celular për detaje.</translation>
diff --git a/chromeos/strings/chromeos_strings_te.xtb b/chromeos/strings/chromeos_strings_te.xtb
index 9347336d..c8f5e44 100644
--- a/chromeos/strings/chromeos_strings_te.xtb
+++ b/chromeos/strings/chromeos_strings_te.xtb
@@ -517,6 +517,7 @@
 <translation id="5423849171846380976">సక్రియం చేయబడింది</translation>
 <translation id="5430931332414098647">తక్షణ టెథెరింగ్</translation>
 <translation id="5431318178759467895">రంగు</translation>
+<translation id="5456936324019847994">ఎనేబుల్ చేసి ఉన్న ఏ అనుకూల APNలకు కనెక్ట్ అవ్వడమూ సాధ్యం కాదు. మరింత సమాచారం కోసం మీ మొబైల్ క్యారియర్‌ను సంప్రదించండి.</translation>
 <translation id="5457599981699367932">అతిథి లాగా బ్రౌజ్ చేయండి</translation>
 <translation id="54609108002486618">నిర్వహించబడింది</translation>
 <translation id="5478289488939624992">{ATTEMPTS_LEFT,plural, =1{{0} ప్రయత్నం మిగిలి ఉంది}other{{0} ప్రయత్నాలు మిగిలి ఉన్నాయి}}</translation>
diff --git a/chromeos/strings/chromeos_strings_tr.xtb b/chromeos/strings/chromeos_strings_tr.xtb
index 2c12244..3108baa 100644
--- a/chromeos/strings/chromeos_strings_tr.xtb
+++ b/chromeos/strings/chromeos_strings_tr.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">İşinize yarayabilecek diğer kaynaklar:</translation>
 <translation id="1905710495812624430">İzin verilen maksimum deneme sayısı aşıldı.</translation>
 <translation id="1908234395526491708">UDP istek hataları</translation>
+<translation id="1923388006036088459">Vurgu renkleri</translation>
 <translation id="1947737735496445907">Yazdırıldı</translation>
 <translation id="1951012854035635156">Asistan</translation>
 <translation id="1962550982027027473">Varsayılan bir APN gerekli</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">İndirme tamamlandı</translation>
 <translation id="3969602104473960991">ChromeOS şifresi güncellendi</translation>
 <translation id="397105322502079400">Hesaplanııyor...</translation>
+<translation id="3974175076798940554">Özel Chromebook Plus öğeleri artık kullanılabilir</translation>
 <translation id="39823212440917567"><ph name="NUMBER_OF_DAYS" /> günden eski yazdırma işleri silinir</translation>
 <translation id="3993704782688964914"><ph name="DEVICE_NAME" /> cihazınız artık güncel</translation>
 <translation id="4003384961948020559">İşlem başarısız - Çıkış dolu</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Çoklu oturum açmaya bir hesap ekleyin. Oturum açılmış tüm hesaplara şifresiz erişilebileceği için bu özellik sadece güvenilir hesaplarla kullanılmalıdır.</translation>
 <translation id="8364946094152050673">Alan adı sunucuları boş</translation>
 <translation id="8372477600026034341">Ekstra ana makineler</translation>
+<translation id="8373046809163484087">Duvar kağıdınızla eşleşen renkler kullanın</translation>
 <translation id="8380114448424469341">Pencereyi, ekranın <ph name="DIRECTION" /> yarısına sabitleyin</translation>
 <translation id="8395584934117017006">Bu <ph name="DEVICE_TYPE" />, kuruluş tarafından yönetiliyor</translation>
 <translation id="8398927464629426868">Cihazın şu andaki şarj olma veya şarjının boşalma hızı</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Kullanıcı adı</translation>
 <translation id="8503836310948963452">Sadece birkaç dakika kaldı…</translation>
 <translation id="8508640263392900755">APN ayrıntıları</translation>
+<translation id="8522687886059337719">Artık yeni <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />duvar kağıtları<ph name="END_LINK_WALLPAPER_SUBPAGE" /> ve <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />ekran koruyucu<ph name="END_LINK_SCREENSAVER_SUBPAGE" /> özelliklerine erişebilirsiniz</translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Operatörünüz, ağlarına bağlanmak için bu seçeneği gerektirebilir. Ayrıntılı bilgiler için operatörünüzle iletişime geçin.</translation>
diff --git a/chromeos/strings/chromeos_strings_uk.xtb b/chromeos/strings/chromeos_strings_uk.xtb
index 0484989..a4aec24c 100644
--- a/chromeos/strings/chromeos_strings_uk.xtb
+++ b/chromeos/strings/chromeos_strings_uk.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Нижче наведено інші корисні ресурси.</translation>
 <translation id="1905710495812624430">Перевищено максимальну кількість дозволених спроб.</translation>
 <translation id="1908234395526491708">Не виконано запити за протоколом UDP</translation>
+<translation id="1923388006036088459">Акцентні кольори</translation>
 <translation id="1947737735496445907">Надруковано</translation>
 <translation id="1951012854035635156">Асистент</translation>
 <translation id="1962550982027027473">Укажіть точку доступу за умовчанням</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Завантажено</translation>
 <translation id="3969602104473960991">Пароль ОС Chrome оновлено</translation>
 <translation id="397105322502079400">Обчислення...</translation>
+<translation id="3974175076798940554">Тепер доступні ексклюзивні об’єкти Chromebook Plus</translation>
 <translation id="39823212440917567">Завдання друку, старіші за <ph name="NUMBER_OF_DAYS" /> дн., буде вилучено</translation>
 <translation id="3993704782688964914"><ph name="DEVICE_NAME" />: пристрій оновлено</translation>
 <translation id="4003384961948020559">Не надруковано – вихідний лоток заповнений</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Додайте обліковий запис для паралельного входу. Доступ до всіх облікових записів, у які ви ввійшли, можна отримувати без пароля, тому цю функцію варто використовувати лише з надійними обліковими записами.</translation>
 <translation id="8364946094152050673">Сервери імен порожні</translation>
 <translation id="8372477600026034341">Додаткові хости</translation>
+<translation id="8373046809163484087">Використовувати набори кольорів, які відповідають фоновому малюнку</translation>
 <translation id="8380114448424469341">Закріпити вікно <ph name="DIRECTION" /> на половину екрана</translation>
 <translation id="8395584934117017006">Цим пристроєм <ph name="DEVICE_TYPE" /> керує організація</translation>
 <translation id="8398927464629426868">Поточна сила струму заряджання або розряджання</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Ім’я користувача</translation>
 <translation id="8503836310948963452">Залишилося кілька хвилин…</translation>
 <translation id="8508640263392900755">Відомості про APN</translation>
+<translation id="8522687886059337719">Тепер ви маєте доступ до нових <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />фонових малюнків<ph name="END_LINK_WALLPAPER_SUBPAGE" /> і <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />заставок<ph name="END_LINK_SCREENSAVER_SUBPAGE" /></translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Можливо, вам доведеться ввімкнути це налаштування, щоб підключитися до мережі. Щоб дізнатися більше, зверніться до свого оператора.</translation>
diff --git a/chromeos/strings/chromeos_strings_uz.xtb b/chromeos/strings/chromeos_strings_uz.xtb
index 83c8f4ef..59b5835 100644
--- a/chromeos/strings/chromeos_strings_uz.xtb
+++ b/chromeos/strings/chromeos_strings_uz.xtb
@@ -123,6 +123,7 @@
 <translation id="1904932688895783618">Quyidagi manbalar foydali boʻlishi mumkin:</translation>
 <translation id="1905710495812624430">Urinishlar soni cheklovdan oshib ketdi.</translation>
 <translation id="1908234395526491708">Bajarilmagan UDP soʻrovlari</translation>
+<translation id="1923388006036088459">Aksent ranglari</translation>
 <translation id="1947737735496445907">Chop etildi</translation>
 <translation id="1951012854035635156">Assistent</translation>
 <translation id="1962550982027027473">Standart APN talab qilinadi</translation>
@@ -332,6 +333,7 @@
 <translation id="3967822245660637423">Yuklab olindi</translation>
 <translation id="3969602104473960991">ChromeOS paroli yangilandi</translation>
 <translation id="397105322502079400">Hisoblanmoqda...</translation>
+<translation id="3974175076798940554">Chromebook Plus ekskluziv resurslari chiqdi</translation>
 <translation id="39823212440917567"><ph name="NUMBER_OF_DAYS" /> kundan eski chop etish vazifalari avtomatik tozalanadi</translation>
 <translation id="3993704782688964914"><ph name="DEVICE_NAME" /> hozir yangi</translation>
 <translation id="4003384961948020559">Bajarilmadi - Boʻsh joy qolmadi</translation>
@@ -845,6 +847,7 @@
 <translation id="8352772353338965963">Bir nechta hisobga kirish tizimiga hisob qo‘shish. Kirish bajarilgan hisoblarni ko‘rish uchun parol so‘ralmaydi, shuning uchun bu funksiyadan faqat ishonchli hisoblarda foydalanish kerak.</translation>
 <translation id="8364946094152050673">Nom serverlari kiritilmagan</translation>
 <translation id="8372477600026034341">Qoʻshimcha hostlar</translation>
+<translation id="8373046809163484087">Fonga mos ranglar majmuasidan foydalaning</translation>
 <translation id="8380114448424469341">Oynani yarim ekran <ph name="DIRECTION" /> mahkamlash</translation>
 <translation id="8395584934117017006">Bu <ph name="DEVICE_TYPE" /> korporativ domen boshqaruvida</translation>
 <translation id="8398927464629426868">Qurilmaning quvvat olish yoki sarflash darajasi</translation>
@@ -864,6 +867,7 @@
 <translation id="8503813439785031346">Foydalanuvchi nomi</translation>
 <translation id="8503836310948963452">Yana bir necha daqiqa kuting…</translation>
 <translation id="8508640263392900755">APN tafsiloti</translation>
+<translation id="8522687886059337719">Endi yangi <ph name="BEGIN_LINK_WALLPAPER_SUBPAGE" />fon rasmlari<ph name="END_LINK_WALLPAPER_SUBPAGE" /> va <ph name="BEGIN_LINK_SCREENSAVER_SUBPAGE" />ekran lavhasini<ph name="END_LINK_SCREENSAVER_SUBPAGE" /> ishlatish mumkin</translation>
 <translation id="8528615187455571738">Crosvm</translation>
 <translation id="8557447961879934694">WPA2</translation>
 <translation id="8575298406870537639">Aloqa operatoringiz oʻz tarmogʻiga ulanishi uchun bu parametrni talab qilishi mumkin. Tafsilotlar uchun aloqa operatoringizga murojaat qiling.</translation>
diff --git a/chromeos/strings/chromeos_strings_zu.xtb b/chromeos/strings/chromeos_strings_zu.xtb
index 53f98e0..66def1b1 100644
--- a/chromeos/strings/chromeos_strings_zu.xtb
+++ b/chromeos/strings/chromeos_strings_zu.xtb
@@ -572,6 +572,7 @@
 <translation id="5931523347251946569">Ifayela alitholakalanga</translation>
 <translation id="5939518447894949180">Setha kabusha</translation>
 <translation id="594552776027197022">Khiqiza ukubhanqa ukhiye okungahleliwe</translation>
+<translation id="5946538341867151940">Awuxhunyiwe okwamanje. Uma inkampani yakho yenethiwekhi incoma i-APN yangokwezifiso, faka imininingwane ye-APN ngokukhetha "+ I-APN Entsha"</translation>
 <translation id="5972388717451707488">Buyekeza Inini</translation>
 <translation id="5984145644188835034">Isithombe Sangemuva Esizenzakalelayo</translation>
 <translation id="6017514345406065928">Okuluhlaza</translation>
diff --git a/components/autofill/core/browser/autofill_suggestion_generator.cc b/components/autofill/core/browser/autofill_suggestion_generator.cc
index 530c911..3d418b0 100644
--- a/components/autofill/core/browser/autofill_suggestion_generator.cc
+++ b/components/autofill/core/browser/autofill_suggestion_generator.cc
@@ -18,6 +18,7 @@
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/autofill_optimization_guide.h"
 #include "components/autofill/core/browser/data_model/autofill_offer_data.h"
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/browser/data_model/iban.h"
 #include "components/autofill/core/browser/field_filler.h"
@@ -129,6 +130,17 @@
   for (auto& suggestion : suggestions) {
     suggestion.frontend_id = MakeFrontendIdFromBackendId(
         suggestion.GetPayload<Suggestion::BackendId>());
+
+    // Populate feature IPH for externally created account profiles.
+    const AutofillProfile* profile = personal_data_->GetProfileByGUID(
+        suggestion.GetPayload<Suggestion::BackendId>().value());
+    if (profile && profile->source() == AutofillProfile::Source::kAccount &&
+        profile->initial_creator_id() !=
+            AutofillProfile::kInitialCreatorOrModifierChrome) {
+      suggestion.feature_for_iph =
+          feature_engagement::
+              kIPHAutofillExternalAccountProfileSuggestionFeature.name;
+    }
   }
 
   return suggestions;
diff --git a/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc b/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
index 26aec90..67f509e 100644
--- a/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
+++ b/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
@@ -75,7 +75,9 @@
   // Log issuer-specific metrics on whether metadata was shown.
   LogCardWithMetadataFormEventMetric(
       autofill_metrics::CardMetadataLoggingEvent::kShown,
-      metadata_logging_context_);
+      metadata_logging_context_,
+      HasBeenLogged(has_logged_suggestion_with_metadata_shown_));
+  has_logged_suggestion_with_metadata_shown_ = true;
 }
 
 void CreditCardFormEventLogger::OnDidSelectCardSuggestion(
@@ -128,7 +130,9 @@
       form);
   LogCardWithMetadataFormEventMetric(
       autofill_metrics::CardMetadataLoggingEvent::kSelected,
-      metadata_logging_context_);
+      metadata_logging_context_,
+      HasBeenLogged(has_logged_suggestion_with_metadata_selected_));
+  has_logged_suggestion_with_metadata_selected_ = true;
 }
 
 void CreditCardFormEventLogger::OnDidFillSuggestion(
diff --git a/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.h b/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.h
index ff976da..9a0f6bfed 100644
--- a/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.h
+++ b/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.h
@@ -134,6 +134,8 @@
   bool DoSuggestionsIncludeVirtualCard();
 
   UnmaskAuthFlowType current_authentication_flow_;
+  bool has_logged_suggestion_with_metadata_shown_ = false;
+  bool has_logged_suggestion_with_metadata_selected_ = false;
   bool has_logged_masked_server_card_suggestion_selected_ = false;
   bool has_logged_virtual_card_suggestion_selected_ = false;
   bool logged_suggestion_filled_was_masked_server_card_ = false;
diff --git a/components/autofill/core/browser/metrics/payments/card_metadata_metrics.cc b/components/autofill/core/browser/metrics/payments/card_metadata_metrics.cc
index 438627d9..0d5850a 100644
--- a/components/autofill/core/browser/metrics/payments/card_metadata_metrics.cc
+++ b/components/autofill/core/browser/metrics/payments/card_metadata_metrics.cc
@@ -113,7 +113,8 @@
 
 void LogCardWithMetadataFormEventMetric(
     CardMetadataLoggingEvent event,
-    const CardMetadataLoggingContext& context) {
+    const CardMetadataLoggingContext& context,
+    HasBeenLogged has_been_logged) {
   for (const auto& [issuer, has_metadata] :
        context.issuer_to_metadata_availability) {
     switch (event) {
@@ -122,12 +123,24 @@
                                       GetCardIssuerIdSuffix(issuer) +
                                       ".ShownWithMetadata",
                                   has_metadata);
+        if (!has_been_logged.value()) {
+          base::UmaHistogramBoolean("Autofill.CreditCard." +
+                                        GetCardIssuerIdSuffix(issuer) +
+                                        ".ShownWithMetadataOnce",
+                                    has_metadata);
+        }
         break;
       case CardMetadataLoggingEvent::kSelected:
         base::UmaHistogramBoolean("Autofill.CreditCard." +
                                       GetCardIssuerIdSuffix(issuer) +
                                       ".SelectedWithMetadata",
                                   has_metadata);
+        if (!has_been_logged.value()) {
+          base::UmaHistogramBoolean("Autofill.CreditCard." +
+                                        GetCardIssuerIdSuffix(issuer) +
+                                        ".SelectedWithMetadataOnce",
+                                    has_metadata);
+        }
         break;
     }
   }
diff --git a/components/autofill/core/browser/metrics/payments/card_metadata_metrics.h b/components/autofill/core/browser/metrics/payments/card_metadata_metrics.h
index 9ddc7f8..ee69f94 100644
--- a/components/autofill/core/browser/metrics/payments/card_metadata_metrics.h
+++ b/components/autofill/core/browser/metrics/payments/card_metadata_metrics.h
@@ -32,6 +32,8 @@
   kMaxValue = kSelected,
 };
 
+using HasBeenLogged = base::StrongAlias<class HasBeenLoggedTag, bool>;
+
 // Struct that groups metadata-related information together for some set of
 // credit cards. Used for metrics logging.
 struct CardMetadataLoggingContext {
@@ -54,9 +56,12 @@
 CardMetadataLoggingContext GetMetadataLoggingContext(
     const std::vector<CreditCard>& cards);
 
+// Log the suggestion event regarding card metadata. `has_been_logged` indicates
+// whether the event has already been logged since last page load.
 void LogCardWithMetadataFormEventMetric(
     CardMetadataLoggingEvent event,
-    const CardMetadataLoggingContext& context);
+    const CardMetadataLoggingContext& context,
+    HasBeenLogged has_been_logged);
 
 // Log the latency between suggestions being shown and a suggestion was
 // selected, in milliseconds, and it is broken down by metadata availability
diff --git a/components/autofill/core/browser/metrics/payments/card_metadata_metrics_unittest.cc b/components/autofill/core/browser/metrics/payments/card_metadata_metrics_unittest.cc
index b5b2f8d..ea7ed62 100644
--- a/components/autofill/core/browser/metrics/payments/card_metadata_metrics_unittest.cc
+++ b/components/autofill/core/browser/metrics/payments/card_metadata_metrics_unittest.cc
@@ -101,9 +101,24 @@
                  card_issuer_available() && card_metadata_available()),
           Bucket(FORM_EVENT_CARD_SUGGESTION_WITHOUT_METADATA_SHOWN,
                  !card_issuer_available() || !card_metadata_available())));
+
   histogram_tester.ExpectUniqueSample(
       "Autofill.CreditCard.Amex.ShownWithMetadata", card_metadata_available(),
-      card_issuer_available());
+      card_issuer_available() ? 1 : 0);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.CreditCard.Amex.ShownWithMetadataOnce",
+      card_metadata_available(), card_issuer_available() ? 1 : 0);
+
+  // Show the popup again.
+  autofill_manager().OnAskForValuesToFillTest(form(), form().fields.back());
+  autofill_manager().DidShowSuggestions(/*has_autofill_suggestions=*/true,
+                                        form(), form().fields.back());
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.CreditCard.Amex.ShownWithMetadata", card_metadata_available(),
+      card_issuer_available() ? 2 : 0);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.CreditCard.Amex.ShownWithMetadataOnce",
+      card_metadata_available(), card_issuer_available() ? 1 : 0);
 }
 
 // Test metadata selected metrics are correctly logged.
@@ -136,7 +151,22 @@
                  !card_issuer_available() || !card_metadata_available())));
   histogram_tester.ExpectUniqueSample(
       "Autofill.CreditCard.Amex.SelectedWithMetadata",
-      card_metadata_available(), card_issuer_available());
+      card_metadata_available(), card_issuer_available() ? 1 : 0);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.CreditCard.Amex.SelectedWithMetadataOnce",
+      card_metadata_available(), card_issuer_available() ? 1 : 0);
+
+  // Select the suggestion again.
+  autofill_manager().FillOrPreviewForm(
+      mojom::RendererFormDataAction::kFill, form(), form().fields.back(),
+      MakeFrontendId({.credit_card_id = kCardGuid}),
+      AutofillTriggerSource::kPopup);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.CreditCard.Amex.SelectedWithMetadata",
+      card_metadata_available(), card_issuer_available() ? 2 : 0);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.CreditCard.Amex.SelectedWithMetadataOnce",
+      card_metadata_available(), card_issuer_available() ? 1 : 0);
 }
 
 // Params:
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp
index b14b823..e39e14e 100644
--- a/components/autofill_strings.grdp
+++ b/components/autofill_strings.grdp
@@ -166,6 +166,10 @@
     </message>
   </if>
 
+  <message name="IDS_AUTOFILL_IPH_EXTERNAL_ACCOUNT_PROFILE_SUGGESTION" desc="IPH bubble for a suggestion item with an account profile that was created somewhere outside Chrome (e.g. Google Pay).">
+    You can now use addresses from your Google Account.
+  </message>
+
   <!-- Autofill suggestion label separator -->
   <message name="IDS_AUTOFILL_SUGGESTION_LABEL_SEPARATOR" desc="A separator to place between different elements of a suggestion's label. Labels sometimes have more than one type of information, such as a phone number and an email address or a street address, a phone number, and an email address. A symbol, in this case a bullet •, with a white space before it and a white space after it, is used to separate the parts of the label that appear on the same line, e.g. (877) 733-7699 • fanfeedback@redsox.com or 465 Huntington Ave • (617) 267-9300 • matthewt@mfa.org. A bullet • is preferred for separating the label parts; however, if the bullet • resembles another symbol in the language, please translate the bullet • as a symbol (A) that is not easily mistaken for a number or letter in the language and (B) that is typically used to separate elements.">
   ''' • '''</message>
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_IPH_EXTERNAL_ACCOUNT_PROFILE_SUGGESTION.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_IPH_EXTERNAL_ACCOUNT_PROFILE_SUGGESTION.png.sha1
new file mode 100644
index 0000000..719cfe8
--- /dev/null
+++ b/components/autofill_strings_grdp/IDS_AUTOFILL_IPH_EXTERNAL_ACCOUNT_PROFILE_SUGGESTION.png.sha1
@@ -0,0 +1 @@
+b7e7184ad7aeae775ea014f00d74f937fccb013b
\ No newline at end of file
diff --git a/components/bookmarks/browser/bookmark_model.cc b/components/bookmarks/browser/bookmark_model.cc
index 98fa518..fe16b01 100644
--- a/components/bookmarks/browser/bookmark_model.cc
+++ b/components/bookmarks/browser/bookmark_model.cc
@@ -351,6 +351,10 @@
   for (BookmarkModelObserver& observer : observers_) {
     observer.BookmarkNodeMoved(this, old_parent, old_index, new_parent, index);
   }
+
+  if (old_parent != new_parent) {
+    metrics::RecordBookmarkMovedTo(GetFolderType(new_parent));
+  }
 }
 
 void BookmarkModel::UpdateLastUsedTime(const BookmarkNode* node,
@@ -744,6 +748,19 @@
   }
 }
 
+metrics::BookmarkFolderTypeForUMA BookmarkModel::GetFolderType(
+    const BookmarkNode* folder) const {
+  CHECK(folder->is_folder());
+  if (folder == bookmark_bar_node()) {
+    return metrics::BookmarkFolderTypeForUMA::kBookmarksBar;
+  } else if (folder == other_node()) {
+    return metrics::BookmarkFolderTypeForUMA::kOtherBookmarks;
+  } else if (folder == mobile_node()) {
+    return metrics::BookmarkFolderTypeForUMA::kMobileBookmarks;
+  }
+  return metrics::BookmarkFolderTypeForUMA::kUserGeneratedFolder;
+}
+
 const BookmarkNode* BookmarkModel::AddFolder(
     const BookmarkNode* parent,
     size_t index,
@@ -772,7 +789,7 @@
   if (meta_info) {
     new_node->SetMetaInfoMap(*meta_info);
   }
-
+  metrics::RecordBookmarkFolderAdded(GetFolderType(parent));
   return AddNode(AsMutable(parent), index, std::move(new_node));
 }
 
@@ -782,7 +799,7 @@
     const std::u16string& title,
     const GURL& url,
     const BookmarkNode::MetaInfoMap* meta_info) {
-  metrics::RecordBookmarkAdded();
+  metrics::RecordUrlBookmarkAdded(GetFolderType(parent));
   return AddURL(parent, index, title, url, meta_info, absl::nullopt,
                 absl::nullopt, true);
 }
diff --git a/components/bookmarks/browser/bookmark_model.h b/components/bookmarks/browser/bookmark_model.h
index 389f8773..ec38fda 100644
--- a/components/bookmarks/browser/bookmark_model.h
+++ b/components/bookmarks/browser/bookmark_model.h
@@ -220,6 +220,10 @@
   // same or not.
   void GetBookmarks(std::vector<UrlAndTitle>* urls);
 
+  // Returns the type of |folder| as represented in metrics.
+  metrics::BookmarkFolderTypeForUMA GetFolderType(
+      const BookmarkNode* folder) const;
+
   // Adds a new folder node at the specified position with the given
   // |creation_time|, |uuid| and |meta_info|. If no UUID is provided (i.e.
   // nullopt), then a random one will be generated. If a UUID is provided, it
diff --git a/components/bookmarks/common/bookmark_metrics.cc b/components/bookmarks/common/bookmark_metrics.cc
index 56672df7..08b2da31 100644
--- a/components/bookmarks/common/bookmark_metrics.cc
+++ b/components/bookmarks/common/bookmark_metrics.cc
@@ -9,13 +9,25 @@
 #include "components/bookmarks/common/url_load_stats.h"
 
 namespace {
+
 const int kBytesPerKB = 1024;
+
+void RecordBookmarkParentFolderType(
+    bookmarks::metrics::BookmarkFolderTypeForUMA parent) {
+  base::UmaHistogramEnumeration("Bookmarks.ParentFolderType", parent);
+}
 }
 
 namespace bookmarks::metrics {
 
-void RecordBookmarkAdded() {
+void RecordUrlBookmarkAdded(BookmarkFolderTypeForUMA parent) {
   base::RecordAction(base::UserMetricsAction("Bookmarks.Added"));
+  RecordBookmarkParentFolderType(parent);
+}
+
+void RecordBookmarkFolderAdded(BookmarkFolderTypeForUMA parent) {
+  base::RecordAction(base::UserMetricsAction("Bookmarks.FolderAdded"));
+  RecordBookmarkParentFolderType(parent);
 }
 
 void RecordBookmarkRemoved(BookmarkEditSource source) {
@@ -34,6 +46,10 @@
   base::RecordAction(base::UserMetricsAction("Bookmarks.Opened"));
 }
 
+void RecordBookmarkMovedTo(BookmarkFolderTypeForUMA new_parent) {
+  RecordBookmarkParentFolderType(new_parent);
+}
+
 void RecordTimeSinceLastScheduledSave(base::TimeDelta delta) {
   base::UmaHistogramLongTimes("Bookmarks.Storage.TimeSinceLastScheduledSave",
                               delta);
diff --git a/components/bookmarks/common/bookmark_metrics.h b/components/bookmarks/common/bookmark_metrics.h
index fba8b43..96f0ba6 100644
--- a/components/bookmarks/common/bookmark_metrics.h
+++ b/components/bookmarks/common/bookmark_metrics.h
@@ -13,6 +13,17 @@
 
 namespace metrics {
 
+// Enum for folder categories, reported through UMA. Present in enums.xml as
+// BookmarkFolderType. New values should be added at the end and things should
+// not be renumbered.
+enum class BookmarkFolderTypeForUMA {
+  kBookmarksBar = 0,
+  kOtherBookmarks = 1,
+  kMobileBookmarks = 2,
+  kUserGeneratedFolder = 3,
+  kMaxValue = kUserGeneratedFolder,
+};
+
 // Enum for possible sources for edits, reported through UMA. Present in
 // enums.xml as BookmarkEditSource. New values should be added at the end
 // and things should not be renumbered.
@@ -26,7 +37,10 @@
 };
 
 // Records when a bookmark is added by the user.
-void RecordBookmarkAdded();
+void RecordUrlBookmarkAdded(BookmarkFolderTypeForUMA parent);
+
+// Records when a bookmark folder is added by the user.
+void RecordBookmarkFolderAdded(BookmarkFolderTypeForUMA parent);
 
 // Records when a bookmark is removed.
 void RecordBookmarkRemoved(BookmarkEditSource source);
@@ -36,6 +50,10 @@
                           base::Time date_last_used,
                           base::Time date_added);
 
+// Records when a bookmark or bookmark folder is moved to a different parent
+// folder.
+void RecordBookmarkMovedTo(BookmarkFolderTypeForUMA new_parent);
+
 // Records the time since the last save with a 1 hour max. The first save will
 // record the time since startup.
 void RecordTimeSinceLastScheduledSave(base::TimeDelta delta);
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb
index 2c089de..c916095 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb
@@ -153,7 +153,7 @@
 <translation id="3721953990244350188">关闭此操作并显示下一项可查看的操作</translation>
 <translation id="3744111561329211289">后台同步</translation>
 <translation id="3763247130972274048">在视频左侧或右侧点按两次即可跳过 10 秒</translation>
-<translation id="3794286421982011626">您访问的网站可以保存与您正在进行的浏览活动有关的信息,以便网站能按预期运行 - 例如,以便保持您在网站上的登录状态或者保存您的购物车内的商品。网站通常会将这类信息暂时保存在您的设备上。</translation>
+<translation id="3794286421982011626">您访问的网站可以保存与您正在进行的浏览活动有关的信息,以便确保网站能按预期运行,例如保持您在网站上的登录状态或者保存您的购物车内的商品。网站通常会将这类信息暂时保存在您的设备上。</translation>
 <translation id="3797520601150691162">不对特定网站应用深色主题</translation>
 <translation id="3803367742635802571">您访问的网站可能会停止按预期运行</translation>
 <translation id="3804247818991980532"><ph name="TYPE_1" />。<ph name="TYPE_2" />。</translation>
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index 417737d6..e654262 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "20.39",
-  "log_list_timestamp": "2023-04-14T12:54:04Z",
+  "version": "20.40",
+  "log_list_timestamp": "2023-04-15T12:53:45Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/commerce/core/android/java/src/org/chromium/components/commerce/core/ShoppingService.java b/components/commerce/core/android/java/src/org/chromium/components/commerce/core/ShoppingService.java
index 8a958f6..49963d49 100644
--- a/components/commerce/core/android/java/src/org/chromium/components/commerce/core/ShoppingService.java
+++ b/components/commerce/core/android/java/src/org/chromium/components/commerce/core/ShoppingService.java
@@ -231,6 +231,15 @@
                 mNativeShoppingServiceAndroid, this);
     }
 
+    // This is a feature check for the "price tracking", which will return true if the user has the
+    // feature flag enabled or (if applicable) is in an eligible country and locale.
+    public boolean isCommercePriceTrackingEnabled() {
+        if (mNativeShoppingServiceAndroid == 0) return false;
+
+        return ShoppingServiceJni.get().isCommercePriceTrackingEnabled(
+                mNativeShoppingServiceAndroid, this);
+    }
+
     @CalledByNative
     private void destroy() {
         mNativeShoppingServiceAndroid = 0;
@@ -317,5 +326,7 @@
                 int type, int idType, int managementType, String id);
         boolean isShoppingListEligible(long nativeShoppingServiceAndroid, ShoppingService caller);
         boolean isMerchantViewerEnabled(long nativeShoppingServiceAndroid, ShoppingService caller);
+        boolean isCommercePriceTrackingEnabled(
+                long nativeShoppingServiceAndroid, ShoppingService caller);
     }
 }
diff --git a/components/commerce/core/android/shopping_service_android.cc b/components/commerce/core/android/shopping_service_android.cc
index ebcee2b..642eead 100644
--- a/components/commerce/core/android/shopping_service_android.cc
+++ b/components/commerce/core/android/shopping_service_android.cc
@@ -284,4 +284,12 @@
   return shopping_service_->IsMerchantViewerEnabled();
 }
 
+bool ShoppingServiceAndroid::IsCommercePriceTrackingEnabled(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
+  CHECK(shopping_service_);
+
+  return shopping_service_->IsCommercePriceTrackingEnabled();
+}
+
 }  // namespace commerce
diff --git a/components/commerce/core/android/shopping_service_android.h b/components/commerce/core/android/shopping_service_android.h
index 73410a4..247db5d 100644
--- a/components/commerce/core/android/shopping_service_android.h
+++ b/components/commerce/core/android/shopping_service_android.h
@@ -92,6 +92,9 @@
 
   bool IsMerchantViewerEnabled(JNIEnv* env, const JavaParamRef<jobject>& obj);
 
+  bool IsCommercePriceTrackingEnabled(JNIEnv* env,
+                                      const JavaParamRef<jobject>& obj);
+
   ScopedJavaGlobalRef<jobject> java_ref() { return java_ref_; }
 
  private:
diff --git a/components/commerce/core/commerce_feature_list.cc b/components/commerce/core/commerce_feature_list.cc
index ab33865..f8a4010de 100644
--- a/components/commerce/core/commerce_feature_list.cc
+++ b/components/commerce/core/commerce_feature_list.cc
@@ -47,6 +47,7 @@
     map[&kShoppingPDPMetricsRegionLaunched] = {{"us", {"en-us"}}};
     map[&ntp_features::kNtpChromeCartModule] = {{"us", {"en-us"}}};
     map[&kCommerceMerchantViewerRegionLaunched] = {{"us", {"en-us"}}};
+    map[&kCommercePriceTrackingRegionLaunched] = {{"us", {"en-us"}}};
 
     return map;
   }());
@@ -142,6 +143,15 @@
 BASE_FEATURE(kCommercePriceTracking,
              "CommercePriceTracking",
              base::FEATURE_DISABLED_BY_DEFAULT);
+#if BUILDFLAG(IS_ANDROID)
+BASE_FEATURE(kCommercePriceTrackingRegionLaunched,
+             "CommercePriceTrackingRegionLaunched",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+#else
+BASE_FEATURE(kCommercePriceTrackingRegionLaunched,
+             "CommercePriceTrackingRegionLaunched",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+#endif  // BUILDFLAG(IS_ANDROID)
 
 BASE_FEATURE(kCommerceProductInfoApiEnabled,
              "CommerceProductInfoApiEnabled",
diff --git a/components/commerce/core/commerce_feature_list.h b/components/commerce/core/commerce_feature_list.h
index 0e3fe6c..b2cb84b 100644
--- a/components/commerce/core/commerce_feature_list.h
+++ b/components/commerce/core/commerce_feature_list.h
@@ -28,6 +28,7 @@
 }
 
 BASE_DECLARE_FEATURE(kCommercePriceTracking);
+BASE_DECLARE_FEATURE(kCommercePriceTrackingRegionLaunched);
 
 // Price tracking variations for Android.
 constexpr flags_ui::FeatureEntry::FeatureParam
diff --git a/components/commerce/core/shopping_service.cc b/components/commerce/core/shopping_service.cc
index e6846c0..2562ff6 100644
--- a/components/commerce/core/shopping_service.cc
+++ b/components/commerce/core/shopping_service.cc
@@ -415,6 +415,12 @@
                                       country_on_startup_, locale_on_startup_);
 }
 
+bool ShoppingService::IsCommercePriceTrackingEnabled() {
+  return IsRegionLockedFeatureEnabled(kCommercePriceTracking,
+                                      kCommercePriceTrackingRegionLaunched,
+                                      country_on_startup_, locale_on_startup_);
+}
+
 void ShoppingService::HandleOptGuideProductInfoResponse(
     const GURL& url,
     ProductInfoCallback callback,
diff --git a/components/commerce/core/shopping_service.h b/components/commerce/core/shopping_service.h
index 5c9055c..face29e 100644
--- a/components/commerce/core/shopping_service.h
+++ b/components/commerce/core/shopping_service.h
@@ -271,6 +271,11 @@
   // enabled country and locale.
   virtual bool IsMerchantViewerEnabled();
 
+  // This is a feature check for the "price tracking", which will return true
+  // if the user has the feature flag enabled or (if applicable) is in an
+  // enabled country and locale.
+  virtual bool IsCommercePriceTrackingEnabled();
+
   // Get a weak pointer for this service instance.
   base::WeakPtr<ShoppingService> AsWeakPtr();
 
diff --git a/components/feature_engagement/public/feature_configurations.cc b/components/feature_engagement/public/feature_configurations.cc
index 07c252b..ebcbbfe 100644
--- a/components/feature_engagement/public/feature_configurations.cc
+++ b/components/feature_engagement/public/feature_configurations.cc
@@ -1137,6 +1137,35 @@
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
     BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
+
+  if (kIPHAutofillExternalAccountProfileSuggestionFeature.name ==
+      feature->name) {
+    // Externally created account profile suggestion IPH is shown:
+    // * once for an installation, 10-year window is used as the maximum
+    // * if there was no address keyboard accessory IPH in the last 2 weeks
+    // * if such a suggestion was not already accepted
+    absl::optional<FeatureConfig> config = FeatureConfig();
+    config->valid = true;
+    config->availability = Comparator(ANY, 0);
+    config->session_rate = Comparator(EQUAL, 0);
+    config->trigger =
+        EventConfig("autofill_external_account_profile_suggestion_iph_trigger",
+                    Comparator(EQUAL, 0), feature_engagement::kMaxStoragePeriod,
+                    feature_engagement::kMaxStoragePeriod);
+    config->used =
+        EventConfig("autofill_external_account_profile_suggestion_accepted",
+                    Comparator(EQUAL, 0), feature_engagement::kMaxStoragePeriod,
+                    feature_engagement::kMaxStoragePeriod);
+
+#if BUILDFLAG(IS_ANDROID)
+    config->event_configs.insert(
+        EventConfig("keyboard_accessory_address_filling_iph_trigger",
+                    Comparator(EQUAL, 0), 14, k10YearsInDays));
+#endif  // BUILDFLAG(IS_ANDROID)
+
+    return config;
+  }
+
   if (kIPHAutofillVirtualCardSuggestionFeature.name == feature->name) {
     // A config that allows the virtual card credit card suggestion IPH to be
     // shown when:
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc
index a9aab07..74264a3 100644
--- a/components/feature_engagement/public/feature_constants.cc
+++ b/components/feature_engagement/public/feature_constants.cc
@@ -473,6 +473,9 @@
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
     BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
+BASE_FEATURE(kIPHAutofillExternalAccountProfileSuggestionFeature,
+             "IPH_AutofillExternalAccountProfileSuggestion",
+             base::FEATURE_ENABLED_BY_DEFAULT);
 BASE_FEATURE(kIPHAutofillVirtualCardSuggestionFeature,
              "IPH_AutofillVirtualCardSuggestion",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/components/feature_engagement/public/feature_constants.h b/components/feature_engagement/public/feature_constants.h
index 1bad8ab5f..888b4b2 100644
--- a/components/feature_engagement/public/feature_constants.h
+++ b/components/feature_engagement/public/feature_constants.h
@@ -195,6 +195,7 @@
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
     BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
+BASE_DECLARE_FEATURE(kIPHAutofillExternalAccountProfileSuggestionFeature);
 BASE_DECLARE_FEATURE(kIPHAutofillVirtualCardSuggestionFeature);
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
         // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) ||
diff --git a/components/feature_engagement/public/feature_list.cc b/components/feature_engagement/public/feature_list.cc
index b428e41..104256a 100644
--- a/components/feature_engagement/public/feature_list.cc
+++ b/components/feature_engagement/public/feature_list.cc
@@ -172,6 +172,7 @@
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
     BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
+    &kIPHAutofillExternalAccountProfileSuggestionFeature,
     &kIPHAutofillVirtualCardSuggestionFeature,
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
         // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) ||
diff --git a/components/feature_engagement/public/feature_list.h b/components/feature_engagement/public/feature_list.h
index d38335ab..5bfb408 100644
--- a/components/feature_engagement/public/feature_list.h
+++ b/components/feature_engagement/public/feature_list.h
@@ -303,6 +303,8 @@
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
     BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
+DEFINE_VARIATION_PARAM(kIPHAutofillExternalAccountProfileSuggestionFeature,
+                       "IPH_AutofillExternalAccountProfileSuggestion");
 DEFINE_VARIATION_PARAM(kIPHAutofillVirtualCardSuggestionFeature,
                        "IPH_AutofillVirtualCardSuggestion");
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
@@ -470,6 +472,7 @@
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
     BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
+        VARIATION_ENTRY(kIPHAutofillExternalAccountProfileSuggestionFeature),
         VARIATION_ENTRY(kIPHAutofillVirtualCardSuggestionFeature),
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
         // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) ||
diff --git a/components/feed/core/v2/public/common_enums.h b/components/feed/core/v2/public/common_enums.h
index a73ad3b..6efa05b 100644
--- a/components/feed/core/v2/public/common_enums.h
+++ b/components/feed/core/v2/public/common_enums.h
@@ -11,6 +11,22 @@
 // Android.
 namespace feed {
 
+// Values for the UMA ContentSuggestions.Feed.FeedSignInUI histogram.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused. This must be kept in sync with
+// FeedSignInUI in enums.xml.
+enum class FeedSignInUI : int {
+  // Histogram recorded when a sync half sheet is shown from Feed, when sign-in
+  // UI is not supported.
+  kShowSyncHalfSheet = 0,
+  // Histogram recorded when asign in only flow is shown from Feed.
+  kShowSignInOnlyFlow = 1,
+  // Histogram recorded when a service disabled toast is shown from Feed.
+  kShowSignInDisableToast = 2,
+
+  kMaxValue = kShowSignInDisableToast,
+};
+
 // Values for the UMA ContentSuggestions.Feed.EngagementType
 // histogram. These values are persisted to logs. Entries should not be
 // renumbered and numeric values should never be reused. This must be kept
diff --git a/components/metrics/field_trials_provider.cc b/components/metrics/field_trials_provider.cc
index 8356eb8..d4f08df 100644
--- a/components/metrics/field_trials_provider.cc
+++ b/components/metrics/field_trials_provider.cc
@@ -35,7 +35,12 @@
 
 void FieldTrialsProvider::GetFieldTrialIds(
     std::vector<ActiveGroupId>* field_trial_ids) const {
-  variations::GetFieldTrialActiveGroupIds(suffix_, field_trial_ids);
+  base::FieldTrial::ActiveGroups active_groups;
+  // As the trial groups are included in metrics reports, we must not include
+  // the low anonymity trials.
+  base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  variations::GetFieldTrialActiveGroupIds(suffix_, active_groups,
+                                          field_trial_ids);
 }
 
 void FieldTrialsProvider::ProvideSystemProfileMetrics(
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc
index c3b1169..7572037 100644
--- a/components/omnibox/browser/autocomplete_controller.cc
+++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -19,6 +19,7 @@
 #include "base/feature_list.h"
 #include "base/format_macros.h"
 #include "base/functional/bind.h"
+#include "base/functional/callback.h"
 #include "base/functional/callback_forward.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
@@ -1014,13 +1015,16 @@
         input_, template_url_service_,
         preserve_default_after_transfer ? preserve_default_match : nullptr);
   } else {
-    // The async ml scoring is only run once all the providers are done.
-    if (MaybeRunUrlScoringModel(last_default_match,
-                                last_default_associated_keyword,
-                                force_notify_default_match_changed)) {
-      // When the ML Scoring model is run, sorting and processing of the result
-      // happens once all matches are scored in
-      // `OnUrlScoringModelDoneForAllMatches()`, so we can skip it here.
+    // The async ML scoring is only run once all the providers are done. Use a
+    // WeakPtr since the model is not owned and `this` may no longer be alive.
+    scoring_model_weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
+    if (MaybeRunUrlScoringModel(base::BindOnce(
+            &AutocompleteController::AnnotateResultAndNotifyChanged,
+            scoring_model_weak_ptr_, last_default_match,
+            last_default_associated_keyword,
+            force_notify_default_match_changed))) {
+      // When the ML scoring model is run, processing the output and sorting
+      // and trimming of the matches happens in `OnUrlScoringModelDone()`.
       return;
     }
     // Sort the matches and trim them to a small number of "best" matches.
@@ -1032,8 +1036,8 @@
 }
 
 void AutocompleteController::AnnotateResultAndNotifyChanged(
-    absl::optional<AutocompleteMatch>& last_default_match,
-    std::u16string& last_default_associated_keyword,
+    const absl::optional<AutocompleteMatch>& last_default_match,
+    const std::u16string& last_default_associated_keyword,
     bool force_notify_default_match_changed) {
 #if DCHECK_IS_ON()
   result_.Validate();
@@ -1514,19 +1518,12 @@
 }
 
 void AutocompleteController::OnUrlScoringModelDone(
-    base::OnceCallback<void(std::pair<absl::optional<float>, size_t>)> callback,
-    size_t match_index,
-    absl::optional<float> model_output) {
-  std::move(callback).Run(std::make_pair(model_output, match_index));
-}
-
-void AutocompleteController::OnUrlScoringModelDoneForAllMatches(
     AutocompleteInput input,
-    absl::optional<AutocompleteMatch> last_default_match,
-    std::u16string last_default_associated_keyword,
-    bool force_notify_default_match_changed,
+    const base::ElapsedTimer elapsed_timer,
+    base::OnceClosure completion_callback,
     std::vector<std::pair<absl::optional<float>, size_t>>
         outputs_and_match_indices) {
+  TRACE_EVENT0("omnibox", "AutocompleteController::OnUrlScoringModelDone");
   // The goal is to redistribute the existing relevance scores among the URL
   // suggestions according to the ML model output values. Construct two max
   // heaps for the (legacy) relevance score and the output scores.
@@ -1551,32 +1548,48 @@
     output_and_match_index_heap.emplace(output.value(), index);
   }
 
-  while (!relevance_heap.empty()) {
-    // Assign the match with the highest respective model output with the
-    // highest relevance score.
-    auto match_index = output_and_match_index_heap.top().second;
-    auto* match = result_.match_at(match_index);
+  if (!relevance_heap.empty()) {
+    // Record whether the model was executed for at least one eligible match.
+    provider_client_->GetOmniboxTriggeredFeatureService()->FeatureTriggered(
+        metrics::OmniboxEventProto_Feature_ML_URL_SCORING);
 
-    match->RecordAdditionalInfo("legacy_relevance", match->relevance);
-    match->relevance = relevance_heap.top();
+    // Record how many eligible matches the model was executed for.
+    base::UmaHistogramCounts1000("Omnibox.URLScoringModelExecuted.Matches",
+                                 relevance_heap.size());
 
-    relevance_heap.pop();
-    output_and_match_index_heap.pop();
+    // Record how long it took to execute the model for all eligible matches.
+    base::UmaHistogramTimes("Omnibox.URLScoringModelExecuted.ElapsedTime",
+                            elapsed_timer.Elapsed());
   }
 
-  result_.SortAndCull(input, template_url_service_);
+  // Do not assign new relevance scores to the URL suggestions and do not rerank
+  // them in the counterfactual arm.
+  if (!OmniboxFieldTrial::IsMlUrlScoringCounterfactual()) {
+    while (!relevance_heap.empty()) {
+      // Assign the match with the highest respective model output with the
+      // highest relevance score.
+      auto match_index = output_and_match_index_heap.top().second;
+      auto* match = result_.match_at(match_index);
 
-  AnnotateResultAndNotifyChanged(last_default_match,
-                                 last_default_associated_keyword,
-                                 force_notify_default_match_changed);
+      match->RecordAdditionalInfo("legacy_relevance", match->relevance);
+      match->relevance = relevance_heap.top();
+
+      relevance_heap.pop();
+      output_and_match_index_heap.pop();
+    }
+
+    result_.SortAndCull(input, template_url_service_);
+  }
+
+  std::move(completion_callback).Run();
 }
 
 bool AutocompleteController::MaybeRunUrlScoringModel(
-    absl::optional<AutocompleteMatch>& last_default_match,
-    std::u16string& last_default_associated_keyword,
-    bool force_notify_default_match_changed) {
+    base::OnceClosure completion_callback) {
+  TRACE_EVENT0("omnibox", "AutocompleteController::MaybeRunUrlScoringModel");
+
 #if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
-  if (!OmniboxFieldTrial::IsMlRelevanceScoringEnabled()) {
+  if (!OmniboxFieldTrial::IsMlUrlScoringEnabled()) {
     return false;
   }
 
@@ -1586,17 +1599,12 @@
     return false;
   }
 
-  // Needed because the model is not owned and `this` may not longer be alive.
-  scoring_model_weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
-
   auto barrier_callback =
       base::BarrierCallback<std::pair<absl::optional<float>, size_t>>(
           result_.size(),
-          base::BindOnce(
-              &AutocompleteController::OnUrlScoringModelDoneForAllMatches,
-              scoring_model_weak_ptr_, input_, last_default_match,
-              last_default_associated_keyword,
-              force_notify_default_match_changed));
+          base::BindOnce(&AutocompleteController::OnUrlScoringModelDone,
+                         scoring_model_weak_ptr_, input_, base::ElapsedTimer(),
+                         std::move(completion_callback)));
 
   for (size_t match_index = 0; match_index < result_.matches_.size();
        match_index++) {
@@ -1606,16 +1614,13 @@
     // any other match type.
     if (AutocompleteMatch::GetDefaultGroupId(match->type) !=
         omnibox::GROUP_OTHER_NAVS) {
-      OnUrlScoringModelDone(barrier_callback,
-                            /*match_index=*/match_index,
-                            /*model_output=*/absl::nullopt);
+      barrier_callback.Run(std::make_pair(absl::nullopt, match_index));
       continue;
     }
 
     scoring_model_service->ScoreAutocompleteUrlMatch(
-        &scoring_model_task_tracker_, match->scoring_signals,
-        base::BindOnce(&AutocompleteController::OnUrlScoringModelDone,
-                       scoring_model_weak_ptr_, barrier_callback, match_index));
+        &scoring_model_task_tracker_, match->scoring_signals, match_index,
+        barrier_callback);
   }
 
   return true;
diff --git a/components/omnibox/browser/autocomplete_controller.h b/components/omnibox/browser/autocomplete_controller.h
index eeb6e6f..acc7140 100644
--- a/components/omnibox/browser/autocomplete_controller.h
+++ b/components/omnibox/browser/autocomplete_controller.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
+#include "base/functional/callback_forward.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
@@ -17,6 +18,7 @@
 #include "base/observer_list_types.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/time/time.h"
+#include "base/timer/elapsed_timer.h"
 #include "base/timer/timer.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "build/build_config.h"
@@ -300,8 +302,8 @@
   // info, etc.) and fires notifications that the result and potentially the
   // default match has changed.
   void AnnotateResultAndNotifyChanged(
-      absl::optional<AutocompleteMatch>& last_default_match,
-      std::u16string& last_default_associated_keyword,
+      const absl::optional<AutocompleteMatch>& last_default_match,
+      const std::u16string& last_default_associated_keyword,
       bool force_notify_default_match_changed);
 
   // Updates ML scoring signals of suggestions in the autocomplete result.
@@ -360,37 +362,24 @@
   // only runs on Lacros and the @tabs scope.
   bool ShouldRunProvider(AutocompleteProvider* provider) const;
 
-  // Called each time the model returns for a match. Passes the output from the
-  // model and the index of the associated match to the final
-  // `OnUrlScoringModelDoneForAllMatches()` callback.
-  void OnUrlScoringModelDone(
-      base::OnceCallback<void(std::pair<absl::optional<float>, size_t>)>
-          callback,
-      size_t match_index,
-      absl::optional<float> model_output);
-
-  // Called when the model finishes running for ALL matches in
+  // Called when the model is done running for all the eligible matches in
   // `results_.matches_`. Redistributes the existing relevance scores to the
   // matches based on the model output (i.e. highest relevance now belongs to
-  // the match with the highest output value, and vice versa), re-sorts the
-  // matches, and notifies listeners.
-  void OnUrlScoringModelDoneForAllMatches(
+  // the match with the highest output value, and vice versa), re-sorts and
+  // trims the matches, and calls `completion_callback`.
+  void OnUrlScoringModelDone(
       AutocompleteInput input,
-      absl::optional<AutocompleteMatch> last_default_match,
-      std::u16string last_default_associated_keyword,
-      bool force_notify_default_match_changed,
+      const base::ElapsedTimer elapsed_timer,
+      base::OnceClosure completion_callback,
       std::vector<std::pair<absl::optional<float>, size_t>>
           outputs_and_match_indices);
 
-  // If ML Relevance Scoring is enabled, runs the model for all the supported
-  // `matches_` in `results_` and returns true. `OnUrlScoringModelOutput()`
-  // callback is expected to be called for every match and
-  // `OnUrlScoringModelDoneForAllMatches()` callback is expected to be called
-  // once the scoring is done for ALL matches, whether successfully or not.
-  bool MaybeRunUrlScoringModel(
-      absl::optional<AutocompleteMatch>& last_default_match,
-      std::u16string& last_default_associated_keyword,
-      bool force_notify_default_match_changed);
+  // If ML Relevance Scoring is not enabled returns false. Otherwise runs the
+  // model asynchronously for all the eligible matches in `results_.matches_`
+  // and returns true. Passes `completion_callback` to `OnUrlScoringModelDone()`
+  // callback which is called once the scoring is done for all the eligible
+  // matches, whether successfully or not.
+  bool MaybeRunUrlScoringModel(base::OnceClosure completion_callback);
 
   base::ObserverList<Observer> observers_;
 
diff --git a/components/omnibox/browser/autocomplete_scoring_model_service.cc b/components/omnibox/browser/autocomplete_scoring_model_service.cc
index ece9a1e..b8533cf6 100644
--- a/components/omnibox/browser/autocomplete_scoring_model_service.cc
+++ b/components/omnibox/browser/autocomplete_scoring_model_service.cc
@@ -38,23 +38,28 @@
     base::CancelableTaskTracker* tracker,
     const metrics::OmniboxEventProto::Suggestion::ScoringSignals&
         scoring_signals,
+    size_t match_index,
     ResultCallback result_callback) {
+  TRACE_EVENT0("omnibox",
+               "AutocompleteScoringModelService::ScoreAutocompleteUrlMatch");
+
   if (!UrlScoringModelAvailable()) {
-    std::move(result_callback).Run(absl::nullopt);
+    std::move(result_callback).Run(std::make_pair(absl::nullopt, match_index));
     return;
   }
 
   absl::optional<std::vector<float>> input_signals =
       url_scoring_model_handler_->GetModelInput(scoring_signals);
   if (!input_signals) {
-    std::move(result_callback).Run(absl::nullopt);
+    std::move(result_callback).Run(std::make_pair(absl::nullopt, match_index));
     return;
   }
 
   url_scoring_model_handler_->ExecuteModelWithInput(
       tracker,
       base::BindOnce(&AutocompleteScoringModelService::ProcessModelOutput,
-                     base::Unretained(this), std::move(result_callback)),
+                     base::Unretained(this), std::move(result_callback),
+                     match_index),
       *input_signals);
 }
 
@@ -65,14 +70,18 @@
 
 void AutocompleteScoringModelService::ProcessModelOutput(
     ResultCallback result_callback,
+    size_t match_index,
     const absl::optional<AutocompleteScoringModelExecutor::ModelOutput>&
         model_output) {
+  TRACE_EVENT0("omnibox",
+               "AutocompleteScoringModelService::ProcessModelOutput");
   if (model_output.has_value()) {
     if (!model_output.value().empty()) {
-      std::move(result_callback).Run(model_output.value()[0]);
+      std::move(result_callback)
+          .Run(std::make_pair(model_output.value()[0], match_index));
       return;
     }
     NOTREACHED() << "The model generated an empty output vector.";
   }
-  std::move(result_callback).Run(absl::nullopt);
+  std::move(result_callback).Run(std::make_pair(absl::nullopt, match_index));
 }
diff --git a/components/omnibox/browser/autocomplete_scoring_model_service.h b/components/omnibox/browser/autocomplete_scoring_model_service.h
index 8ea722a..ad50eff 100644
--- a/components/omnibox/browser/autocomplete_scoring_model_service.h
+++ b/components/omnibox/browser/autocomplete_scoring_model_service.h
@@ -22,7 +22,8 @@
 // OptimizationGuide's model handler.
 class AutocompleteScoringModelService : public KeyedService {
  public:
-  using ResultCallback = base::OnceCallback<void(absl::optional<float>)>;
+  using ResultCallback =
+      base::OnceCallback<void(std::pair<absl::optional<float>, size_t>)>;
 
   explicit AutocompleteScoringModelService(
       optimization_guide::OptimizationGuideModelProvider* model_provider);
@@ -40,6 +41,7 @@
       base::CancelableTaskTracker* tracker,
       const metrics::OmniboxEventProto::Suggestion::ScoringSignals&
           scoring_signals,
+      size_t match_index,
       ResultCallback result_callback);
 
   // Returns whether the scoring model is loaded and the pointer to the
@@ -52,6 +54,7 @@
   // output is nullopt or an empty vector (which is unexpected).
   void ProcessModelOutput(
       ResultCallback result_callback,
+      size_t match_index,
       const absl::optional<AutocompleteScoringModelExecutor::ModelOutput>&
           model_output);
 
diff --git a/components/omnibox/browser/bookmark_provider.cc b/components/omnibox/browser/bookmark_provider.cc
index 076db5a..efb17f8 100644
--- a/components/omnibox/browser/bookmark_provider.cc
+++ b/components/omnibox/browser/bookmark_provider.cc
@@ -135,7 +135,7 @@
                     matches_.end(), AutocompleteMatch::MoreRelevant);
   ResizeMatches(
       num_matches,
-      OmniboxFieldTrial::IsMlRelevanceScoringIncreaseNumCandidatesEnabled());
+      OmniboxFieldTrial::IsMlUrlScoringIncreaseNumCandidatesEnabled());
 }
 
 std::vector<TitledUrlMatch> BookmarkProvider::GetMatchesWithBookmarkPaths(
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index bac138c..96e6166 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -1088,20 +1088,36 @@
 
 // ---------------------------------------------------------
 // ML Relevance Scoring ->
-const base::FeatureParam<bool> kMlRelevanceScoringIncreaseNumCandidates(
-    &omnibox::kMlRelevanceScoring,
-    "MlRelevanceScoringIncreaseNumCandidates",
+
+// If true, enables scoring signal annotators for logging Omnibox scoring
+// signals to OmniboxEventProto.
+const base::FeatureParam<bool> kEnableScoringSignalsAnnotators(
+    &omnibox::kLogUrlScoringSignals,
+    "enable_scoring_signals_annotators",
+    false);
+
+// If true, runs the ML scoring model but does not assign new relevance scores
+// to the URL suggestions and does not rerank them.
+const base::FeatureParam<bool> kMlUrlScoringCounterfactual(
+    &omnibox::kMlUrlScoring,
+    "MlUrlScoringCounterfactual",
+    false);
+
+// If true, increases the number of candidates the URL autocomplete providers
+// pass to the controller beyond `provider_max_matches`.
+const base::FeatureParam<bool> kMlUrlScoringIncreaseNumCandidates(
+    &omnibox::kMlUrlScoring,
+    "MlUrlScoringIncreaseNumCandidates",
     false);
 
 MLConfig::MLConfig() {
   log_url_scoring_signals =
       base::FeatureList::IsEnabled(omnibox::kLogUrlScoringSignals);
-  enable_scoring_signals_annotators = base::GetFieldTrialParamByFeatureAsBool(
-      omnibox::kLogUrlScoringSignals, "enable_scoring_signals_annotators",
-      /*default_value=*/false);
-  ml_relevance_scoring =
-      base::FeatureList::IsEnabled(omnibox::kMlRelevanceScoring);
-  increase_num_candidates = kMlRelevanceScoringIncreaseNumCandidates.Get();
+  enable_scoring_signals_annotators = kEnableScoringSignalsAnnotators.Get();
+  ml_url_scoring = base::FeatureList::IsEnabled(omnibox::kMlUrlScoring);
+  ml_url_scoring_counterfactual = kMlUrlScoringCounterfactual.Get();
+  ml_url_scoring_increase_num_candidates =
+      kMlUrlScoringIncreaseNumCandidates.Get();
   url_scoring_model = base::FeatureList::IsEnabled(omnibox::kUrlScoringModel);
 }
 
@@ -1123,19 +1139,19 @@
 bool IsLogUrlScoringSignalsEnabled() {
   return GetMLConfig().log_url_scoring_signals;
 }
-
 bool AreScoringSignalsAnnotatorsEnabled() {
   return GetMLConfig().enable_scoring_signals_annotators;
 }
-
-bool IsMlRelevanceScoringEnabled() {
-  return GetMLConfig().ml_relevance_scoring && IsUrlScoringModelEnabled();
+bool IsMlUrlScoringEnabled() {
+  return IsUrlScoringModelEnabled() && GetMLConfig().ml_url_scoring;
 }
-
-bool IsMlRelevanceScoringIncreaseNumCandidatesEnabled() {
-  return GetMLConfig().increase_num_candidates;
+bool IsMlUrlScoringCounterfactual() {
+  return IsMlUrlScoringEnabled() && GetMLConfig().ml_url_scoring_counterfactual;
 }
-
+bool IsMlUrlScoringIncreaseNumCandidatesEnabled() {
+  return IsMlUrlScoringEnabled() &&
+         GetMLConfig().ml_url_scoring_increase_num_candidates;
+}
 bool IsUrlScoringModelEnabled() {
   return GetMLConfig().url_scoring_model;
 }
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h
index 3257b6c8..2b0ecfea 100644
--- a/components/omnibox/browser/omnibox_field_trial.h
+++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -629,11 +629,6 @@
 // ---------------------------------------------------------
 // ML Relevance Scoring ->
 
-// Whether the URL providers should pass more suggestion candidates to the
-// controller. If enabled, providers are no longer limited to
-// provider_max_matches.
-extern const base::FeatureParam<bool> kMlRelevanceScoringIncreaseNumCandidates;
-
 // The ML Relevance Scoring features and params configuration.
 // Use `GetMLConfig()` to get the current configuration.
 //
@@ -643,24 +638,29 @@
 struct MLConfig {
   MLConfig();
 
-  // If true, logs Omnibox URL scoring signals to OmniboxEventProto in UMA.
+  // If true, logs Omnibox URL scoring signals to OmniboxEventProto.
   // Equivalent to omnibox::kLogUrlScoringSignals.
   bool log_url_scoring_signals{false};
 
-  // If true, enables scoring signal annotators.
-  // Requires omnibox::kLogUrlScoringSignals to be enabled.
+  // If true, enables scoring signal annotators for logging Omnibox URL scoring
+  // signals to OmniboxEventProto. Equivalent to
+  // OmniboxFieldTrial::kLogUrlScoringSignalsEnableScoringSignalsAnnotators.
   bool enable_scoring_signals_annotators{false};
 
-  // If true, runs the ML scoring model to assign relevance scores to URL
-  // suggestions. Also enables the autocomplete system related changes to
-  // support ML scoring and moves scoring out of the autocomplete providers into
-  // the autocomplete controller.
-  // Equivalent to omnibox::kMlRelevanceScoring.
-  bool ml_relevance_scoring{false};
+  // If true, runs the ML scoring model to assign new relevance scores to the
+  // URL suggestions and reranks them.
+  // Equivalent to omnibox::kMlUrlScoring.
+  bool ml_url_scoring{false};
 
-  // If true, increases the number of candidates the url autocomplete providers
-  // pass to the controller.
-  bool increase_num_candidates{false};
+  // If true, runs the ML scoring model but does not assign new relevance scores
+  // to the URL suggestions and does not rerank them.
+  // Equivalent to OmniboxFieldTrial::kMlUrlScoringCounterfactual.
+  bool ml_url_scoring_counterfactual{false};
+
+  // If true, increases the number of candidates the URL autocomplete providers
+  // pass to the controller beyond `provider_max_matches`.
+  // Equivalent to OmniboxFieldTrial::kMlUrlScoringIncreaseNumCandidates.
+  bool ml_url_scoring_increase_num_candidates{false};
 
   // If true, creates Omnibox autocompete URL scoring model.
   // Equivalent to omnibox::kUrlScoringModel.
@@ -687,21 +687,25 @@
 // Returns the current configuration.
 const MLConfig& GetMLConfig();
 
-// For logging Omnibox scoring signals for training machine learning models.
+// If enabled, logs Omnibox scoring signals to OmniboxEventProto for training
+// the ML scoring models.
 bool IsLogUrlScoringSignalsEnabled();
 
-// Returns whether the scoring signal annotators are enabled.
+// Whether the scoring signal annotators are enabled for logging Omnibox scoring
+// signals to OmniboxEventProto.
 bool AreScoringSignalsAnnotatorsEnabled();
 
-// If enabled, runs the machine learning scoring model and uses the ML-based
-// relevance scores. This flag enables the omnibox autocomplete system related
-// changes to support ML scoring and moves the responsibility for scoring and
-// trimming results from the providers into the autocomplete controller.
-bool IsMlRelevanceScoringEnabled();
+// If enabled, runs the ML scoring model to assign new relevance scores to the
+// URL suggestions and reranks them.
+bool IsMlUrlScoringEnabled();
+
+// If true, runs the ML scoring model but does not assign new relevance scores
+// to URL suggestions.
+bool IsMlUrlScoringCounterfactual();
 
 // If true, increases the number of candidates the url autocomplete providers
 // pass to the controller.
-bool IsMlRelevanceScoringIncreaseNumCandidatesEnabled();
+bool IsMlUrlScoringIncreaseNumCandidatesEnabled();
 
 // Whether the URL scoring model is enabled.
 bool IsUrlScoringModelEnabled();
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index 4046ac0..bab3052 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -357,6 +357,12 @@
              "ClipboardSuggestionContentHidden",
              enabled_by_default_android_only);
 
+// If enabled, uses Chrome Refresh 2023 Action Chips in the omnibox suggestion
+// popup.
+BASE_FEATURE(kCr2023ActionChips,
+             "Cr2023ActionChips",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // If enabled, finance ticker answer from omnibox will reverse the color for
 // stock ticker. only colors being swapped are those that represent "growth" and
 // "loss" to represent colors red and green in a way that is appropriate for a
@@ -684,18 +690,15 @@
              "OmniboxReportSearchboxStats",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// If enabled, logs Omnibox URL scoring signals to OmniboxEventProto in UMA.
+// If enabled, logs Omnibox URL scoring signals to OmniboxEventProto for
+// training the ML scoring models.
 BASE_FEATURE(kLogUrlScoringSignals,
              "LogUrlScoringSignals",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// If enabled, runs the ML scoring model to assign relevance scores to URL
-// suggestions. This enables the autocomplete system related changes to support
-// ML scoring and moves scoring out of the autocomplete providers into
-// autocomplete controller.
-BASE_FEATURE(kMlRelevanceScoring,
-             "MlRelevanceScoring",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+// If enabled, runs the ML scoring model to assign new relevance scores to the
+// URL suggestions and reranks them.
+BASE_FEATURE(kMlUrlScoring, "MlUrlScoring", base::FEATURE_DISABLED_BY_DEFAULT);
 
 // If enabled, creates Omnibox autocompete URL scoring model.
 BASE_FEATURE(kUrlScoringModel,
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h
index f646e5f..0d599a93 100644
--- a/components/omnibox/common/omnibox_features.h
+++ b/components/omnibox/common/omnibox_features.h
@@ -88,6 +88,7 @@
 // Suggestions UI - these affect the UI or function of the suggestions popup.
 BASE_DECLARE_FEATURE(kAdaptiveSuggestionsCount);
 BASE_DECLARE_FEATURE(kClipboardSuggestionContentHidden);
+BASE_DECLARE_FEATURE(kCr2023ActionChips);
 BASE_DECLARE_FEATURE(kSuggestionAnswersColorReverse);
 BASE_DECLARE_FEATURE(kMostVisitedTiles);
 BASE_DECLARE_FEATURE(kRichAutocompletion);
@@ -154,7 +155,7 @@
 
 // Omnibox ML scoring.
 BASE_DECLARE_FEATURE(kLogUrlScoringSignals);
-BASE_DECLARE_FEATURE(kMlRelevanceScoring);
+BASE_DECLARE_FEATURE(kMlUrlScoring);
 BASE_DECLARE_FEATURE(kUrlScoringModel);
 
 // Inspire Me - additional suggestions based on user's location and interests.
diff --git a/components/omnibox/resources/translations/omnibox_pedal_synonyms_pt-PT.xtb b/components/omnibox/resources/translations/omnibox_pedal_synonyms_pt-PT.xtb
index 543bda3..d2a9c16 100644
--- a/components/omnibox/resources/translations/omnibox_pedal_synonyms_pt-PT.xtb
+++ b/components/omnibox/resources/translations/omnibox_pedal_synonyms_pt-PT.xtb
@@ -3,7 +3,7 @@
 <translationbundle lang="pt-PT">
 <translation id="101606685846791463">limpar cache do navegador, limpar histórico, eliminar cookies, apagar histórico de navegação, apagar histórico do navegador, limpar histórico do navegador</translation>
 <translation id="132297926492792130">controlar a minha conta google, corrigir conta google, gerir conta google, gerir a minha conta google</translation>
-<translation id="1455865776268085776">entrar no modo de navegação anónima, nova janela de navegação anónima, abrir separador de navegação anónima</translation>
+<translation id="1455865776268085776">entrar no modo de navegação anónima, nova janela de navegação anónima, abrir separador anónimo</translation>
 <translation id="1545931455576308147">partilhar esta página, partilhar este separador</translation>
 <translation id="1912698329644085067">alterar definições do chrome, gerir definições</translation>
 <translation id="1938436187879863297">criar nota do google keep, criar nota do google, criar nova nota do google keep, nova nota do google, iniciar nota do google, notas google, criar notas google</translation>
@@ -16,13 +16,13 @@
 <translation id="3489247412199563299">personalizar acessibilidade do chrome, gerir definições de acessibilidade</translation>
 <translation id="3936847108123063274">criar site google, criar website google, novo site google, abrir site novo site google</translation>
 <translation id="4165988127016746956">criar formulário do google forms, criar formulário do forms, criar novo formulário do google forms, novo formulário do google forms, iniciar inquérito google, criar inquérito google</translation>
-<translation id="4341944745395709813">abrir sempre links no chrome, usar sempre o chrome, utilizar sempre o chrome, chrome como predefinição, navegador predefinido, como tornar o chrome o navegador predefinido, navegador principal, tornar o chrome a predefinição, tornar o chrome o navegador predefinido, tornar o chrome o meu navegador predefinido, abrir links no chrome, escolher o chrome como navegador predefinido, pesquisar no chrome, fazer do chrome a predefinição, fazer do chrome o navegador predefinido, navegador padrão</translation>
+<translation id="4341944745395709813">abrir sempre links no chrome, usar sempre o chrome, utilizar sempre o chrome, chrome como predefinição, navegador predefinido, como tornar o chrome o navegador predefinido, navegador principal, tornar o chrome a predefinição, tornar o chrome o navegador predefinido, tornar o chrome o meu navegador predefinido, abrir links no chrome, escolher o chrome como navegador predefinido, pesquisar no chrome, fazer do chrome a predefinição, definir o Chrome como o navegador predefinido, navegador padrão</translation>
 <translation id="4367205929005172598">localizar telemóvel perdido, localizar o meu dispositivo</translation>
 <translation id="4692900934258103694">no interior, dentro, por, como, o, um, fazer, no, meu, sobre, para, uma, eu</translation>
 <translation id="4834023075966161189">criar documento do google docs, criar novo documento do google docs, abrir documento do google, criar google docs, criar documentos no google docs</translation>
 <translation id="4922709528022057939">chrome dino, jogo dino, jogar dino run</translation>
 <translation id="5061612070235737664">alterar tipo de letra do navegador, tipos de letra do chrome</translation>
-<translation id="6413237123574479071">gerir métodos de pagamento, alterar métodos de pagamento, atualizar cartão de crédito, editar cartão de crédito</translation>
+<translation id="6413237123574479071">gerir métodos de pagamento, alterar métodos de pagamento, atualizar cartão de crédito</translation>
 <translation id="6654270263159958770">adicionar pesquisa personalizada, gerir motores de pesquisa, motores de pesquisa</translation>
 <translation id="7081494400361697539">criar folha de cálculo do google sheets, criar folha de cálculo do workspace, nova folha de cálculo do google sheets, iniciar nova folha de cálculo do google sheets, criar google sheets, folha de cálculo do sheets</translation>
 <translation id="7153639895359139570">adicionar morada, alterar morada de envio, editar moradas, editar morada, gerir moradas, gerir morada</translation>
diff --git a/components/omnibox/resources/translations/omnibox_pedal_synonyms_sv.xtb b/components/omnibox/resources/translations/omnibox_pedal_synonyms_sv.xtb
index e21f249..5490e9fb 100644
--- a/components/omnibox/resources/translations/omnibox_pedal_synonyms_sv.xtb
+++ b/components/omnibox/resources/translations/omnibox_pedal_synonyms_sv.xtb
@@ -22,19 +22,19 @@
 <translation id="4834023075966161189">skapa google-dokument, skapa ett nytt google-dokument, öppna google-dokument</translation>
 <translation id="4922709528022057939">chrome dino, dinospelet, spela dino run, spela chrome dino</translation>
 <translation id="5061612070235737664">ändra webbläsarens teckensnitt, teckensnitt i chrome, ändra teckensnitt</translation>
-<translation id="6413237123574479071">hantera betalningsmetoder, uppdatera kreditkort</translation>
+<translation id="6413237123574479071">hantera betalningsmetoder, uppdatera kreditkort, uppdatera kortuppgifter</translation>
 <translation id="6654270263159958770">lägg till anpassad sökning, hantera sökmotorer, sökmotorer</translation>
 <translation id="7081494400361697539">skapa google-kalkylark, skapa kalkylark i workspace, nytt google-kalkylark, öppna ett nytt google-kalkylark</translation>
 <translation id="7153639895359139570">lägg till adress, ändra leveransadress, redigera adresser, hantera adresser</translation>
 <translation id="7242693601647412075">hantera säkerhetsinställningar</translation>
-<translation id="7441773108452086364">ändra gmail-lösenord, ändra gmail-lösenord, byta lösenord för google, byta lösenord för gmail, ändra lösenord för gmail-kontot</translation>
+<translation id="7441773108452086364">ändra gmail-lösenord, ändra mitt gmail-lösenord, byta lösenord för google, byta lösenord för gmail, återställa gmail-lösenordet</translation>
 <translation id="7660956169713698963">anpassa tillgänglighet i chromeos, hantera tillgänglighetsinställningar, ändra tillgänglighetsinställningar</translation>
 <translation id="7700496593710078083">se historik i chrome, visa webbhistorik, se webbhistorik</translation>
 <translation id="7739523284295786564">hantera nedladdningar i chrome, visa nedladdningar, se nedladdningar</translation>
 <translation id="7873993277886791795">skapa google-presentation, skapa en ny presentation, ny google-presentation, öppna google presentationer</translation>
 <translation id="7992725801741093524">ändra googles integritetsinställningar, hantera integritet på google, ändra integritetsinställningar</translation>
 <translation id="8189600756055704659">ändra synkroniseringsinställningar i webbläsaren chrome, ändra chrome sync, redigera synkronisering, redigera synkroniseringsinställningar, hantera synkronisering</translation>
-<translation id="8307473667919507216">gör chromes säkerhetskontroll, gör säkerhetskontrollen</translation>
+<translation id="8307473667919507216">säkerhetskontroll, kör säkerhetskontroll, gör chromes säkerhetskontroll, gör säkerhetskontrollen</translation>
 <translation id="8319253638505741466">stäng inkognitofönster, avsluta inkognito, stäng inkognito</translation>
 <translation id="8350110529112037703">hantera lösenord för chrome, visa lösenord i chrome</translation>
 <translation id="9015559449837241926">chrome-funktioner, ta reda på mer om funktioner i google chrome, nya funktioner i google chrome, få tips för chrome</translation>
diff --git a/components/page_info_strings.grdp b/components/page_info_strings.grdp
index b993030..dcb1d13 100644
--- a/components/page_info_strings.grdp
+++ b/components/page_info_strings.grdp
@@ -505,7 +505,7 @@
 
     <!-- Permission change infobar. -->
     <if expr="not is_android">
-      <message name="IDS_PAGE_INFO_INFOBAR_TEXT" desc="The string shown in the infobar after the user has changed site permissions settings, reminding them to reload the page in order for the new settings to take effect.">
+      <message name="IDS_PAGE_INFO_INFOBAR_TEXT" desc="The string shown in the infobar after the user has changed site permissions settings, reminding them to reload the page in order for the new settings to take effect.  Deliberately similar to IDS_EXTENSION_SITE_RELOAD_PAGE_BUBBLE_HEADING, but used for an different permission setting so they are not combined. If updating the one, please update the other or consult the extensions and privacy teams.">
         To apply your updated settings to this site, reload this page
       </message>
       <message name="IDS_PAGE_INFO_INFOBAR_BUTTON" desc="The string used in the infobar button allowing the user to reload the page directly from the infobar.">
diff --git a/components/paint_preview/DEPS b/components/paint_preview/DEPS
index 28f2c7a..e8e0fba 100644
--- a/components/paint_preview/DEPS
+++ b/components/paint_preview/DEPS
@@ -4,5 +4,6 @@
   "+mojo/public/cpp",
   "+third_party/harfbuzz-ng/src/src",
   "+third_party/skia/include/core",
+  "+third_party/skia/include/encode",
   "+ui/gfx/geometry",
 ]
diff --git a/components/paint_preview/common/serial_utils.cc b/components/paint_preview/common/serial_utils.cc
index 1e24e084..f477918 100644
--- a/components/paint_preview/common/serial_utils.cc
+++ b/components/paint_preview/common/serial_utils.cc
@@ -15,6 +15,7 @@
 #include "third_party/skia/include/core/SkMatrix.h"
 #include "third_party/skia/include/core/SkPictureRecorder.h"
 #include "third_party/skia/include/core/SkString.h"
+#include "third_party/skia/include/encode/SkPngEncoder.h"
 
 namespace paint_preview {
 
@@ -123,7 +124,7 @@
     // Use the default PNG at quality 100 as it is safe.
     // TODO(crbug/1198304): Investigate supporting JPEG at quality 100 for
     // opaque images.
-    encoded_data = image->encodeToData();
+    encoded_data = SkPngEncoder::Encode(nullptr, image, {});
   }
 
   if (!encoded_data)
diff --git a/components/paint_preview/renderer/paint_preview_recorder_utils_unittest.cc b/components/paint_preview/renderer/paint_preview_recorder_utils_unittest.cc
index 4e08de9..7f2efdc4 100644
--- a/components/paint_preview/renderer/paint_preview_recorder_utils_unittest.cc
+++ b/components/paint_preview/renderer/paint_preview_recorder_utils_unittest.cc
@@ -46,6 +46,7 @@
 #include "third_party/skia/include/core/SkSamplingOptions.h"
 #include "third_party/skia/include/core/SkTextBlob.h"
 #include "third_party/skia/include/core/SkTypeface.h"
+#include "third_party/skia/include/encode/SkPngEncoder.h"
 
 namespace paint_preview {
 
@@ -406,7 +407,7 @@
     SkCanvas sk_canvas(bitmap);
     sk_canvas.drawColor(SkColors::kRed);
     auto sk_image = SkImages::RasterFromBitmap(bitmap);
-    auto data = sk_image->encodeToData();
+    auto data = SkPngEncoder::Encode(nullptr, sk_image.get(), {});
     auto lazy_sk_image = SkImages::DeferredFromEncodedData(data);
     ASSERT_TRUE(lazy_sk_image->isLazyGenerated());
     cc::PaintImage paint_image =
diff --git a/components/performance_manager/BUILD.gn b/components/performance_manager/BUILD.gn
index 1b669ef..59799cb 100644
--- a/components/performance_manager/BUILD.gn
+++ b/components/performance_manager/BUILD.gn
@@ -307,6 +307,7 @@
     "performance_manager_unittest.cc",
     "registered_objects_unittest.cc",
     "render_process_host_id_unittest.cc",
+    "user_tuning/prefs_unittest.cc",
     "v8_memory/v8_context_tracker_helpers_unittest.cc",
     "v8_memory/v8_context_tracker_internal_unittest.cc",
     "v8_memory/v8_context_tracker_unittest.cc",
diff --git a/components/performance_manager/public/user_tuning/prefs.h b/components/performance_manager/public/user_tuning/prefs.h
index 71deff4..de95971 100644
--- a/components/performance_manager/public/user_tuning/prefs.h
+++ b/components/performance_manager/public/user_tuning/prefs.h
@@ -14,8 +14,17 @@
 
 namespace performance_manager::user_tuning::prefs {
 
+// DEPRECATED: being replaced by kHighEfficiencyModeState
 extern const char kHighEfficiencyModeEnabled[];
 
+enum class HighEfficiencyModeState {
+  kDisabled = 0,
+  kEnabled = 1,
+  kEnabledOnTimer = 2,
+};
+
+extern const char kHighEfficiencyModeState[];
+
 enum class BatterySaverModeState {
   kDisabled = 0,
   kEnabledBelowThreshold = 1,
@@ -41,9 +50,17 @@
 
 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
+HighEfficiencyModeState GetCurrentHighEfficiencyModeState(
+    PrefService* pref_service);
+
 BatterySaverModeState GetCurrentBatterySaverModeState(
     PrefService* pref_service);
 
+// This function migrates the old, boolean High Efficiency (Memory Saver)
+// preference to the new, integer one that represents a value of the
+// `HighEfficiencyModeState` enum. This is done once at startup.
+void MigrateHighEfficiencyModePref(PrefService* pref_service);
+
 }  // namespace performance_manager::user_tuning::prefs
 
 #endif  // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_USER_TUNING_PREFS_H_
diff --git a/components/performance_manager/user_tuning/prefs.cc b/components/performance_manager/user_tuning/prefs.cc
index 5d0df25..1ced436 100644
--- a/components/performance_manager/user_tuning/prefs.cc
+++ b/components/performance_manager/user_tuning/prefs.cc
@@ -4,6 +4,7 @@
 
 #include "components/performance_manager/public/user_tuning/prefs.h"
 
+#include "components/performance_manager/public/features.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
@@ -13,6 +14,9 @@
 const char kHighEfficiencyModeEnabled[] =
     "performance_tuning.high_efficiency_mode.enabled";
 
+const char kHighEfficiencyModeState[] =
+    "performance_tuning.high_efficiency_mode.state";
+
 const char kBatterySaverModeState[] =
     "performance_tuning.battery_saver_mode.state";
 
@@ -28,6 +32,9 @@
 void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
   registry->RegisterBooleanPref(kHighEfficiencyModeEnabled, false);
   registry->RegisterIntegerPref(
+      kHighEfficiencyModeState,
+      static_cast<int>(HighEfficiencyModeState::kDisabled));
+  registry->RegisterIntegerPref(
       kBatterySaverModeState,
       static_cast<int>(BatterySaverModeState::kEnabledBelowThreshold));
   registry->RegisterTimePref(kLastBatteryUseTimestamp, base::Time());
@@ -39,6 +46,19 @@
   registry->RegisterListPref(kManagedTabDiscardingExceptions);
 }
 
+HighEfficiencyModeState GetCurrentHighEfficiencyModeState(
+    PrefService* pref_service) {
+  int state = pref_service->GetInteger(kHighEfficiencyModeState);
+  if (state < static_cast<int>(HighEfficiencyModeState::kDisabled) ||
+      state > static_cast<int>(HighEfficiencyModeState::kEnabledOnTimer)) {
+    int disabled_state = static_cast<int>(HighEfficiencyModeState::kDisabled);
+    pref_service->SetInteger(kHighEfficiencyModeState, disabled_state);
+    state = disabled_state;
+  }
+
+  return static_cast<HighEfficiencyModeState>(state);
+}
+
 BatterySaverModeState GetCurrentBatterySaverModeState(
     PrefService* pref_service) {
   int state = pref_service->GetInteger(kBatterySaverModeState);
@@ -52,4 +72,31 @@
   return static_cast<BatterySaverModeState>(state);
 }
 
+void MigrateHighEfficiencyModePref(PrefService* pref_service) {
+  const PrefService::Preference* state_pref =
+      pref_service->FindPreference(kHighEfficiencyModeState);
+  if (!state_pref->IsDefaultValue()) {
+    // The user has changed the new pref, no migration needed. Clear the old
+    // pref because it won't be used anymore.
+    pref_service->ClearPref(kHighEfficiencyModeEnabled);
+    return;
+  }
+
+  const PrefService::Preference* bool_pref =
+      pref_service->FindPreference(kHighEfficiencyModeEnabled);
+
+  bool enabled = bool_pref->GetValue()->GetBool();
+  int equivalent_int_pref =
+      enabled ? static_cast<int>(HighEfficiencyModeState::kEnabledOnTimer)
+              : static_cast<int>(HighEfficiencyModeState::kDisabled);
+  if (!bool_pref->IsDefaultValue()) {
+    // The user has changed the old pref, but the new pref is still set to the
+    // default value. This means the old pref's state needs to be migrated into
+    // the new pref.
+    pref_service->SetInteger(kHighEfficiencyModeState, equivalent_int_pref);
+    // Clear the old pref because it won't be used anymore.
+    pref_service->ClearPref(kHighEfficiencyModeEnabled);
+  }
+}
+
 }  // namespace performance_manager::user_tuning::prefs
diff --git a/components/performance_manager/user_tuning/prefs_unittest.cc b/components/performance_manager/user_tuning/prefs_unittest.cc
new file mode 100644
index 0000000..ad7898e
--- /dev/null
+++ b/components/performance_manager/user_tuning/prefs_unittest.cc
@@ -0,0 +1,80 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/performance_manager/public/user_tuning/prefs.h"
+
+#include "components/performance_manager/public/features.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace performance_manager::user_tuning::prefs {
+
+class HighEfficiencyModePrefMigrationTest : public ::testing::Test {
+ public:
+  void SetUp() override { RegisterLocalStatePrefs(pref_service_.registry()); }
+
+  TestingPrefServiceSimple pref_service_;
+};
+
+TEST_F(HighEfficiencyModePrefMigrationTest, NoChangeToUserSetNewPref) {
+  // The old pref is set by the user, but so is the new pref so no migration
+  // should happen.
+  pref_service_.SetBoolean(kHighEfficiencyModeEnabled, true);
+  pref_service_.SetInteger(
+      kHighEfficiencyModeState,
+      static_cast<int>(HighEfficiencyModeState::kDisabled));
+
+  MigrateHighEfficiencyModePref(&pref_service_);
+
+  EXPECT_EQ(pref_service_.GetInteger(kHighEfficiencyModeState),
+            static_cast<int>(HighEfficiencyModeState::kDisabled));
+  // The old pref should be reset.
+  EXPECT_TRUE(pref_service_.FindPreference(kHighEfficiencyModeEnabled)
+                  ->IsDefaultValue());
+  EXPECT_FALSE(pref_service_.GetBoolean(kHighEfficiencyModeEnabled));
+}
+
+TEST_F(HighEfficiencyModePrefMigrationTest, BothPrefsDefaultNoMigration) {
+  // Simulate that the default enum state value is not "disabled"
+  pref_service_.SetDefaultPrefValue(kHighEfficiencyModeState, base::Value(1));
+
+  EXPECT_EQ(pref_service_.GetInteger(kHighEfficiencyModeState),
+            static_cast<int>(HighEfficiencyModeState::kEnabled));
+  EXPECT_TRUE(
+      pref_service_.FindPreference(kHighEfficiencyModeState)->IsDefaultValue());
+
+  MigrateHighEfficiencyModePref(&pref_service_);
+
+  // Both prefs were in the default state, no migration happens
+  EXPECT_TRUE(
+      pref_service_.FindPreference(kHighEfficiencyModeState)->IsDefaultValue());
+  EXPECT_EQ(pref_service_.GetInteger(kHighEfficiencyModeState),
+            static_cast<int>(HighEfficiencyModeState::kEnabled));
+}
+
+TEST_F(HighEfficiencyModePrefMigrationTest,
+       MigrateDefaultNewPrefUserSetOldPref) {
+  // Set the old pref as-if set by the user.
+  pref_service_.SetBoolean(kHighEfficiencyModeEnabled, true);
+
+  EXPECT_EQ(pref_service_.GetInteger(kHighEfficiencyModeState),
+            static_cast<int>(HighEfficiencyModeState::kDisabled));
+  EXPECT_TRUE(
+      pref_service_.FindPreference(kHighEfficiencyModeState)->IsDefaultValue());
+
+  MigrateHighEfficiencyModePref(&pref_service_);
+
+  EXPECT_FALSE(
+      pref_service_.FindPreference(kHighEfficiencyModeState)->IsDefaultValue());
+  // "true" in the boolean pref maps to `2` (enabled on timer)
+  EXPECT_EQ(pref_service_.GetInteger(kHighEfficiencyModeState),
+            static_cast<int>(HighEfficiencyModeState::kEnabledOnTimer));
+
+  // The old pref should be reset.
+  EXPECT_TRUE(pref_service_.FindPreference(kHighEfficiencyModeEnabled)
+                  ->IsDefaultValue());
+  EXPECT_FALSE(pref_service_.GetBoolean(kHighEfficiencyModeEnabled));
+}
+
+}  // namespace performance_manager::user_tuning::prefs
diff --git a/components/policy/resources/policy_templates_de.xtb b/components/policy/resources/policy_templates_de.xtb
index 6c14413..23ab522 100644
--- a/components/policy/resources/policy_templates_de.xtb
+++ b/components/policy/resources/policy_templates_de.xtb
@@ -532,15 +532,6 @@
 
       Diese Richtlinie wurde in M94 entfernt.</translation>
 <translation id="1507373253059695424">Privatsphärefunktion auf dem Anmeldebildschirm immer aktivieren</translation>
-<translation id="150857982247452081">Ermöglicht das Erstellen einer Liste mit Protokollen und für jedes Protokoll eine verknüpfte Liste mit zugelassenen Quellmustern, die eine externe App starten können, ohne beim Nutzer nachzufragen. Das abschließende Trennzeichen sollte beim Aufführen des Protokolls nicht mit angegeben werden. Gib also beispielsweise „skype“ ein, statt „skype:“ oder „skype://“.
-
-      Wenn diese Richtlinie konfiguriert ist, darf ein Protokoll nur dann ohne Nachfrage eine externe App starten, wenn es auf der Liste aufgeführt ist und die Quelle der Website, die das Protokoll starten will, mit einem der Muster in der Liste allowed_origins des jeweiligen Protokolls übereinstimmt. Wenn eine der Bedingungen nicht erfüllt ist, wird die Nachfrage beim Starten externer Protokolle durch die Richtlinie nicht weggelassen.
-
-      Wenn diese Richtlinie nicht konfiguriert ist, können standardmäßig keine Protokolle ohne Nachfrage starten. Nutzer können für einzelne Protokolle oder Websites auf die Aufforderung verzichten, es sei denn, die Richtlinie <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" /> ist deaktiviert. Diese Richtlinie hat keine Auswirkung auf vom Nutzer festgelegte Ausnahmen für einzelne Protokolle oder Websites.
-
-      In den Mustern, die mit der Quelle übereinstimmen, wird ein ähnliches Format wie in der Richtlinie <ph name="URL_BLOCKLIST_POLICY_NAME" /> verwendet. Sie sind unter http://www.chromium.org/administrators/url-blocklist-filter-format beschrieben.
-
-      Die Muster für diese Richtlinie dürfen allerdings keine „/path“- oder „@query“-Elemente enthalten. Muster, die „/path“- oder „@query“-Elemente enthalten, werden ignoriert.</translation>
 <translation id="1508588104835702000">Cloud-Berichterstellung über verwaltete Browser deaktivieren</translation>
 <translation id="1509377996969000672">Wenn die Richtlinie festgelegt ist, werden Konfigurationen für gerätegebundene Unternehmensdrucker bereitgestellt. Das Format entspricht dem <ph name="NATIVE_PRINTERS_POLICY_NAME" />-Wörterbuch, erfordert jedoch zusätzlich ein „id“- oder „guid“-Feld pro Drucker für die Zulassungs- oder Sperrliste. Die Datei darf nicht größer als 5 MB sein und muss im JSON-Format vorliegen. Eine Datei mit ungefähr 21.000 Druckern ergibt nach dem Codieren eine Datei mit 5 MB. Die Integrität des Downloads wird anhand des kryptografischen Hashs verifiziert. Die Datei wird heruntergeladen, im Cache gespeichert und noch einmal heruntergeladen, sobald sich URL oder Hash ändern. <ph name="PRODUCT_OS_NAME" /> lädt die Datei für Druckerkonfigurationen herunter und sorgt dafür, dass die Drucker gemäß <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />, <ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" /> und <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" /> verfügbar gemacht werden.
 
@@ -7528,14 +7519,6 @@
 <translation id="802776363472387903">SHA-256-Hash des <ph name="PLUGIN_VM_NAME" />-Image.</translation>
 <translation id="8028814157747157754">Den Standardsuchanbieter aktivieren und zulassen, dass Nutzer die Liste der Suchanbieter ändern</translation>
 <translation id="8029201909194194377">Maximal zulässige Sitzungsdauer für Verbindungen per Remotezugriff</translation>
-<translation id="8032201191311129122">Mit dieser Richtlinie wird das Kopieren von Daten in die Zwischenablage auf bestimmten URLs blockiert.
-
-      Mit den URL-Listen <ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> und <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> wird gesteuert, welche Websites in die Zwischenablage schreiben dürfen. Wenn ein URL-Muster in der Liste „Enable“ enthalten und in der Liste „Disable“ nicht enthalten ist, kann die betreffende Website nicht in die Zwischenablage schreiben. Ist die URL in keiner der beiden Listen enthalten, ist das Kopieren nicht blockiert.
-
-      Es werden ähnliche URL-Muster wie in der Richtlinie <ph name="URL_BLOCKLIST_POLICY_NAME" /> verwendet. Sie sind unter http://www.chromium.org/administrators/url-blocklist-filter-format beschrieben.
-
-      Unter <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" /> ist die minimale Datenmenge in Byte angegeben, die die Musterprüfung auslöst. Das bedeutet, dass ein Schreibvorgang in die Zwischenablage auf einer blockierten URL zulässig ist, wenn die Menge der kopierten Daten unter dem Wert in diesem Feld liegt. Wenn der Wert nicht festgelegt ist, gilt der Standardwert von 100 Byte.
-      </translation>
 <translation id="8033908599068513676">URL des herunterzuladenden Firmware-Images.</translation>
 <translation id="8035570672225663428">Adaptives Lademodell aktivieren, um den Ladevorgang anzuhalten und die Akkulaufzeit zu verlängern</translation>
 <translation id="8044493735196713914">Startmodus von Geräten melden</translation>
diff --git a/components/policy/resources/policy_templates_es-419.xtb b/components/policy/resources/policy_templates_es-419.xtb
index 1440033..2618b21 100644
--- a/components/policy/resources/policy_templates_es-419.xtb
+++ b/components/policy/resources/policy_templates_es-419.xtb
@@ -538,15 +538,6 @@
 
       En la versión M94, se quitó esta política.</translation>
 <translation id="1507373253059695424">Habilitar siempre la pantalla de privacidad en la pantalla de acceso</translation>
-<translation id="150857982247452081">Te permite configurar una lista de protocolos y, para cada uno de ellos, una lista asociada de patrones de origen permitidos, que pueden ejecutar una aplicación externa sin pedirle permiso al usuario. No se debe agregar el separador final cuando se incluye el protocolo en la lista; por lo tanto, usa "skype" en lugar de "skype:" o "skype://".
-
-      Si estableces esta política, un protocolo solamente podrá ejecutar una aplicación externa sin pedir permiso según la política si el protocolo aparece en la lista y el origen del sitio que intenta ejecutar el protocolo coincide con uno de los patrones de origen que se encuentra en la lista allowed_origins de ese protocolo. Si no se cumple alguna de estas condiciones, la política no omitirá el pedido de permiso para la ejecución por parte del protocolo externo.
-
-      Si no estableces la política, ningún protocolo puede ejecutar aplicaciones sin haber obtenido el permiso correspondiente de forma predeterminada. A menos que se inhabilite la política <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" />, los usuarios podrán rechazar las solicitudes de permiso según cada protocolo o sitio. Esta política no afecta a las excepciones de las solicitudes de permiso que establecen los usuarios para cada protocolo o sitio.
-
-      Los patrones de coincidencia de orígenes usan un formato similar a los de la política "<ph name="URL_BLOCKLIST_POLICY_NAME" />", que se documentan en ( http://www.chromium.org/administrators/url-blocklist-filter-format ).
-
-      Sin embargo, los patrones de coincidencia de orígenes para esta política no pueden incluir los elementos "/path" ni "@query". Se ignorará cualquier patrón que contenga alguno de estos elementos.</translation>
 <translation id="1508588104835702000">Inhabilitar los informes en la nube de navegadores administrados</translation>
 <translation id="1509377996969000672">Si estableces la política, se proporcionan configuraciones para las impresoras empresariales vinculadas a dispositivos. Su formato coincide con el diccionario de <ph name="NATIVE_PRINTERS_POLICY_NAME" />. Incluye un campo "id" o "guid" obligatorio adicional para cada impresora para la lista de impresoras permitidas o bloqueadas. El tamaño del archivo no puede superar los 5 MB y está en formato JSON (un archivo de ese tamaño contiene aproximadamente 21,000 impresoras). El hash criptográfico permite verificar la integridad de la descarga. Cada vez que cambie la URL o el hash, se descargará el archivo, se almacenará en caché y se volverá a descargar. <ph name="PRODUCT_OS_NAME" /> descargará el archivo para las configuraciones de impresoras y hará que las impresoras estén disponibles junto con <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />, <ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" /> y <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" />.
 
@@ -7739,14 +7730,6 @@
 <translation id="802776363472387903">El hash SHA-256 de la imagen del <ph name="PLUGIN_VM_NAME" />.</translation>
 <translation id="8028814157747157754">Habilitar el proveedor de búsqueda predeterminado y permitir que los usuarios modifiquen la lista de proveedores de búsqueda</translation>
 <translation id="8029201909194194377">Duración máxima de la sesión que se permite para las conexiones de acceso remoto</translation>
-<translation id="8032201191311129122">Esta política bloquea la copia de datos al portapapeles en URLs específicas.
-
-      Las listas de URLs <ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> y <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> controlan los sitios que pueden escribir en el portapapeles. Si la URL coincide con un patrón del campo "enable" y no coincide con ningún patrón del campo "disable", se bloqueará una escritura en el portapapeles. Si la URL no coincide con ningún patrón, no se bloqueará la copia.
-
-      Los patrones de coincidencia de orígenes usan un formato similar a los de la política "<ph name="URL_BLOCKLIST_POLICY_NAME" />", que se documentan en http://www.chromium.org/administrators/url-blocklist-filter-format.
-
-      El valor <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" /> indica la cantidad mínima de datos (expresada en bytes) que activa la revisión de patrones. Esto significa que se permitiría una escritura en el portapapeles de parte de una URL bloqueada si el tamaño de los datos copiados es menor al valor especificado en este campo. Si no estableces el campo, el valor predeterminado es 100 bytes.
-      </translation>
 <translation id="8033908599068513676">URL de la imagen de firmware que se descargará.</translation>
 <translation id="8035570672225663428">Habilitar el modelo de carga adaptable para detener el proceso de carga y así extender la duración de la batería</translation>
 <translation id="8044493735196713914">Modo de notificación de inicio de dispositivo</translation>
diff --git a/components/policy/resources/policy_templates_es.xtb b/components/policy/resources/policy_templates_es.xtb
index 9527c1f5..518d986 100644
--- a/components/policy/resources/policy_templates_es.xtb
+++ b/components/policy/resources/policy_templates_es.xtb
@@ -534,15 +534,6 @@
 
       Esta política se quitó en la versión M94.</translation>
 <translation id="1507373253059695424">Habilitar siempre la pantalla de privacidad en la pantalla de inicio de sesión</translation>
-<translation id="150857982247452081">Permite definir una lista de protocolos y una lista asociada de patrones de origen permitidos para cada uno de los protocolos, que pueden abrir una aplicación externa sin pedir permiso al usuario. No se debe incluir el separador del final al añadir el protocolo a la lista, así que añade "skype" en lugar de "skype:" o "skype://".
-
-      Si se define esta política, un protocolo solo podrá abrir una aplicación externa sin pedir permiso (por política) si está en la lista y si el origen del sitio que intenta iniciar el protocolo coincide con uno de los patrones de origen de la lista allowed_origins del protocolo. Si no se cumple alguna de estas condiciones, esta política no omitirá la solicitud para iniciar el protocolo externo.
-
-      Si no se define esta política, no se podrá iniciar ningún protocolo sin pedir permiso (de forma predeterminada). Los usuarios pueden rechazar las solicitudes por protocolo o por sitio, a menos que la política <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" /> se inhabilite. Esta política no tiene ningún efecto sobre las exenciones de solicitudes por protocolos o por sitios establecidas por el usuario.
-
-      Los patrones que coinciden con el origen tienen un formato similar a los de la política <ph name="URL_BLOCKLIST_POLICY_NAME" />, tal y como se indica en la página http://www.chromium.org/administrators/url-blocklist-filter-format
-
-      Sin embargo, los patrones de esta política que coinciden con el origen no pueden contener los elementos /path ni @query. Se ignorarán todos los patrones que contengan un elemento /path o @query.</translation>
 <translation id="1508588104835702000">Inhabilitar los informes en la nube a través de un navegador gestionado</translation>
 <translation id="1509377996969000672">Si se establece esta política, proporciona opciones de configuración para impresoras de empresa vinculadas a dispositivos. Su formato es el mismo que el del diccionario <ph name="NATIVE_PRINTERS_POLICY_NAME" />, con un campo id o guid obligatorio por impresora para incluirla en una lista de permitidas o bloqueadas. El tamaño del archivo no debe exceder los 5 MB y debe estar en formato JSON. El tamaño de un archivo que contiene unas 21.000 impresoras es de 5 MB. El hash criptográfico ayuda a comprobar la integridad de la descarga. Si se cambia la URL o el hash, el archivo se descarga, se almacena en caché y se vuelve a descargar. <ph name="PRODUCT_OS_NAME" /> descarga el archivo con las configuraciones de las impresoras y estas están disponibles según lo especificado en las políticas <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />, <ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" /> y <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" />.
 
@@ -7628,14 +7619,6 @@
 <translation id="802776363472387903">El hash SHA-256 de la imagen de <ph name="PLUGIN_VM_NAME" />.</translation>
 <translation id="8028814157747157754">Habilitar el proveedor de búsqueda predeterminado y permitir a los usuarios modificar la lista de proveedores de búsqueda</translation>
 <translation id="8029201909194194377">Duración máxima permitida de la sesión para conexiones de acceso remoto</translation>
-<translation id="8032201191311129122">Esta política impide copiar datos en el portapapeles en URLs específicas.
-
-      Las listas de URLs <ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> y <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> controlan los sitios en los que se puede escribir en el portapapeles. Se bloquea la escritura en el portapapeles si la URL coincide con un patrón en la lista de URLs permitidas y no coincide con un patrón en la lista de bloqueadas. No se impide copiar si la URL no coincide con ningún patrón.
-
-      Los patrones que coinciden con el origen tienen un formato similar a los de la política <ph name="URL_BLOCKLIST_POLICY_NAME" />, tal y como se indica en la página http://www.chromium.org/administrators/url-blocklist-filter-format.
-
-      El campo <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" /> indica la cantidad mínima de datos (en bytes) que activa la comprobación de patrones. Esto significa que la escritura en el portapapeles desde una URL bloqueada se permitiría si el tamaño de los datos copiados es inferior al valor especificado en este campo. El valor predeterminado es 100 bytes si el campo no se establece.
-      </translation>
 <translation id="8033908599068513676">URL de la imagen de firmware que se va a descargar.</translation>
 <translation id="8035570672225663428">Habilitar el modelo de Carga inteligente para suspender el proceso de carga y prolongar la duración de la batería</translation>
 <translation id="8044493735196713914">Notificar modo de inicio de dispositivo</translation>
diff --git a/components/policy/resources/policy_templates_fr.xtb b/components/policy/resources/policy_templates_fr.xtb
index 0cf935e..7635150 100644
--- a/components/policy/resources/policy_templates_fr.xtb
+++ b/components/policy/resources/policy_templates_fr.xtb
@@ -534,15 +534,6 @@
 
       Cette règle a été supprimée dans M94.</translation>
 <translation id="1507373253059695424">Toujours activer l'écran de confidentialité sur l'écran de connexion</translation>
-<translation id="150857982247452081">Permet d'établir la liste des protocoles (et pour chacun d'eux, une liste associée de formats d'origines autorisées) qui peuvent lancer une application externe sans afficher d'invite. Lorsqu'un protocole est répertorié, le séparateur de fin ne doit pas être inclus. Par exemple, il convient de garder "skype" et non "skype:" ou "skype://".
-
-      Si cette règle est configurée, un protocole n'est autorisé à lancer une application externe sans afficher d'invite que si ce protocole est répertorié dans la liste établie, et si l'origine du site qui essaie de lancer le protocole correspond à l'un des formats d'origines figurant dans la liste des origines autorisées de ce protocole. Si l'une des deux conditions est fausse, la règle n'omet pas l'invite de lancement du protocole externe.
-
-      Si cette règle n'est pas configurée, aucun protocole ne peut être lancé sans invite par défaut. Les utilisateurs peuvent désactiver les invites selon le protocole ou le site, sauf si la règle <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" /> est désactivée. Cette règle n'a aucune incidence sur les exceptions définies par les utilisateurs concernant les invites selon le protocole ou le site.
-
-      Les formats d'origines correspondants dans la liste sont semblables à ceux de la règle <ph name="URL_BLOCKLIST_POLICY_NAME" /> décrite à la page http://www.chromium.org/administrators/url-blocklist-filter-format.
-
-      Toutefois, dans le cadre de cette règle, ces formats ne doivent pas inclure les éléments "/path" ni "@query". Tout format qui inclut l'élément "/path" ou "@query" est ignoré.</translation>
 <translation id="1508588104835702000">Désactiver la création de rapports cloud via un navigateur géré</translation>
 <translation id="1509377996969000672">La définition de cette règle fournit les configurations des imprimantes d'entreprise associées à des appareils. Son format correspond au dictionnaire <ph name="NATIVE_PRINTERS_POLICY_NAME" />, avec un champ supplémentaire "id" ou "guid" obligatoire pour chaque imprimante à ajouter à la liste d'autorisation ou à la liste de refus. Le fichier est au format JSON et sa taille ne peut pas dépasser 5 Mo. Un fichier encodé de 5 Mo peut contenir environ 21 000 imprimantes. Le hachage cryptographique permet de valider l'intégrité du téléchargement. Le fichier est téléchargé, mis en cache, puis téléchargé à nouveau à chaque modification de l'URL ou du hachage. <ph name="PRODUCT_OS_NAME" /> télécharge le fichier des configurations d'imprimante et rend les imprimantes accessibles avec <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />, <ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" /> et <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" />.
 
@@ -7562,14 +7553,6 @@
 <translation id="802776363472387903">Hachage SHA-256 de l'image <ph name="PLUGIN_VM_NAME" />.</translation>
 <translation id="8028814157747157754">Activer le moteur de recherche par défaut et autoriser les utilisateurs à modifier la liste des moteurs de recherche</translation>
 <translation id="8029201909194194377">Durée maximale des sessions autorisée pour les connexions d'accès à distance</translation>
-<translation id="8032201191311129122">Cette règle permet de bloquer ou non la copie de données dans le presse-papiers sur des URL précises.
-
-      Les listes de formats d'URL <ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> et <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> déterminent quels sites sont autorisés ou non à écrire dans le presse-papiers. L'écriture dans le presse-papiers est bloquée si le format d'URL concerné figure dans la liste "enable" et pas dans la liste "disable". La copie n'est pas bloquée si le format d'URL n'est dans aucune liste.
-
-      Les formats correspondant à l'origine dans la liste sont semblables à ceux de la règle <ph name="URL_BLOCKLIST_POLICY_NAME" /> décrite à la page http://www.chromium.org/administrators/url-blocklist-filter-format.
-
-      Le champ <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" /> indique la quantité minimale de données en octets à partir de laquelle le format est vérifié. Autrement dit, l'écriture dans le presse-papiers sur une URL bloquée serait autorisée si la taille des données copiées est inférieure à la valeur indiquée dans ce champ. Si ce champ n'est pas renseigné, la valeur par défaut est de 100 octets.
-      </translation>
 <translation id="8033908599068513676">URL de l'image du micrologiciel à télécharger.</translation>
 <translation id="8035570672225663428">Activez le modèle de recharge adaptative pour suspendre le processus de charge et allonger la durée de vie de la batterie.</translation>
 <translation id="8044493735196713914">Indiquer le mode de démarrage de l'appareil</translation>
diff --git a/components/policy/resources/policy_templates_id.xtb b/components/policy/resources/policy_templates_id.xtb
index a571ecc..bd70b1e 100644
--- a/components/policy/resources/policy_templates_id.xtb
+++ b/components/policy/resources/policy_templates_id.xtb
@@ -537,15 +537,6 @@
 
       Kebijakan ini dihapus di M94.</translation>
 <translation id="1507373253059695424">Selalu aktifkan layar privasi pada layar login</translation>
-<translation id="150857982247452081">Memungkinkan Anda menyetel daftar protokol, dan daftar terkait pola asal yang diizinkan untuk setiap protokol, yang dapat meluncurkan aplikasi eksternal tanpa meminta izin pengguna. Pemisah di akhir tidak boleh disertakan saat mencantumkan protokol, jadi cantumkan "skype" bukan "skype:" atau "skype://".
-
-      Jika kebijakan ini disetel, protokol hanya akan diizinkan oleh kebijakan untuk meluncurkan aplikasi eksternal tanpa meminta izin jika protokol tersebut tercantum, dan asal situs yang mencoba meluncurkan protokol tersebut cocok dengan pola asal dalam daftar allowed_origins protokol. Jika salah satu kondisinya tidak terpenuhi, permintaan izin peluncuran protokol eksternal tidak akan dihilangkan oleh kebijakan.
-
-      Jika kebijakan ini tidak disetel, secara default tidak ada protokol yang dapat diluncurkan tanpa meminta izin. Pengguna dapat memilih tidak dimintai izin per protokol/per situs kecuali jika kebijakan <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" /> disetel ke Nonaktif. Kebijakan ini tidak memengaruhi pengecualian permintaan izin per protokol/per situs yang disetel pengguna.
-
-      Pola yang cocok dengan asal akan menggunakan format serupa dengan kebijakan '<ph name="URL_BLOCKLIST_POLICY_NAME" />' yang didokumentasikan di http://www.chromium.org/administrators/url-blocklist-filter-format.
-
-      Namun, pola yang cocok dengan asal untuk kebijakan ini tidak boleh berisi elemen "/path" atau "@query". Semua pola yang berisi elemen "/path" atau "@query" akan diabaikan.</translation>
 <translation id="1508588104835702000">Nonaktifkan pelaporan cloud browser terkelola</translation>
 <translation id="1509377996969000672">Jika kebijakan disetel, konfigurasi untuk printer perusahaan yang terikat ke perangkat akan tersedia. Jika formatnya cocok dengan kamus <ph name="NATIVE_PRINTERS_POLICY_NAME" />, dengan tambahan kolom "id" atau "guid" yang diperlukan agar setiap printer dapat mengizinkan atau menolak daftar. Ukuran file tidak boleh lebih dari 5 MB dan dalam format JSON. File yang berisi sekitar 21.000 printer dienkode sebagai file 5 MB. Hash kriptografi membantu memverifikasi integritas download. File didownload, disimpan dalam cache, dan didownload ulang ketika URL atau hash berubah. <ph name="PRODUCT_OS_NAME" /> mendownload file untuk konfigurasi printer dan menyediakan printer beserta <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />, <ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" />, dan <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" />.
 
@@ -7742,14 +7733,6 @@
 <translation id="802776363472387903">Hash SHA-256 gambar <ph name="PLUGIN_VM_NAME" />.</translation>
 <translation id="8028814157747157754">Aktifkan penyedia penelusuran default dan izinkan pengguna mengubah daftar penyedia penelusuran</translation>
 <translation id="8029201909194194377">Durasi sesi maksimum yang diizinkan untuk koneksi akses jarak jauh</translation>
-<translation id="8032201191311129122">Kebijakan ini memblokir penyalinan data ke papan klip pada URL tertentu.
-
-      Daftar URL <ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> dan <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> mengontrol situs mana yang diizinkan untuk menulis ke papan klip. Penulisan di papan klip diblokir jika URL cocok dengan pola di daftar 'aktifkan' dan tidak cocok dengan pola di daftar 'nonaktifkan'. Penyalinan tidak diblokir jika URL tidak cocok dengan pola apa pun.
-
-      Pola yang cocok dengan asal akan menggunakan format serupa dengan kebijakan '<ph name="URL_BLOCKLIST_POLICY_NAME" />' yang didokumentasikan di http://www.chromium.org/administrators/url-blocklist-filter-format.
-
-      <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" /> menunjukkan jumlah minimum data dalam byte yang memicu pemeriksaan pola. Hal ini berarti bahwa penulisan di papan klip dari URL yang diblokir akan diizinkan jika ukuran data yang disalin lebih kecil dari nilai yang ditentukan dalam kolom ini. Nilai defaultnya adalah 100 byte jika kolom tidak disetel.
-      </translation>
 <translation id="8033908599068513676">URL image firmware untuk didownload.</translation>
 <translation id="8035570672225663428">Aktifkan model pengisian daya adaptif untuk menunda proses pengisian daya guna memperpanjang masa pakai baterai</translation>
 <translation id="8044493735196713914">Laporkan mode boot perangkat</translation>
diff --git a/components/policy/resources/policy_templates_it.xtb b/components/policy/resources/policy_templates_it.xtb
index 61a67fa..c0161bd 100644
--- a/components/policy/resources/policy_templates_it.xtb
+++ b/components/policy/resources/policy_templates_it.xtb
@@ -534,15 +534,6 @@
 
       Questo criterio è stato rimosso dalla versione M94.</translation>
 <translation id="1507373253059695424">Attiva sempre la Schermata privata nella schermata di accesso</translation>
-<translation id="150857982247452081">Consente di impostare un elenco di protocolli, e per ogni protocollo un elenco associato di pattern di origini consentite, che possono lanciare un'applicazione esterna senza chiedere conferma all'utente. Il separatore finale non deve essere incluso nell'elenco di protocolli, quindi usa "skype" anziché "skype:" o "skype://".
-
-      Se questo criterio viene impostato, un protocollo sarà autorizzato a lanciare un'applicazione esterna senza chiedere conferma in base al criterio soltanto se il protocollo è nell'elenco e se l'origine del sito che prova a lanciare il protocollo corrisponde a uno dei pattern di origini nell'elenco allowed_origins del protocollo. Se una delle condizioni è falsa, la richiesta di lancio di un protocollo esterno non sarà omessa, in base al criterio.
-
-      Se questo criterio non viene impostato, per impostazione predefinita nessun protocollo può essere lanciato senza chiedere conferma. Gli utenti possono disattivare le richieste di conferma per ogni singolo protocollo/sito, a meno che il criterio <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" /> sia impostato su Disattivato. Questo criterio non influisce sulle esenzioni delle richieste di conferma per ogni singolo protocollo/sito impostate dagli utenti.
-
-      Per i pattern corrispondenti alle origini viene usato un formato simile a quello usato per i pattern del criterio "<ph name="URL_BLOCKLIST_POLICY_NAME" />", documentati all'indirizzo http://www.chromium.org/administrators/url-blocklist-filter-format.
-
-      I pattern corrispondenti alle origini di questo criterio non possono però contenere elementi "/path" o "@query". I pattern contenenti un elemento "/path" o "@query" verranno ignorati.</translation>
 <translation id="1508588104835702000">Disattiva reporting su cloud tramite browser gestito</translation>
 <translation id="1509377996969000672">La configurazione del criterio consente di specificare le configurazioni delle stampanti aziendali associate ai dispositivi. Il formato corrisponde a quello del dizionario <ph name="NATIVE_PRINTERS_POLICY_NAME" />, con un campo "id" o "guid" aggiuntivo obbligatorio per ogni stampante ai fini dell'inserimento in una lista consentita o in una lista bloccata. Le dimensioni del file non possono superare i 5 MB e il formato deve essere JSON. Un file con circa 21.000 stampanti viene codificato come file di 5 MB. L'hash di crittografia consente di verificare l'integrità del download. Il file viene scaricato, memorizzato nella cache e riscaricato ogni volta che l'URL o l'hash cambiano. <ph name="PRODUCT_OS_NAME" /> scarica il file per le configurazioni delle stampanti e rende disponibili le stampanti in base ai criteri <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />, <ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" /> e <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" />.
 
@@ -7570,14 +7561,6 @@
 <translation id="802776363472387903">L'hash SHA-256 dell'immagine <ph name="PLUGIN_VM_NAME" />.</translation>
 <translation id="8028814157747157754">Attiva il provider di ricerca predefinito e consenti agli utenti di modificare l'elenco dei provider di ricerca</translation>
 <translation id="8029201909194194377">Durata massima della sessione consentita per le connessioni di accesso remoto</translation>
-<translation id="8032201191311129122">Questo criterio impedisce la copia dei dati negli appunti per URL specifici.
-
-      Gli elenchi di URL<ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> e <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> consentono di controllare a quali siti è consentito scrivere negli appunti. La scrittura negli appunti viene bloccata se l'URL corrisponde a un pattern in "enable" e non corrisponde a un pattern in "disable". La copia non viene bloccata se l'URL non corrisponde ad alcun pattern.
-
-      Per i pattern corrispondenti alle origini viene usato un formato simile a quello usato per i pattern del criterio "<ph name="URL_BLOCKLIST_POLICY_NAME" />", documentati all'indirizzo http://www.chromium.org/administrators/url-blocklist-filter-format.
-
-      La dimensione <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" /> indica la quantità minima di dati in byte che attiva il controllo dei pattern. Ciò significa che la scrittura negli appunti da un URL bloccato sarebbe consentita se la dimensione dei dati copiati fosse inferiore al valore specificato in questo campo. Se il campo non viene impostato, il valore predefinito è 100 byte.
-      </translation>
 <translation id="8033908599068513676">URL dell'immagine del firmware da scaricare.</translation>
 <translation id="8035570672225663428">Consenti al modello di ricarica adattiva di sospendere la procedura di ricarica per prolungare la durata della batteria</translation>
 <translation id="8044493735196713914">Indicazione modalità di avvio dispositivo</translation>
diff --git a/components/policy/resources/policy_templates_ja.xtb b/components/policy/resources/policy_templates_ja.xtb
index 497893c..995b789 100644
--- a/components/policy/resources/policy_templates_ja.xtb
+++ b/components/policy/resources/policy_templates_ja.xtb
@@ -523,15 +523,6 @@
 
       このポリシーは M94 で削除されました。</translation>
 <translation id="1507373253059695424">ログイン画面でプライバシー画面を常に有効にする</translation>
-<translation id="150857982247452081">ユーザーに許可を求めずに外部アプリケーションを実行できるプロトコルのリストと、各プロトコルに対して許可する提供元のパターンのリストを定義します。プロトコルのリストは、末尾の区切り記号を含めずに指定してください。たとえば「skype:」や「skype://」ではなく「skype」と指定します。
-
-      このポリシーを設定した場合、プロトコルがリストで指定されていて、プロトコルを実行するサイトの提供元がそのプロトコルの allowed_origins リストのパターンと一致する場合にのみ、ユーザーに許可を求めずに外部アプリケーションを実行できます。いずれかの条件を満たさない場合、ポリシーによって外部プロトコルの実行プロンプトを省略することはできません。
-
-      このポリシーを設定しない場合、プロンプトを表示せずにプロトコルを実行することはデフォルトで許可されません。<ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" /> ポリシーが無効に設定されていない場合、ユーザーはプロトコルやサイト単位でプロンプト表示を無効にできます。このポリシーは、ユーザーがプロトコルやサイト単位で設定したプロンプト表示の無効化に影響しません。
-
-      提供元の一致パターンは、<ph name="URL_BLOCKLIST_POLICY_NAME" /> ポリシーと同様の形式で指定します。詳しくは、http://www.chromium.org/administrators/url-blocklist-filter-format をご覧ください。
-
-      ただし、このポリシーの提供元の一致パターンに「/path」要素や「@query」要素を含めることはできません。「/path」要素や「@query」要素が含まれているパターンは無視されます。</translation>
 <translation id="1508588104835702000">管理対象ブラウザのクラウド レポートを無効にする</translation>
 <translation id="1509377996969000672">このポリシーでは、デバイスに接続された企業プリンタの設定を指定できます。フォーマットは <ph name="NATIVE_PRINTERS_POLICY_NAME" /> ディクショナリと一致させ、許可リストまたは拒否リストに登録するプリンタごとに「id」または「guid」フィールドを追加で指定する必要があります。ファイルのサイズは 5 MB 以下とし、JSON 形式にします。5 MB は、約 21,000 台のプリンタを指定してエンコードしたファイルに相当します。ダウンロードの整合性の確認には暗号化ハッシュが使用されます。このファイルはダウンロードされた後、キャッシュされ、URL またはハッシュに変更があった場合は再度ダウンロードされます。<ph name="PRODUCT_OS_NAME" /> ではプリンタ設定ファイルがダウンロードされ、<ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />、<ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" />、<ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" /> に沿ってプリンタが利用可能になります。
 
@@ -7193,8 +7184,6 @@
 <translation id="802776363472387903"><ph name="PLUGIN_VM_NAME" /> 画像の SHA-256 ハッシュです。</translation>
 <translation id="8028814157747157754">デフォルトの検索プロバイダを有効にし、ユーザーに検索プロバイダ リストの変更を許可</translation>
 <translation id="8029201909194194377">リモート アクセス接続で許可する最長セッション継続時間</translation>
-<translation id="8032201191311129122">このポリシーによって、特定の URL 上のクリップボードにデータをコピーすることがブロックされます。<ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> と <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> の URL リストは、クリップボードへの書き込みを許可するサイトを管理します。クリップボードへの書き込みは、URL が「enable」のパターンに一致し、「disable」のパターンとは一致しない場合にブロックされます。URL がいずれのパターンとも一致しない場合、コピーはブロックされません。提供元の一致パターンは、<ph name="URL_BLOCKLIST_POLICY_NAME" /> ポリシーと同様の形式で指定します。詳しくは、http://www.chromium.org/administrators/url-blocklist-filter-format をご覧ください。<ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" /> は、パターンのチェックをトリガーする最小データ量(単位: バイト)を示します。つまり、ブロック対象の URL からのクリップボードへの書き込みは、コピーするデータのサイズがこのフィールドで指定された値未満である場合に許可されます。このフィールドが未設定の場合のデフォルト値は 100 バイトです。
-      </translation>
 <translation id="8033908599068513676">ダウンロードするファームウェア イメージの URL。</translation>
 <translation id="8035570672225663428">アダプティブ充電モデルを有効にして、バッテリー寿命を延ばすため充電プロセスを保留する</translation>
 <translation id="8044493735196713914">デバイス起動モードを報告する</translation>
diff --git a/components/policy/resources/policy_templates_ko.xtb b/components/policy/resources/policy_templates_ko.xtb
index a2e3da14..d98d964f 100644
--- a/components/policy/resources/policy_templates_ko.xtb
+++ b/components/policy/resources/policy_templates_ko.xtb
@@ -534,15 +534,6 @@
 
       이 정책은 M94에서 삭제되었습니다.</translation>
 <translation id="1507373253059695424">로그인 화면의 개인 정보 보호 화면을 항상 사용 설정</translation>
-<translation id="150857982247452081">프로토콜 목록과 각 프로토콜에 허용되는 출처 패턴의 목록을 설정할 수 있도록 하여 사용자에게 메시지를 표시하지 않고 외부 애플리케이션이 실행될 수 있도록 합니다. 프로토콜을 목록에 등록할 때 후행 구분자가 포함되어서는 안 됩니다. 따라서 'skype:' 또는 'skype://'가 아닌 'skype'로 표시하세요.
-
-      이 정책을 설정하면 프로토콜이 목록에 등록되어 있고 해당 프로토콜을 실행하려는 사이트의 출처가 해당 프로토콜의 allowed_origins 목록에 있는 출처 패턴 중 하나와 일치하는 경우에만 사용자에게 메시지를 표시하지 않고 프로토콜이 외부 애플리케이션을 실행할 수 있도록 정책에서 허용합니다. 두 가지 조건 중 하나라도 충족되지 않는 경우 외부 프로토콜이 실행될 때 정책에서 메시지 표시를 생략하지 않습니다.
-
-      정책을 설정하지 않으면 기본적으로 어떠한 프로토콜도 메시지 표시 없이는 실행될 수 없습니다. <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" /> 정책이 사용 안함으로 설정되지 않은 경우 사용자는 프로토콜별/사이트별로 메시지 표시를 선택 해제할 수 있습니다. 이 정책은 사용자가 설정한 프로토콜별/사이트별 메시지 표시 예외에 영향을 미치지 않습니다.
-
-      출처 일치 패턴은 http://www.chromium.org/administrators/url-blocklist-filter-format에 설명된 '<ph name="URL_BLOCKLIST_POLICY_NAME" />' 정책과 비슷한 형식을 사용합니다.
-
-      하지만 이 정책의 출처 일치 패턴에는 '/path' 또는 '@query' 요소가 포함될 수 없습니다. '/path' 또는 '@query' 요소가 포함된 패턴은 무시됩니다.</translation>
 <translation id="1508588104835702000">관리 브라우저 클라우드 보고 사용 안함</translation>
 <translation id="1509377996969000672">정책을 설정하면 기기에 연결된 회사 프린터의 설정이 제공됩니다. 형식은 <ph name="NATIVE_PRINTERS_POLICY_NAME" /> 사전과 일치하며 허용 목록 또는 차단 목록을 사용하려면 프린터마다 'id' 또는 'guid' 필드가 추가로 필요합니다. 파일 크기는 5MB를 초과할 수 없으며 JSON 형식입니다. 약 21,000대의 프린터가 포함된 파일은 5MB 크기의 파일로 인코딩됩니다. 암호화 해시로 다운로드 파일의 무결성을 확인할 수 있습니다. 파일이 다운로드되고 캐시되며 이후 URL 또는 해시가 변경되면 다시 다운로드됩니다. <ph name="PRODUCT_OS_NAME" />에서 프린터 설정 파일을 다운로드하고 <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />, <ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" />, <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" />에 따라 프린터를 사용할 수 있게 합니다.
 
@@ -7585,14 +7576,6 @@
 <translation id="802776363472387903"><ph name="PLUGIN_VM_NAME" /> 이미지의 SHA-256 해시입니다.</translation>
 <translation id="8028814157747157754">기본 검색 제공업체를 사용 설정하고 사용자가 검색 제공업체 목록을 수정할 수 있도록 허용</translation>
 <translation id="8029201909194194377">원격 액세스 연결에 허용되는 최대 세션 시간</translation>
-<translation id="8032201191311129122">이 정책은 특정 URL에서 데이터를 클립보드에 복사하지 못하게 차단합니다.
-
-      <ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> 및 <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> URL 목록은 클립보드에 쓸 수 있는 사이트를 제어합니다. URL이 '사용'의 패턴과 일치하고 '사용 중지'의 패턴과 일치하지 않는 경우 클립보드 쓰기가 차단됩니다. URL이 어떤 패턴과도 일치하지 않으면 복사가 차단되지 않습니다.
-
-      출처 일치 패턴은 '<ph name="URL_BLOCKLIST_POLICY_NAME" />' 정책(http://www.chromium.org/administrators/url-blocklist-filter-format의 설명 참고)과 비슷한 형식을 사용합니다.
-
-      <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" />은(는) 패턴 확인을 트리거하는 데이터의 최소 크기를 바이트 단위로 나타낸 것입니다. 즉, 복사된 데이터의 크기가 이 입력란에 지정된 값보다 작으면 차단된 URL의 클립보드 쓰기가 허용될 수 있습니다. 입력란이 설정되지 않은 경우 기본값은 100바이트입니다.
-      </translation>
 <translation id="8033908599068513676">다운로드할 펌웨어 이미지의 URL입니다.</translation>
 <translation id="8035570672225663428">자동 조절 충전 모델을 사용 설정하여 배터리 수명 연장을 위해 충전 프로세스를 보류합니다.</translation>
 <translation id="8044493735196713914">기기 부팅 모드 보고</translation>
diff --git a/components/policy/resources/policy_templates_nl.xtb b/components/policy/resources/policy_templates_nl.xtb
index dbd42e5..b33345a6 100644
--- a/components/policy/resources/policy_templates_nl.xtb
+++ b/components/policy/resources/policy_templates_nl.xtb
@@ -534,15 +534,6 @@
 
       Dit beleid is verwijderd in M94.</translation>
 <translation id="1507373253059695424">Het privacyscherm op het inlogscherm altijd aanzetten</translation>
-<translation id="150857982247452081">Hiermee kun je een lijst met protocollen instellen (en voor elk protocol een gekoppelde lijst met toegestane oorsprongpatronen) die een externe app kunnen starten zonder prompt aan de gebruiker. Het scheidingsteken achteraan moet niet worden opgenomen bij de vermelding van het protocol. Vermeld bijvoorbeeld 'skype' in plaats van 'skype:' of 'skype://'.
-
-      Als dit beleid is ingesteld, kan een protocol volgens het beleid een externe app alleen starten zonder prompt aan de gebruiker als het protocol in de lijst wordt vermeld en de oorsprong van de site die probeert het protocol te starten, overeenkomt met een van de oorsprongpatronen in de lijst allowed_origins van dat protocol. Als een van de voorwaarden False is, wordt de prompt voor starten via een extern protocol volgens het beleid niet overgeslagen.
-
-      Als dit beleid niet is ingesteld, kunnen protocollen standaard niet worden gestart zonder prompt. Gebruikers kunnen zich voor specifieke protocollen/sites afmelden voor prompts, tenzij het beleid <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" /> niet is toegepast. Dit beleid heeft geen invloed op promptuitzonderingen voor specifieke protocollen/sites die zijn ingesteld door gebruikers.
-
-      De patronen voor overeenkomende oorsprong gebruiken een vergelijkbare indeling als die voor het beleid <ph name="URL_BLOCKLIST_POLICY_NAME" /> (deze worden gedocumenteerd op http://www.chromium.org/administrators/url-blocklist-filter-format).
-
-      Patronen voor overeenkomende oorsprong voor dit beleid mogen geen /path- of @query-elementen bevatten. Patronen die een /path- of @query-element bevatten, worden genegeerd.</translation>
 <translation id="1508588104835702000">Cloudrapportage voor beheerde browsers uitzetten</translation>
 <translation id="1509377996969000672">Als je dit beleid instelt, worden configuraties geboden voor bedrijfsprinters die aan apparaten zijn gekoppeld. De indeling komt overeen met de dictionary <ph name="NATIVE_PRINTERS_POLICY_NAME" />, waarbij voor elke printer ook een veld 'id' of 'guid' verplicht is voor de toelatingslijst of weigeringslijst. Bestanden moeten een json-indeling hebben en mogen maximaal 5 MB zijn. In een bestand van 5 MB kunnen ongeveer 21.000 printers staan. De cryptografische hash wordt gebruikt om de integriteit van de download te verifiëren. Het bestand wordt gedownload, gecachet en opnieuw gedownload als de URL of de hash wordt gewijzigd. <ph name="PRODUCT_OS_NAME" /> downloadt het bestand voor printerconfiguraties en maakt printers beschikbaar in overeenstemming met <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />, <ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" /> en <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" />.
 
@@ -7527,14 +7518,6 @@
 <translation id="802776363472387903">De SHA-256-hash van de <ph name="PLUGIN_VM_NAME" />-afbeelding.</translation>
 <translation id="8028814157747157754">De standaard zoekprovider aanzetten en toestaan dat gebruikers de lijst met zoekproviders wijzigen</translation>
 <translation id="8029201909194194377">Maximale toegestane sessieduur voor verbindingen voor externe toegang</translation>
-<translation id="8032201191311129122">Met dit beleid blokkeer je het kopiëren van gegevens naar het klembord voor specifieke URL's.
-
-De URL-lijsten <ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> en <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> bepalen welke sites naar het klembord mogen schrijven. Een schrijfactie naar het klembord wordt geblokkeerd als de URL overeenkomt met een patroon in 'enable' en niet overeenkomt met een patroon in 'disable'. Een kopieeractie wordt niet geblokkeerd als de URL met geen enkel patroon overeenkomt.
-
-      De patronen voor overeenkomende oorsprong gebruiken een vergelijkbare indeling als die voor het beleid <ph name="URL_BLOCKLIST_POLICY_NAME" /> (deze worden gedocumenteerd op http://www.chromium.org/administrators/url-blocklist-filter-format).
-
-      De <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" /> geeft de minimale hoeveelheid gegevens in bytes aan die de patrooncontrole activeert. Dit betekent dat een schrijfactie naar het klembord vanaf een geblokkeerde URL is toegestaan als de grootte van de gekopieerde gegevens kleiner is dan de waarde in dit veld. De standaardwaarde is 100 bytes als het veld niet is ingesteld.
-      </translation>
 <translation id="8033908599068513676">URL van de firmware-image die moet worden gedownload.</translation>
 <translation id="8035570672225663428">Het model voor aangepast opladen aanzetten om het oplaadproces te onderbreken om de batterijduur te verlengen</translation>
 <translation id="8044493735196713914">Opstartmodus van apparaat melden</translation>
diff --git a/components/policy/resources/policy_templates_pt-BR.xtb b/components/policy/resources/policy_templates_pt-BR.xtb
index 95bd19ea..c2bd43a 100644
--- a/components/policy/resources/policy_templates_pt-BR.xtb
+++ b/components/policy/resources/policy_templates_pt-BR.xtb
@@ -534,15 +534,6 @@
 
       Essa política foi removida na versão M94.</translation>
 <translation id="1507373253059695424">Sempre ativar a tela de privacidade na tela de login</translation>
-<translation id="150857982247452081">Permite definir uma lista de protocolos e, para cada protocolo, uma lista associada de padrões de origem com permissão para inicializar um aplicativo externo sem notificar o usuário. O separador à direita não pode ser incluído ao listar o protocolo, então liste "skype" em vez de "skype:" ou "skype://".
-
-      Se esta política for definida, um protocolo só terá permissão para inicializar um aplicativo externo sem notificação se o protocolo estiver listado e a origem do site que tentou inicializar o protocolo corresponder a um dos padrões de origem na lista allowed_origins desse protocolo. Se alguma das condições for falsa, a solicitação de inicialização de protocolo externo não será omitida pela política.
-
-      Por padrão, se a política não for definida, nenhum protocolo poderá ser inicializado sem uma solicitação. Os usuários podem recusar as solicitações por site ou por protocolo, a menos que a política <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" /> esteja desativada. Esta política não afeta isenções por site ou por protocolo definidas pelo usuário.
-
-      Os padrões de correspondência de origem usam um formato semelhante aos da política <ph name="URL_BLOCKLIST_POLICY_NAME" />, que estão documentados em http://www.chromium.org/administrators/url-blocklist-filter-format (link em inglês).
-
-      Entretanto, os padrões de correspondência de origem para esta política não podem conter elementos "/path" ou "@query". Todos os padrões que contiverem um elemento "/path" ou "@query" serão ignorados.</translation>
 <translation id="1508588104835702000">Desativar os relatórios de nuvem do navegador gerenciado</translation>
 <translation id="1509377996969000672">A definição da política fornece configurações para impressoras corporativas vinculadas a dispositivos. O formato corresponde ao dicionário <ph name="NATIVE_PRINTERS_POLICY_NAME" />, com campos extras "id" ou "guid" obrigatórios para cada impressora para inclusão na lista de bloqueio ou de permissão. O arquivo não pode exceder 5 MB e precisa estar no formato JSON. Um arquivo contendo 21.000 impressoras é codificado como um arquivo de 5 MB. O hash criptográfico ajuda a verificar a integridade do download. O download do arquivo é feito com armazenamento em cache e é refeito quando o URL ou o hash mudam. O <ph name="PRODUCT_OS_NAME" /> faz o download do arquivo para as configurações de impressora e disponibiliza as impressoras de acordo com <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />, <ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" /> e <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" />.
 
@@ -7731,14 +7722,6 @@
 <translation id="802776363472387903">Hash SHA-256 da imagem do <ph name="PLUGIN_VM_NAME" />.</translation>
 <translation id="8028814157747157754">Ativar o provedor de pesquisa padrão e permitir que os usuários modifiquem a lista de provedores de pesquisa</translation>
 <translation id="8029201909194194377">Duração máxima da seção permitida por conexões de acesso remoto</translation>
-<translation id="8032201191311129122">Esta política bloqueia a cópia para a área de transferência de dados em URLs específicas.
-
-      As listas de URL <ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> e <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> controlam quais sites têm permissão para salvar na área de transferência. Uma cópia na área de transferência é bloqueada se a URL corresponde a um padrão na lista "enable" (ativar) e não corresponde a um padrão em "disable" (desativar). A cópia não é bloqueada se a URL não corresponde a nenhum padrão.
-
-      Os padrões de correspondência de origem usam um formato semelhante aos da política <ph name="URL_BLOCKLIST_POLICY_NAME" />, que estão documentados em http://www.chromium.org/administrators/url-blocklist-filter-format (link em inglês).
-
-      O <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" /> indica a quantidade mínima de dados em bytes que aciona a verificação de padrões. Isso significa que a cópia para a área de transferência de uma URL bloqueada é autorizada se o tamanho dos dados copiados for menor que o valor especificado nesse campo. Se o campo não for definido, o valor padrão será de 100 bytes.
-      </translation>
 <translation id="8033908599068513676">URL da imagem de firmware para download.</translation>
 <translation id="8035570672225663428">Permitir que o modelo de carregamento adaptável controle o processo de carregamento para prolongar a duração da bateria</translation>
 <translation id="8044493735196713914">Informar modo de inicialização do dispositivo</translation>
diff --git a/components/policy/resources/policy_templates_ru.xtb b/components/policy/resources/policy_templates_ru.xtb
index defb0511..ea65ec1 100644
--- a/components/policy/resources/policy_templates_ru.xtb
+++ b/components/policy/resources/policy_templates_ru.xtb
@@ -531,15 +531,6 @@
 
       Это правило было удалено в версии M94.</translation>
 <translation id="1507373253059695424">Всегда включать экран конфиденциальности на экране входа</translation>
-<translation id="150857982247452081">Это правило позволяет настроить список протоколов и список допустимых шаблонов источников для каждого протокола, которые могут запускать внешнее приложение без отправки запроса пользователю. Протокол нужно указывать без разделителя – например, skype, а не skype: или skype://.
-
-      Если правило настроено, протокол сможет запускать внешнее приложение без отправки запроса пользователю, только если этот протокол указан в списке, а источник сайта, который пытается выполнить такой протокол, соответствует одному из шаблонов в списке allowed_origins, связанном с этим протоколом. Если хотя бы одно из условий не выполняется, правило не сможет предотвратить отправку пользователю запроса о подтверждении запуска внешнего протокола.
-
-      Если правило не настроено, то запуск любых протоколов без отправки запроса будет невозможен по умолчанию. Пользователи могут отключать запросы для отдельных протоколов или сайтов, если для правила <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" /> задано любое значение, кроме варианта "Отключено". На исключения запросов, заданные пользователями для отдельных протоколов или сайтов, это правило не влияет.
-
-      Шаблоны источников имеют практически тот же формат, что и шаблоны, которые используются в правиле <ph name="URL_BLOCKLIST_POLICY_NAME" />. Подробная информация о формате приведена на странице http://www.chromium.org/administrators/url-blocklist-filter-format.
-
-      При этом в шаблонах источников не могут содержаться элементы /path и @query. Шаблон с такими элементами учитываться не будет.</translation>
 <translation id="1508588104835702000">Не отправлять отчеты управляемого браузера в консоль администратора</translation>
 <translation id="1509377996969000672">Позволяет настроить корпоративные принтеры, связанные с устройствами. Поддерживаемый формат файла тот же, что и для словаря <ph name="NATIVE_PRINTERS_POLICY_NAME" />, но с дополнительными полями id и guid. Заполните их для каждого принтера, чтобы занести его в список разрешенных или заблокированных. Поддерживаемый формат файла конфигурации – JSON. Его размер не должен превышать 5 МБ. В файле такого объема можно указать около 21 000 принтеров. Для проверки целостности скачанного файла используется хеш-сумма. Файл скачивается и кешируется. В случае изменения URL или хеша файл скачивается повторно. <ph name="PRODUCT_OS_NAME" /> скачивает файл конфигурации и открывает доступ к принтерам согласно правилам <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />, <ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" /> и <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" />.
 
@@ -7570,14 +7561,6 @@
 <translation id="802776363472387903">Хеш SHA-256 для проверки изображения <ph name="PLUGIN_VM_NAME" />.</translation>
 <translation id="8028814157747157754">Включить поисковую систему по умолчанию и разрешить пользователям изменять список поисковых систем</translation>
 <translation id="8029201909194194377">Максимальная длительность сеанса удаленного подключения</translation>
-<translation id="8032201191311129122">Это правило запрещает копирование данных в буфер обмена на конкретных сайтах.
-
-      Списки URL <ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> и <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> определяют, каким сайтам разрешено записывать информацию в буфер обмена. Запись в буфер обмена блокируется, если URL соответствует шаблону из списка enable и не соответствует шаблону из списка disable. Копирование допускается, если URL не соответствует ни одному из шаблонов.
-
-      Шаблоны источников имеют практически тот же формат, что и шаблоны в правиле <ph name="URL_BLOCKLIST_POLICY_NAME" />. Подробная информация о формате приведена на странице http://www.chromium.org/administrators/url-blocklist-filter-format.
-
-      Параметр <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" /> указывает минимальный объем данных в байтах, для которых выполняется проверка. То есть запись в буфер обмена с заблокированного сайта будет разрешена, если объем копируемых данных меньше значения, указанного в этом поле. Минимальный объем по умолчанию равен 100 байтам.
-      </translation>
 <translation id="8033908599068513676">URL для скачивания образа встроенного ПО.</translation>
 <translation id="8035570672225663428">Разрешить модели адаптивной зарядки приостанавливать зарядку устройства, чтобы продлевать время его работы от батареи</translation>
 <translation id="8044493735196713914">Сообщать о режиме загрузки устройства</translation>
diff --git a/components/policy/resources/policy_templates_th.xtb b/components/policy/resources/policy_templates_th.xtb
index 577b89f..de73dea5 100644
--- a/components/policy/resources/policy_templates_th.xtb
+++ b/components/policy/resources/policy_templates_th.xtb
@@ -534,15 +534,6 @@
 
       เรานำนโยบายนี้ออกไปแล้วในเวอร์ชัน M94</translation>
 <translation id="1507373253059695424">เปิดใช้หน้าจอความเป็นส่วนตัวในหน้าจอลงชื่อเข้าใช้เสมอ</translation>
-<translation id="150857982247452081">ให้คุณกำหนดรายการโปรโตคอล และรายการที่เชื่อมโยงของรูปแบบต้นทางที่อนุญาตสำหรับแต่ละโปรโตคอล ซึ่งเปิดแอปพลิเคชันภายนอกได้โดยไม่ต้องแจ้งผู้ใช้ ไม่ควรใส่ตัวคั่นข้างหลังเมื่อระบุโปรโตคอล เช่น ให้ใช้ "skype" แทน "skype:" หรือ "skype://"
-
-      หากตั้งค่านโยบายนี้ ระบบจะอนุญาตให้โปรโตคอลเปิดแอปพลิเคชันภายนอกโดยไม่มีข้อความแจ้งจากนโยบาย ในกรณีที่มีการระบุโปรโตคอลดังกล่าวไว้ และต้นทางของเว็บไซต์ที่พยายามเปิดใช้งานโปรโตคอลตรงกับต้นทางรูปแบบใดรูปแบบหนึ่งในรายการ allowed_origins ของโปรโตคอลนั้น หากเงื่อนไขข้อใดข้อหนึ่งเป็น "เท็จ" นโยบายจะไม่ละเว้นข้อความแจ้งการเปิดใช้งานโปรโตคอลภายนอก
-
-      หากไม่ได้ตั้งค่านโยบาย โปรโตคอลทั้งหมดจะเปิดใช้งานได้ต่อเมื่อมีข้อความแจ้งโดยค่าเริ่มต้นเท่านั้น ผู้ใช้เลือกไม่รับข้อความแจ้งแบบรายโปรโตคอล/รายเว็บไซต์ได้หากนโยบาย <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" /> ไม่ได้ตั้งค่าเป็น "ปิดใช้" นโยบายนี้ไม่มีผลต่อการยกเว้นข้อความแจ้งแบบรายโปรโตคอล/รายเว็บไซต์ที่ผู้ใช้ตั้งค่า
-
-      รูปแบบที่ตรงกันของต้นทางใช้รูปแบบที่คล้ายกับของนโยบาย "<ph name="URL_BLOCKLIST_POLICY_NAME" />" ตามที่บันทึกไว้ที่ http://www.chromium.org/administrators/url-blocklist-filter-format
-
-      แต่รูปแบบที่ตรงกันของต้นทางในนโยบายนี้ต้องไม่มีองค์ประกอบ "/path" หรือ "@query" ระบบจะไม่สนใจรูปแบบที่มีองค์ประกอบ "/path" หรือ "@query"</translation>
 <translation id="1508588104835702000">ปิดใช้การรายงานในระบบคลาวด์ของเบราว์เซอร์ที่มีการจัดการ</translation>
 <translation id="1509377996969000672">การตั้งค่านโยบายนี้จะระบุการกำหนดค่าสำหรับเครื่องพิมพ์องค์กรที่เชื่อมโยงกับอุปกรณ์ รูปแบบการตั้งค่าเหมือนกับพจนานุกรม <ph name="NATIVE_PRINTERS_POLICY_NAME" /> แต่มีช่อง "id" หรือ "guid" ที่จำเป็นต้องกรอกเพิ่มเข้ามาสำหรับเครื่องพิมพ์แต่ละเครื่องเพื่อใช้ระบุว่าอยู่ในรายการที่อนุญาตหรือไม่อนุญาต ไฟล์ต้องมีขนาดไม่เกิน 5 MB และอยู่ในรูปแบบ JSON ไฟล์ที่ระบุเครื่องพิมพ์ประมาณ 21,000 เครื่องเข้ารหัสเป็นไฟล์ขนาด 5 MB ได้ 1 ไฟล์ แฮชแบบเข้ารหัสช่วยยืนยันความสมบูรณ์ของการดาวน์โหลด ไฟล์จะมีการดาวน์โหลด แคช และดาวน์โหลดอีกครั้งเมื่อ URL หรือแฮชมีการเปลี่ยนแปลง <ph name="PRODUCT_OS_NAME" /> จะดาวน์โหลดไฟล์ดังกล่าวเพื่อการกำหนดค่าเครื่องพิมพ์และทำให้เครื่องพิมพ์พร้อมใช้งานพร้อมด้วย <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />, <ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" /> และ <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" />
 
@@ -7532,14 +7523,6 @@
 <translation id="802776363472387903">แฮช SHA-256 ของรูปภาพ <ph name="PLUGIN_VM_NAME" /></translation>
 <translation id="8028814157747157754">เปิดใช้ผู้ให้บริการค้นหาเริ่มต้นและอนุญาตให้ผู้ใช้แก้ไขรายชื่อผู้ให้บริการค้นหา</translation>
 <translation id="8029201909194194377">ระยะเวลาเซสชันสูงสุดที่อนุญาตสำหรับการเชื่อมต่อของการเข้าถึงจากระยะไกล</translation>
-<translation id="8032201191311129122">นโยบายนี้จะบล็อกไม่ให้คัดลอกข้อมูลไปยังคลิปบอร์ดใน URL ที่เจาะจง
-
-      รายการ URL ที่<ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" />และ<ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" />จะควบคุมเว็บไซต์ที่ได้รับอนุญาตให้เขียนไปยังคลิปบอร์ด การเขียนไปยังคลิปบอร์ดจะถูกบล็อกหาก URL ตรงกับรูปแบบใน "เปิดใช้" แต่ไม่ตรงกับรูปแบบใน "ปิดใช้" การคัดลอกจะไม่ถูกบล็อกหาก URL ไม่ตรงกับรูปแบบใดๆ
-
-      รูปแบบที่ตรงกันของต้นทางใช้รูปแบบที่คล้ายกับของนโยบาย "<ph name="URL_BLOCKLIST_POLICY_NAME" />" ตามที่บันทึกไว้ใน http://www.chromium.org/administrators/url-blocklist-filter-format
-
-      <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" /> จะระบุจำนวนข้อมูลต่ำสุด (หน่วยเป็นไบต์) ที่จะเรียกให้การตรวจสอบรูปแบบทำงาน ซึ่งหมายความว่าระบบจะอนุญาตการเขียนไปยังคลิปบอร์ดจาก URL ที่ถูกบล็อกหากขนาดของข้อมูลที่คัดลอกเล็กกว่าค่าที่ระบุในช่องนี้ ค่าเริ่มต้นคือ 100 ไบต์หากไม่ได้ตั้งค่าช่องนี้
-      </translation>
 <translation id="8033908599068513676">URL ของอิมเมจเฟิร์มแวร์ที่จะดาวน์โหลด</translation>
 <translation id="8035570672225663428">เปิดใช้รูปแบบการชาร์จแบบปรับอัตโนมัติซึ่งจะพักขั้นตอนการชาร์จไว้ชั่วคราวเพื่อยืดอายุการใช้งานแบตเตอรี่</translation>
 <translation id="8044493735196713914">รายงานโหมดการบูตอุปกรณ์</translation>
diff --git a/components/policy/resources/policy_templates_tr.xtb b/components/policy/resources/policy_templates_tr.xtb
index c04e4798..8c33cd59 100644
--- a/components/policy/resources/policy_templates_tr.xtb
+++ b/components/policy/resources/policy_templates_tr.xtb
@@ -535,15 +535,6 @@
 
       Bu politika M94'te kaldırıldı.</translation>
 <translation id="1507373253059695424">Oturum açma ekranında gizlilik ekranını her zaman etkinleştir</translation>
-<translation id="150857982247452081">Protokol listesi ayarlamanıza ve ayarladığınız her protokol için izin verilen kaynak kalıplarının ilişkilendirilmiş bir listesini oluşturmanıza izin verir. Bu kalıplar kullanıcıya sormadan harici bir uygulama başlatabilir. Protokol listelenirken sondaki ayırıcı dahil edilmemelidir, o yüzden listeye "skype:" ya da "skype://" yerine doğrudan "skype" olarak ekleyin.
-
-      Bu politika ayarlanırsa protokol, listelendiği ve protokolü başlatmaya çalışan sitenin kaynağı protokolün izin_verilen_kaynaklar listesindeki kaynak kalıplarından biriyle eşleştiği takdirde politika tarafından sorulmadan yalnızca harici uygulamaları başlatma iznine sahip olur. İki koşul da yanlış ise harici protokol başlatma istemi politika tarafından atlanmaz.
-
-      Bu politika ayarlı değilse protokoller istem olmadan varsayılan halde başlayamaz. <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" /> politikası, devre dışı bırakılmadığı sürece kullanıcılar protokol/site bazında istemlerin kapsamı dışında kalmayı seçebilir. Bu politika, kullanıcıların ayarladığı protokol/site bazında istem muafiyetleri üzerinde etkili değildir.
-
-      Kaynakları eşleşen kalıplar, http://www.chromium.org/administrators/url-blocklist-filter-format adresinde bulabileceğiniz "<ph name="URL_BLOCKLIST_POLICY_NAME" />" politikasıyla benzer bir biçimi kullanır.
-
-      Fakat, bu politika için kaynakları eşleşen kalıplar "/path" ya da "@query" öğelerini içeremez. "/path" ya da "@query" öğelerini içeren kalıplar yok sayılacaktır.</translation>
 <translation id="1508588104835702000">Yönetilen tarayıcı bulut raporlamasını devre dışı bırak</translation>
 <translation id="1509377996969000672">Politika ayarlanırsa cihazlara bağlı kurumsal yazıcılar için yapılandırmalar sağlanır. Biçimi, <ph name="NATIVE_PRINTERS_POLICY_NAME" /> sözlüğü ile aynı olmakla birlikte izin verilenler veya engellenenler listelerine eklenecek her yazıcı için gerekli ek "id" veya "guid" alanlarını içerir. Dosya biçimi JSON olup boyutu 5 MB'tan büyük olamaz. Yaklaşık 21.000 yazıcı içeren bir dosya, 5 MB boyutunda olur. Şifreleme karma değeri, indirmenin bütünlüğünü doğrulamaya yardımcı olur. URL veya karma değer değiştiğinde dosya indirilir, önbelleğe alınır ve yeniden indirilir. <ph name="PRODUCT_OS_NAME" />, yazıcı yapılandırmalarına ait dosyayı indirerek <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />, <ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" /> ve <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" /> ile birlikte yazıcıları kullanılabilir hale getirir.
 
@@ -7627,14 +7618,6 @@
 <translation id="802776363472387903"><ph name="PLUGIN_VM_NAME" /> resminin SHA-256 karması.</translation>
 <translation id="8028814157747157754">Varsayılan arama sağlayıcısını etkinleştir ve kullanıcıların arama sağlayıcısı listesini değiştirmesine izin ver</translation>
 <translation id="8029201909194194377">Uzaktan erişim bağlantıları için izin verilen maksimum oturum süresi</translation>
-<translation id="8032201191311129122">Bu politika, belirli URL'lerdeki verilerin panoya kopyalanmasını engeller.
-
-      <ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> ve <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> URL listeleri, hangi sitelerin panoya yazmasına izin verildiğini kontrol eder. URL, "etkinleştir" seçeneğindeki bir kalıpla eşleşiyor ancak "devre dışı bırak" seçeneğindeki bir kalıpla eşleşmiyorsa panoya yazma engellenir. URL hiçbir kalıpla eşleşmiyorsa kopyalama işlemi engellenmez.
-
-      Kaynakları eşleşen kalıplar, http://www.chromium.org/administrators/url-blocklist-filter-format adresinde bulabileceğiniz "<ph name="URL_BLOCKLIST_POLICY_NAME" />" politikasıyla benzer bir biçimi kullanır.
-
-      <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" />, kalıp kontrolünü tetikleyen bayt cinsinden minimum veri miktarını gösterir. Bu da kopyalanan verilerin boyutunun bu alanda belirtilen değerden küçük olması halinde, engellenen bir URL'den panoya yazmaya izin verileceği anlamına gelir. Alan ayarlanmadan bırakılırsa varsayılan değer 100 bayttır.
-      </translation>
 <translation id="8033908599068513676">İndirilecek donanım yazılımı görüntüsünün URL'si.</translation>
 <translation id="8035570672225663428">Uyarlanabilir şarj modelinin, pil ömrünü uzatmak için şarj sürecini geçici olarak durdurmasına izin ver</translation>
 <translation id="8044493735196713914">Rapor cihazı önyükleme modu</translation>
diff --git a/components/policy/resources/policy_templates_uk.xtb b/components/policy/resources/policy_templates_uk.xtb
index 78eb3902..16c37c43 100644
--- a/components/policy/resources/policy_templates_uk.xtb
+++ b/components/policy/resources/policy_templates_uk.xtb
@@ -533,15 +533,6 @@
 
       У версії M94 це правило вилучено.</translation>
 <translation id="1507373253059695424">Завжди вмикати функцію "Екран конфіденційності" на екрані входу</translation>
-<translation id="150857982247452081">Дає змогу налаштувати список протоколів, а для кожного протоколу – зв'язаний список дозволених шаблонів джерел, які можуть запускати зовнішні додатки без відома користувачів. Після назви протоколу не потрібно додавати роздільник, наприклад указуйте "skype", а не "skype:" чи "skype://".
-
-      Якщо це правило налаштовано, протокол зможе запускати зовнішні додатки без відома користувачів, лише якщо він є в списку, а джерело сайту, який намагається запустити протокол, збігається з одним із шаблонів джерел у списку allowed_origins для цього протоколу. Якщо принаймні одну умову не виконано, правило не дозволить запуск зовнішніх протоколів.
-
-      Якщо це правило не налаштовано, за умовчанням протоколи не можуть запускати додатки без запиту. Користувачі зможуть вимикати сповіщення для окремих протоколів чи сайтів (якщо не вимкнено <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" />). Це правило не впливає на винятки для окремих протоколів чи сайтів, які вказали користувачі.
-
-      Шаблони джерел указуються приблизно в тому ж форматі, що й для чорного списку <ph name="URL_BLOCKLIST_POLICY_NAME" /> (див. http://www.chromium.org/administrators/url-blocklist-filter-format).
-
-      Проте вони не можуть містити елементи "/path" або "@query". Шаблони з елементами "/path" або "@query" ігноруватимуться.</translation>
 <translation id="1508588104835702000">Вимкнути хмарне звітування для керованих веб-переглядачів</translation>
 <translation id="1509377996969000672">Це правило визначає налаштування принтерів підприємства, які зв'язані з пристроями. Його формат збігається зі словником <ph name="NATIVE_PRINTERS_POLICY_NAME" />, але з обов'язковим полем "id" або "guid" для кожного принтера, який додається в білий чи чорний список. Файл має бути у форматі JSON, а його розмір не може перевищувати 5 МБ. Файл розміром 5 МБ містить приблизно 21 000 принтерів. Криптографічний хеш допомагає перевірити цілісність завантаження. Файл завантажується й додається в кеш. Коли URL-адреса або хеш змінюються, файл завантажується повторно. <ph name="PRODUCT_OS_NAME" /> завантажує файл для налаштування принтерів і надає доступ до принтерів відповідно до правил <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />, <ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" /> та <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" />.
 
@@ -7576,14 +7567,6 @@
 <translation id="802776363472387903">Хеш SHA-256 для образу <ph name="PLUGIN_VM_NAME" />.</translation>
 <translation id="8028814157747157754">Увімкнути пошуковий сервіс за умовчанням і дозволити користувачам змінювати список пошукових сервісів</translation>
 <translation id="8029201909194194377">Максимальна дозволена тривалість сеансу віддаленого доступу</translation>
-<translation id="8032201191311129122">Це правило забороняє копіювати дані в буфер обміну за вказаними URL-адресами.
-
-      Списки URL-адрес у полях <ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> і <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> указують, яким сайтам можна записувати дані в буфер обміну. Запис у буфер заборонено, якщо URL-адреса відповідає шаблону в полі enable і не збігається із шаблоном у полі disable. Копіювання не заборонено, якщо URL-адреса не відповідає жодному шаблону.
-
-      Шаблони джерел указуються приблизно в тому ж форматі, що й для чорного списку <ph name="URL_BLOCKLIST_POLICY_NAME" /> (див. http://www.chromium.org/administrators/url-blocklist-filter-format).
-
-      У полі <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" /> указано мінімальний обсяг даних (у байтах), через який активується зіставлення з шаблоном. Тобто запис у буфер обміну із заблокованої URL-адреси буде дозволено, якщо розмір скопійованих даних менший за значення, указане в цьому полі. Якщо це поле не налаштувати, використовується значення за умовчанням 100 байт.
-      </translation>
 <translation id="8033908599068513676">URL-адреса образу мікропрограми, який потрібно завантажити.</translation>
 <translation id="8035570672225663428">Увімкнути модель адаптивного заряджання, щоб призупиняти заряджання та подовжувати час роботи акумулятора</translation>
 <translation id="8044493735196713914">Повідомляти про режим завантаження пристрою</translation>
diff --git a/components/policy/resources/policy_templates_vi.xtb b/components/policy/resources/policy_templates_vi.xtb
index 26b328a..36694119 100644
--- a/components/policy/resources/policy_templates_vi.xtb
+++ b/components/policy/resources/policy_templates_vi.xtb
@@ -534,15 +534,6 @@
 
       Chúng tôi đã xóa chính sách này trong phiên bản M94.</translation>
 <translation id="1507373253059695424">Luôn bật tính năng màn hình bảo vệ quyền riêng tư trên màn hình đăng nhập</translation>
-<translation id="150857982247452081">Cho phép bạn thiết lập danh sách các giao thức (và danh sách liên kết gồm các mẫu nguồn được phép cho mỗi giao thức) có thể chạy một ứng dụng bên ngoài mà không cần nhắc người dùng. Bạn không được thêm dấu phân cách ở phần cuối khi liệt kê giao thức, vì vậy, hãy liệt kê là "skype" thay cho "skype:" hoặc "skype://".
-
-      Nếu bạn đặt chính sách này, thì một giao thức sẽ chỉ được phép chạy một ứng dụng bên ngoài mà không cần nhắc theo chính sách khi giao thức đó được liệt kê, và nguồn của trang web đang cố chạy giao thức khớp với một trong các mẫu nguồn thuộc danh sách allowed_origins của giao thức đó. Nếu bạn đặt một trong hai điều kiện thành tắt, thì chính sách sẽ không bỏ qua lời nhắc chạy giao thức bên ngoài.
-
-      Nếu bạn không đặt chính sách này, thì không giao thức nào có thể chạy khi không có lời nhắc theo mặc định. Người dùng có thể chọn không nhận lời nhắc theo từng giao thức/từng trang web trừ trường hợp bạn đặt chính sách <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" /> thành Tắt. Chính sách này sẽ không ảnh hưởng đến các trường hợp miễn trừ theo từng giao thức/từng trang web do người dùng đặt.
-
-      Mẫu so khớp nguồn sẽ có định dạng giống với các mẫu của chính sách "<ph name="URL_BLOCKLIST_POLICY_NAME" />" nêu tại http://www.chromium.org/administrators/url-blocklist-filter-format.
-
-      Tuy nhiên, các mẫu so khớp nguồn của chính sách này không được chứa các thành phần "/path" hoặc "@query". Mọi mẫu chứa thành phần "/path" hoặc "@query" đều bị bỏ qua.</translation>
 <translation id="1508588104835702000">Tắt tính năng báo cáo trên đám mây qua trình duyệt được quản lý</translation>
 <translation id="1509377996969000672">Việc đặt chính sách này sẽ cung cấp các cấu hình máy in dành cho doanh nghiệp được kết nối với các thiết bị. Định dạng của chính sách khớp với định dạng của từ điển <ph name="NATIVE_PRINTERS_POLICY_NAME" />, có thêm trường "id" hoặc "guid" bắt buộc trên từng máy in để đưa vào danh sách cho phép hoặc danh sách cấm. Kích thước tệp không được vượt quá 5 MB và phải ở định dạng JSON. Một tệp có khoảng 21.000 máy in sẽ mã hóa dưới dạng tệp 5 MB. Hàm băm mật mã giúp xác minh tính toàn vẹn của tệp tải xuống. Tệp này được tải xuống, lưu vào bộ nhớ đệm và tải lại xuống khi URL hoặc hàm băm thay đổi. <ph name="PRODUCT_OS_NAME" /> tải tệp này xuống để định cấu hình máy in và cung cấp các máy in theo đúng <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />, <ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" />, và <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" />.
 
@@ -7665,14 +7656,6 @@
 <translation id="802776363472387903">Hàm băm SHA-256 của hình ảnh <ph name="PLUGIN_VM_NAME" />.</translation>
 <translation id="8028814157747157754">Bật nhà cung cấp dịch vụ tìm kiếm mặc định và cho phép người dùng sửa đổi danh sách nhà cung cấp dịch vụ tìm kiếm</translation>
 <translation id="8029201909194194377">Thời lượng phiên tối đa được phép cho các kết nối truy cập từ xa</translation>
-<translation id="8032201191311129122">Chính sách này chặn việc sao chép dữ liệu vào khay nhớ tạm đối với các URL cụ thể.
-
-       Các danh sách URL <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> và <ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> kiểm soát việc trang web nào được phép ghi vào khay nhớ tạm. Việc ghi dữ liệu vào khay nhớ tạm sẽ bị chặn nếu URL khớp với một mẫu trong "enable" và không khớp với một mẫu trong "disable". Bản sao sẽ không bị chặn nếu URL không khớp với bất kỳ mẫu nào.
-
-      Mẫu so khớp nguồn sẽ có định dạng giống với các mẫu của chính sách "<ph name="URL_BLOCKLIST_POLICY_NAME" />" được nêu tại http://www.chromium.org/administrators/url-blocklist-filter-format.
-
-      Trường <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" /> cho biết lượng dữ liệu tối thiểu tính bằng byte sẽ kích hoạt quá trình kiểm tra mẫu. Điều này có nghĩa là một URL bị chặn sẽ được phép ghi dữ liệu vào khay nhớ tạm nếu kích thước của dữ liệu được sao chép nhỏ hơn giá trị được chỉ định trong trường này. Giá trị mặc định là 100 byte nếu bạn không đặt trường này.
-      </translation>
 <translation id="8033908599068513676">URL của hình ảnh chương trình cơ sở sẽ tải xuống.</translation>
 <translation id="8035570672225663428">Bật mô hình sạc thích ứng để giữ quá trình sạc nhằm kéo dài thời lượng pin</translation>
 <translation id="8044493735196713914">Báo cáo chế độ khởi động thiết bị</translation>
diff --git a/components/policy/resources/policy_templates_zh-CN.xtb b/components/policy/resources/policy_templates_zh-CN.xtb
index 2358d1b..ec856ff 100644
--- a/components/policy/resources/policy_templates_zh-CN.xtb
+++ b/components/policy/resources/policy_templates_zh-CN.xtb
@@ -531,15 +531,6 @@
 
       此政策已从 M94 中移除。</translation>
 <translation id="1507373253059695424">始终为登录屏幕启用隐私保护屏幕</translation>
-<translation id="150857982247452081">让您能够设置一个协议列表,并为每份协议设置一个关联列表,包含允许的来源格式,使协议无需提示用户就能启动外部应用。罗列协议时不应添加结尾分隔符,因此请罗列“skype”而非“skype:”或“skype://”。
-
-      如果您设置了此政策,那么仅当满足以下条件时,相应协议才可依照政策在不提示用户的情况下启动外部应用:该协议包含在列表中,而且尝试启动该协议的网站的来源与该协议 allowed_origins 列表中的来源格式之一匹配。如果相应协议不满足上述任一条件,系统将不会依照此政策跳过外部协议启动提示。
-
-      如果此政策未设置,那么在默认情况下,倘若系统不提示用户,任何协议都无法启动。用户可以针对个别协议/网站选择不接收提示,除非 <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" /> 政策设为“已停用”。对于用户针对个别协议/网站指定的不接收提示设置,此政策不会产生任何影响。
-
-      用于与来源进行匹配的网址格式和“<ph name="URL_BLOCKLIST_POLICY_NAME" />”政策中设置的网址格式类似,详见 http://www.chromium.org/administrators/url-blocklist-filter-format。
-
-      不过,此政策中用于与来源进行匹配的网址格式不能包含“/path”或“@query”元素。系统会忽略所有包含“/path”或“@query”元素的网址格式。</translation>
 <translation id="1508588104835702000">为受管理浏览器停用云报告功能</translation>
 <translation id="1509377996969000672">通过设置此政策,您可为绑定到设备的企业打印机提供配置。其格式与 <ph name="NATIVE_PRINTERS_POLICY_NAME" /> 字典一样,不过每台打印机都还对应一个额外的必填字段“id”或“guid”,以用于将相应打印机加入许可名单/拒绝名单。该文件不得超过 5MB,且必须采用 JSON 格式。一个包含大约 21000 台打印机的文件在编码后的大小是 5MB。相应的加密哈希值可帮助您验证下载内容的完整性。系统会下载、缓存该文件。当相应网址或哈希值发生变化时,系统会重新下载该文件。<ph name="PRODUCT_OS_NAME" />会下载该文件以获取打印机配置,并会根据 <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />、<ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" /> 和 <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" /> 向用户提供可用的打印机。
 
@@ -7510,14 +7501,6 @@
 <translation id="802776363472387903"><ph name="PLUGIN_VM_NAME" /> 图片的 SHA-256 哈希值。</translation>
 <translation id="8028814157747157754">启用默认搜索服务提供商并允许用户修改搜索服务提供商列表</translation>
 <translation id="8029201909194194377">远程访问连接可达到的会话时长上限</translation>
-<translation id="8032201191311129122">此政策用于禁止特定网址向剪贴板中复制数据。
-
-      <ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> 和 <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> 网址列表用于控制允许哪些网站向剪贴板中写入内容。如果相应网址与“enable”中的格式相匹配,但不与“disable”中的格式相匹配,系统将会禁止该网址向剪贴板中写入内容。如果相应网址不与任何格式相匹配,系统将不会禁止该网址向剪贴板中复制内容。
-
-      用于与来源进行匹配的网址格式和“<ph name="URL_BLOCKLIST_POLICY_NAME" />”政策中设置的网址格式类似,详见 http://www.chromium.org/administrators/url-blocklist-filter-format。
-
-      <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" /> 用于指明会触发网址格式检查的最少数据量(以字节为单位)。这意味着,如果所复制数据的大小小于此字段中指定的值,系统将允许被禁网址向剪贴板中写入数据。如果该字段未设置,默认值为 100 字节。
-      </translation>
 <translation id="8033908599068513676">要下载的固件映像的网址。</translation>
 <translation id="8035570672225663428">启用“自适应充电”模式以暂缓充电进程,进而延长电池寿命</translation>
 <translation id="8044493735196713914">报告设备引导模式</translation>
diff --git a/components/policy/resources/policy_templates_zh-TW.xtb b/components/policy/resources/policy_templates_zh-TW.xtb
index 9a81b9d..c77498fe 100644
--- a/components/policy/resources/policy_templates_zh-TW.xtb
+++ b/components/policy/resources/policy_templates_zh-TW.xtb
@@ -528,15 +528,6 @@
 
       這項政策已在 M94 版中遭到移除。</translation>
 <translation id="1507373253059695424">在登入畫面上一律啟用隱私保護功能</translation>
-<translation id="150857982247452081">你可以透過這項政策設定一組通訊協定清單,並且為每個通訊協定設定相關聯的允許來源格式清單,清單中的通訊協定無須提示使用者即可啟動外部應用程式。列出通訊協定時,請勿加入結尾分隔符;換句話說,請列出「skype」,而非「skype:」或「skype://」。
-
-      如果設定這項政策,只有當通訊協定已列於清單中,且嘗試啟動通訊協定的網站來源符合該通訊協定 allowed_origins 清單中的其中一個來源格式時,系統才會依照政策規定,允許通訊協定在不提示使用者的情況下啟動外部應用程式。只要有任一條件不符,系統就不會依照政策規定省略外部通訊協定啟動提示。
-
-      在預設狀態下,如未設定這項政策,則系統在啟動任何通訊協定之前,一律必須先提示使用者。除非 <ph name="EXTERNAL_PROTOCOL_DIALOG_SHOW_ALWAYS_OPEN_CHECKBOX_POLICY_NAME" /> 政策已設為「停用」,否則使用者可以選擇不接收個別通訊協定或網站的提示,而且使用者的設定不會受到這項政策的影響。
-
-      來源比對格式與 <ph name="URL_BLOCKLIST_POLICY_NAME" /> 政策使用的格式類似,請見以下頁面說明:http://www.chromium.org/administrators/url-blocklist-filter-format。
-
-      不過,這項政策的來源比對格式不能包含「/path」或「@query」元素。系統會忽略所有包含「/path」或「@query」元素的格式。</translation>
 <translation id="1508588104835702000">停用受管理瀏覽器的雲端報告功能</translation>
 <translation id="1509377996969000672">你可以透過這項政策設定已連接到裝置的企業印表機。其格式與 <ph name="NATIVE_PRINTERS_POLICY_NAME" /> 條目相符,且針對每台印表機另外設有「id」或「guid」必填欄位,用於指明要加入許可清單或拒絕清單。相關檔案大小不得超過 5 MB,且必須採用 JSON 格式。一個 5 MB 的編碼檔案可包含約 21,000 台印表機的資料。加密編譯雜湊的作用是驗證下載內容的完整性。系統會下載及快取這個檔案,而且只要網址或雜湊一有變動,就會重新下載檔案。<ph name="PRODUCT_OS_NAME" />會下載這個檔案來設定印表機,並依據 <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" />、<ph name="DEVICE_PRINTERS_ALLOWLIST_POLICY_NAME" /> 和 <ph name="DEVICE_PRINTERS_BLOCKLIST_POLICY_NAME" /> 開放使用印表機。
 
@@ -7440,14 +7431,6 @@
 <translation id="802776363472387903"><ph name="PLUGIN_VM_NAME" /> 圖片的 SHA-256 雜湊值。</translation>
 <translation id="8028814157747157754">啟用預設搜尋引擎,並允許使用者修改搜尋引擎清單</translation>
 <translation id="8029201909194194377">遠端存取連線所允許的工作階段持續時間上限</translation>
-<translation id="8032201191311129122">這項規則設定可禁止在特定網址上將資料複製到剪貼簿。
-
-      <ph name="ENTERPRISE_CONNECTOR_ENABLE_FIELD" /> 和 <ph name="ENTERPRISE_CONNECTOR_DISABLE_FIELD" /> 網址清單會控管哪些網站允許寫入剪貼簿。如果網址符合「啟用」中的模式,且不符合「停用」中的模式,系統會禁止剪貼簿寫入功能。當網址不符合任何模式時,系統則不會禁止複製功能。
-
-      來源比對模式與「<ph name="URL_BLOCKLIST_POLICY_NAME" />」規則設定使用的格式類似,請參考以下頁面說明:http://www.chromium.org/administrators/url-blocklist-filter-format。
-
-      <ph name="ENTERPRISE_CONNECTOR_MINIMUM_DATA_SIZE" /> 代表可觸發模式比對的最低資料量 (以位元組為單位)。也就是說,如果複製的資料大小小於這個欄位中指定的值,系統就會允許已封鎖的網址寫入剪貼簿。如果不設定這個欄位,預設值為 100 個位元組。
-      </translation>
 <translation id="8033908599068513676">韌體映像檔的下載網址。</translation>
 <translation id="8035570672225663428">啟用自動調節充電模式,調整充電速度以延長電池壽命</translation>
 <translation id="8044493735196713914">回報裝置啟動模式</translation>
diff --git a/components/query_tiles/internal/tile_service_impl.cc b/components/query_tiles/internal/tile_service_impl.cc
index 109eded..a9206e7 100644
--- a/components/query_tiles/internal/tile_service_impl.cc
+++ b/components/query_tiles/internal/tile_service_impl.cc
@@ -94,7 +94,7 @@
     if (parse_success) {
       TileGroup group;
       TileGroupFromResponse(response_proto, &group);
-      group.id = base::GenerateUuid();
+      group.id = base::Uuid::GenerateRandomV4().AsLowercaseString();
       group.last_updated_ts = clock_->Now();
       auto group_copy = std::make_unique<TileGroup>(group);
       tile_manager_->SaveTiles(
diff --git a/components/remote_cocoa/app_shim/mouse_capture.h b/components/remote_cocoa/app_shim/mouse_capture.h
index cecf0cfe..a5b3931c 100644
--- a/components/remote_cocoa/app_shim/mouse_capture.h
+++ b/components/remote_cocoa/app_shim/mouse_capture.h
@@ -5,18 +5,14 @@
 #ifndef COMPONENTS_REMOTE_COCOA_APP_SHIM_MOUSE_CAPTURE_H_
 #define COMPONENTS_REMOTE_COCOA_APP_SHIM_MOUSE_CAPTURE_H_
 
+#import <Cocoa/Cocoa.h>
+
 #include <memory>
 
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "components/remote_cocoa/app_shim/remote_cocoa_app_shim_export.h"
 
-#if defined(__OBJC__)
-@class NSWindow;
-#else
-class NSWindow;
-#endif
-
 namespace remote_cocoa {
 
 class CocoaMouseCaptureDelegate;
diff --git a/components/remote_cocoa/app_shim/mouse_capture_delegate.h b/components/remote_cocoa/app_shim/mouse_capture_delegate.h
index b2bf1b7..836fc53a 100644
--- a/components/remote_cocoa/app_shim/mouse_capture_delegate.h
+++ b/components/remote_cocoa/app_shim/mouse_capture_delegate.h
@@ -5,13 +5,7 @@
 #ifndef COMPONENTS_REMOTE_COCOA_APP_SHIM_MOUSE_CAPTURE_DELEGATE_H_
 #define COMPONENTS_REMOTE_COCOA_APP_SHIM_MOUSE_CAPTURE_DELEGATE_H_
 
-#if defined(__OBJC__)
-@class NSEvent;
-@class NSWindow;
-#else
-class NSEvent;
-class NSWindow;
-#endif
+#import <Cocoa/Cocoa.h>
 
 namespace remote_cocoa {
 
diff --git a/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service.cc b/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service.cc
index ee933d5..62c84c8 100644
--- a/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service.cc
+++ b/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service.cc
@@ -363,7 +363,7 @@
     HPRTLookupResponseCallback response_callback,
     SBThreatType locally_cached_results_threat_type,
     absl::optional<std::string> key) {
-  // TODO(crbug.com/1407283): Add a histogram to log the key fetch result.
+  base::UmaHistogramBoolean("SafeBrowsing.HPRT.HasOhttpKey", key.has_value());
   if (!key.has_value()) {
     backoff_operator_->ReportError();
     response_callback_task_runner->PostTask(
diff --git a/components/safe_browsing/core/browser/hashprefix_realtime/ohttp_key_service.cc b/components/safe_browsing/core/browser/hashprefix_realtime/ohttp_key_service.cc
index cc5482a..42dd1f78 100644
--- a/components/safe_browsing/core/browser/hashprefix_realtime/ohttp_key_service.cc
+++ b/components/safe_browsing/core/browser/hashprefix_realtime/ohttp_key_service.cc
@@ -4,10 +4,12 @@
 
 #include "components/safe_browsing/core/browser/hashprefix_realtime/ohttp_key_service.h"
 
+#include "base/metrics/histogram_functions.h"
 #include "base/rand_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/safe_browsing/core/browser/utils/backoff_operator.h"
 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
+#include "components/safe_browsing/core/common/utils.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_status_code.h"
@@ -164,7 +166,10 @@
   }
 
   // If there is a valid key in memory, use it directly.
-  if (ohttp_key_ && ohttp_key_->expiration > base::Time::Now()) {
+  bool has_cache_key = ohttp_key_ && ohttp_key_->expiration > base::Time::Now();
+  base::UmaHistogramBoolean("SafeBrowsing.HPRT.OhttpKeyService.HasCachedKey",
+                            has_cache_key);
+  if (has_cache_key) {
     std::move(callback).Run(ohttp_key_->key);
     return;
   }
@@ -217,7 +222,10 @@
 }
 
 void OhttpKeyService::StartFetch(Callback callback) {
-  if (backoff_operator_->IsInBackoffMode()) {
+  bool in_backoff = backoff_operator_->IsInBackoffMode();
+  base::UmaHistogramBoolean("SafeBrowsing.HPRT.OhttpKeyService.BackoffState",
+                            in_backoff);
+  if (in_backoff) {
     std::move(callback).Run(absl::nullopt);
     return;
   }
@@ -239,22 +247,28 @@
   url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
       url_loader_factory_.get(),
       base::BindOnce(&OhttpKeyService::OnURLLoaderComplete,
-                     weak_factory_.GetWeakPtr()));
+                     weak_factory_.GetWeakPtr(), base::TimeTicks::Now()));
 }
 
 void OhttpKeyService::OnURLLoaderComplete(
+    base::TimeTicks request_start_time,
     std::unique_ptr<std::string> response_body) {
-  // TODO(crbug.com/1407283): Log net error and response code.
   DCHECK(url_loader_);
+  int net_error = url_loader_->NetError();
   int response_code = 0;
   if (url_loader_->ResponseInfo() && url_loader_->ResponseInfo()->headers) {
     response_code = url_loader_->ResponseInfo()->headers->response_code();
   }
-  bool is_key_fetch_successful = response_body &&
-                                 url_loader_->NetError() == net::OK &&
-                                 response_code == net::HTTP_OK;
+
+  base::UmaHistogramTimes("SafeBrowsing.HPRT.OhttpKeyService.Network.Time",
+                          base::TimeTicks::Now() - request_start_time);
+  RecordHttpResponseOrErrorCode(
+      "SafeBrowsing.HPRT.OhttpKeyService.Network.Result", net_error,
+      response_code);
 
   url_loader_.reset();
+  bool is_key_fetch_successful =
+      response_body && net_error == net::OK && response_code == net::HTTP_OK;
   if (is_key_fetch_successful) {
     ohttp_key_ = {*response_body, base::Time::Now() + kKeyExpirationDuration};
     StoreKeyToPref();
diff --git a/components/safe_browsing/core/browser/hashprefix_realtime/ohttp_key_service.h b/components/safe_browsing/core/browser/hashprefix_realtime/ohttp_key_service.h
index 3e7fc563..264f55b 100644
--- a/components/safe_browsing/core/browser/hashprefix_realtime/ohttp_key_service.h
+++ b/components/safe_browsing/core/browser/hashprefix_realtime/ohttp_key_service.h
@@ -91,7 +91,8 @@
 
   // Called when the response from the Safe Browsing key hosting endpoint is
   // received.
-  void OnURLLoaderComplete(std::unique_ptr<std::string> response_body);
+  void OnURLLoaderComplete(base::TimeTicks request_start_time,
+                           std::unique_ptr<std::string> response_body);
 
   // Async workflow:
   // Starts to fetch a new key if the current key is close to expiration.
diff --git a/components/services/app_service/public/cpp/app_types.cc b/components/services/app_service/public/cpp/app_types.cc
index 27826a6..b8ceb11 100644
--- a/components/services/app_service/public/cpp/app_types.cc
+++ b/components/services/app_service/public/cpp/app_types.cc
@@ -32,7 +32,7 @@
                    kTerminated,
                    kUninstalledByUser,
                    kRemoved,
-                   kUninstalledByMigration)
+                   kUninstalledByNonUser)
 APP_ENUM_TO_STRING(InstallReason,
                    kUnknown,
                    kSystem,
diff --git a/components/services/app_service/public/cpp/app_types.h b/components/services/app_service/public/cpp/app_types.h
index 67586b92..120a957 100644
--- a/components/services/app_service/public/cpp/app_types.h
+++ b/components/services/app_service/public/cpp/app_types.h
@@ -60,7 +60,8 @@
      // apps, so publishers must set the app as uninstalled before
      // removing it.
      kRemoved,
-     kUninstalledByMigration)
+     // This is used for all non-user initiated uninstallation.
+     kUninstalledByNonUser)
 
 // How the app was installed.
 // This should be kept in sync with histograms.xml, InstallReason in
diff --git a/components/services/app_service/public/cpp/types_util.cc b/components/services/app_service/public/cpp/types_util.cc
index e374d2d2a..6f681171 100644
--- a/components/services/app_service/public/cpp/types_util.cc
+++ b/components/services/app_service/public/cpp/types_util.cc
@@ -16,7 +16,7 @@
     case apps::Readiness::kTerminated:
       return true;
     case apps::Readiness::kUninstalledByUser:
-    case apps::Readiness::kUninstalledByMigration:
+    case apps::Readiness::kUninstalledByNonUser:
     case apps::Readiness::kRemoved:
     case apps::Readiness::kUnknown:
       return false;
diff --git a/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc b/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc
index dc0282a..3efb18f8 100644
--- a/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc
+++ b/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc
@@ -69,8 +69,8 @@
   mojo::PendingRemote<font_service::mojom::FontService> font_service;
   content::UtilityThread::Get()->BindHostReceiver(
       font_service.InitWithNewPipeAndPassReceiver());
-  font_loader_ = sk_make_sp<font_service::FontLoader>(std::move(font_service));
-  SkFontConfigInterface::SetGlobal(font_loader_);
+  SkFontConfigInterface::SetGlobal(
+      sk_make_sp<font_service::FontLoader>(std::move(font_service)));
 #endif
   // TODO(crbug/1023377): Determine if EnsureBlinkInitialized*() does any other
   // initialization we require. Possibly for other platforms (e.g. MacOS,
diff --git a/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.h b/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.h
index b80336a..9d31d10 100644
--- a/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.h
+++ b/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.h
@@ -21,11 +21,6 @@
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-#include "components/services/font/public/cpp/font_loader.h"
-#include "third_party/skia/include/core/SkRefCnt.h"
-#endif
-
 namespace discardable_memory {
 class ClientDiscardableSharedMemoryManager;
 }
@@ -73,10 +68,6 @@
                  std::unique_ptr<PaintPreviewCompositorImpl>>
       compositors_;
 
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-  sk_sp<font_service::FontLoader> font_loader_;
-#endif
-
   const bool initialize_environment_;
 
   // Ensure the discardable memory manager is the last thing to get destructed.
diff --git a/components/strings/components_strings_af.xtb b/components/strings/components_strings_af.xtb
index 5ef862e..5e1e1ec 100644
--- a/components/strings/components_strings_af.xtb
+++ b/components/strings/components_strings_af.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Gebruik Windows Hello om jou aankoop te verifieer en te voltooi?</translation>
 <translation id="5701381305118179107">Sentreer</translation>
 <translation id="570530837424789914">Bestuur …</translation>
-<translation id="5706906618852913030">Stoor in rekening?</translation>
 <translation id="5707154300732650394">Hervat jou reis</translation>
 <translation id="57094364128775171">Stel sterk wagwoord voor …</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_am.xtb b/components/strings/components_strings_am.xtb
index 2a49d66..7c7f83b1 100644
--- a/components/strings/components_strings_am.xtb
+++ b/components/strings/components_strings_am.xtb
@@ -1918,7 +1918,6 @@
 <translation id="5695542892312572833">ግዢዎን ለማረጋገጥ እና ለማጠናቀቅ Windowsን ይጠቀሙ?</translation>
 <translation id="5701381305118179107">መሃከል</translation>
 <translation id="570530837424789914">ያቀናብሩ...</translation>
-<translation id="5706906618852913030">በመለያ ውስጥ ይቀመጥ?</translation>
 <translation id="5707154300732650394">ጉዞዎን ከቆመበት ይቀጥሉ</translation>
 <translation id="57094364128775171">ጠንካራ የይለፍ ቃል ጠቁም...</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_ar.xtb b/components/strings/components_strings_ar.xtb
index 567c2c6c..c2561c064 100644
--- a/components/strings/components_strings_ar.xtb
+++ b/components/strings/components_strings_ar.xtb
@@ -1923,7 +1923,6 @@
 <translation id="5695542892312572833">‏هل تريد استخدام Windows Hello لإثبات صحة عملية الشراء وإكمالها؟</translation>
 <translation id="5701381305118179107">توسيط</translation>
 <translation id="570530837424789914">إدارة...</translation>
-<translation id="5706906618852913030">‏هل تريد الحفظ في حسابك على Google؟</translation>
 <translation id="5707154300732650394">استئناف سجلّ أنشطة البحث والتصفُّح</translation>
 <translation id="57094364128775171">اقتراح كلمة مرور قوية…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_as.xtb b/components/strings/components_strings_as.xtb
index 104aa1ec..def59df 100644
--- a/components/strings/components_strings_as.xtb
+++ b/components/strings/components_strings_as.xtb
@@ -1915,7 +1915,6 @@
 <translation id="5695542892312572833">আপোনাৰ ক্ৰয়টো সত্যাপন আৰু সম্পূৰ্ণ কৰিবলৈ Windows Hello ব্যৱহাৰ কৰিবনে?</translation>
 <translation id="5701381305118179107">কেন্দ্ৰ</translation>
 <translation id="570530837424789914">পৰিচালনা কৰক...</translation>
-<translation id="5706906618852913030">একাউণ্টত ছেভ কৰিবনে?</translation>
 <translation id="5707154300732650394">আপোনাৰ যাত্ৰা পুনৰ আৰম্ভ কৰক</translation>
 <translation id="57094364128775171">জটিল পাছৱৰ্ডৰ পৰামৰ্শ দিয়ক…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_az.xtb b/components/strings/components_strings_az.xtb
index d70514f..c55acb0d 100644
--- a/components/strings/components_strings_az.xtb
+++ b/components/strings/components_strings_az.xtb
@@ -1915,7 +1915,6 @@
 <translation id="5695542892312572833">Doğrulamaq və alışı tamamlamaq üçün Windows Hello istifadə edilsin?</translation>
 <translation id="5701381305118179107">Mərkəzi edin</translation>
 <translation id="570530837424789914">İdarə edin...</translation>
-<translation id="5706906618852913030">Hesabda yadda saxlansın?</translation>
 <translation id="5707154300732650394">Baxışı davam etdirin</translation>
 <translation id="57094364128775171">Güclü parol təklif edin…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_be.xtb b/components/strings/components_strings_be.xtb
index 8d01ad89..902c99c 100644
--- a/components/strings/components_strings_be.xtb
+++ b/components/strings/components_strings_be.xtb
@@ -1918,7 +1918,6 @@
 <translation id="5695542892312572833">Пацвердзіць і завяршыць куплю з дапамогай Windows Hello?</translation>
 <translation id="5701381305118179107">У цэнтры</translation>
 <translation id="570530837424789914">Кіраваць...</translation>
-<translation id="5706906618852913030">Захаваць ва ўліковым запісе?</translation>
 <translation id="5707154300732650394">Працягнуць пошук</translation>
 <translation id="57094364128775171">Прапанаваць надзейны пароль…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_bg.xtb b/components/strings/components_strings_bg.xtb
index c41fb21..abcafe2 100644
--- a/components/strings/components_strings_bg.xtb
+++ b/components/strings/components_strings_bg.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Искате ли да използвате Windows Hello, за да потвърдите и завършите покупката си?</translation>
 <translation id="5701381305118179107">Центриране</translation>
 <translation id="570530837424789914">Управление...</translation>
-<translation id="5706906618852913030">Да се запази ли в профила?</translation>
 <translation id="5707154300732650394">Възобновяване на пътешествието</translation>
 <translation id="57094364128775171">Предложение за надеждна парола…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_bn.xtb b/components/strings/components_strings_bn.xtb
index dd27839..bf3e072 100644
--- a/components/strings/components_strings_bn.xtb
+++ b/components/strings/components_strings_bn.xtb
@@ -1920,7 +1920,6 @@
 <translation id="5695542892312572833">আপনার কেনাকাটা যাচাই করা ও তা সম্পূর্ণ করার জন্য Windows Hello-এর সেন্সর ব্যবহার করতে চান?</translation>
 <translation id="5701381305118179107">কেন্দ্র</translation>
 <translation id="570530837424789914">পরিচালনা করুন...</translation>
-<translation id="5706906618852913030">অ্যাকাউন্টে সেভ করবেন?</translation>
 <translation id="5707154300732650394">আপনার ব্রাউজার অ্যাক্টিভিটি আবার চালু করুন</translation>
 <translation id="57094364128775171">শক্তিশালী পাসওয়ার্ড সাজেস্ট করুন…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_bs.xtb b/components/strings/components_strings_bs.xtb
index c6f9aff..d62c04b9 100644
--- a/components/strings/components_strings_bs.xtb
+++ b/components/strings/components_strings_bs.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Potvrditi i završiti kupovinu koristeći Windows Hello?</translation>
 <translation id="5701381305118179107">Sredina</translation>
 <translation id="570530837424789914">Upravljajte…</translation>
-<translation id="5706906618852913030">Sačuvati na račun?</translation>
 <translation id="5707154300732650394">Nastavite iskustvo pregledanja</translation>
 <translation id="57094364128775171">Predloži jaku lozinku…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_ca.xtb b/components/strings/components_strings_ca.xtb
index 956265e..8c0ab618 100644
--- a/components/strings/components_strings_ca.xtb
+++ b/components/strings/components_strings_ca.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Vols fer servir Windows Hello per verificar la teva identitat i completar la compra?</translation>
 <translation id="5701381305118179107">Centre</translation>
 <translation id="570530837424789914">Gestiona...</translation>
-<translation id="5706906618852913030">La vols desar al compte?</translation>
 <translation id="5707154300732650394">Reprèn el recorregut</translation>
 <translation id="57094364128775171">Suggereix una contrasenya segura…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_cs.xtb b/components/strings/components_strings_cs.xtb
index 922590b..d5c3621 100644
--- a/components/strings/components_strings_cs.xtb
+++ b/components/strings/components_strings_cs.xtb
@@ -1789,6 +1789,7 @@
 <translation id="5344579389779391559">Tato stránka se vám může pokusit naúčtovat poplatky</translation>
 <translation id="5347645913823149105">Tlačítko přizpůsobení písem v Chromu. Stisknutím klávesy Enter si můžete přizpůsobit velikosti a typy písem v Chromu</translation>
 <translation id="5355557959165512791">Web <ph name="SITE" /> teď nemůžete navštívit, protože jeho certifikát byl zrušen. Síťové chyby a útoky jsou obvykle dočasné, tato stránka pravděpodobně později bude fungovat.</translation>
+<translation id="5356345925629253198">Uložené adresy můžete používat ve službách Google. Tato adresa bude uložena ve vašem účtu Google (<ph name="ACCOUNT" />).</translation>
 <translation id="5357848622083956825">Vizuální umění a design</translation>
 <translation id="536296301121032821">Ukládání nastavení zásady se nezdařilo</translation>
 <translation id="5363309033720083897">Sériový port je povolen administrátorem</translation>
@@ -1914,7 +1915,6 @@
 <translation id="5695542892312572833">Chcete nákup ověřit a dokončit pomocí Windows Hello?</translation>
 <translation id="5701381305118179107">Na střed</translation>
 <translation id="570530837424789914">Spravovat...</translation>
-<translation id="5706906618852913030">Uložit do účtu?</translation>
 <translation id="5707154300732650394">Pokračovat v cestě</translation>
 <translation id="57094364128775171">Navrhnout silné heslo…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_cy.xtb b/components/strings/components_strings_cy.xtb
index 4433ad0d..927c5d5 100644
--- a/components/strings/components_strings_cy.xtb
+++ b/components/strings/components_strings_cy.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Defnyddio Windows Hello i ddilysu a chwblhau eich pryniad?</translation>
 <translation id="5701381305118179107">Canoli</translation>
 <translation id="570530837424789914">Rheoli…</translation>
-<translation id="5706906618852913030">Cadw yn y Cyfrif</translation>
 <translation id="5707154300732650394">Parhau eich taith</translation>
 <translation id="57094364128775171">Awgrymu cyfrinair cryf…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_da.xtb b/components/strings/components_strings_da.xtb
index ee453ba..122a6d70 100644
--- a/components/strings/components_strings_da.xtb
+++ b/components/strings/components_strings_da.xtb
@@ -27,7 +27,7 @@
 <translation id="1043382569739532657">Bevillinger, legater og finansiel bistand</translation>
 <translation id="1048785276086539861">Når du redigerer annoteringer, skifter dette dokument tilbage til enkeltsidevisning</translation>
 <translation id="1050038467049342496">Luk andre apps</translation>
-<translation id="1053959602163383901">Du har valgt at bekræfte med en authenticator-enhed på websites, der anvender <ph name="PROVIDER_ORIGIN" />. Denne udbyder har muligvis gemt oplysninger om din betalingsmetode. Du kan <ph name="LINK_TEXT" /> af disse oplysninger.</translation>
+<translation id="1053959602163383901">Du har valgt at verificere med en authenticator-enhed på websites, der anvender <ph name="PROVIDER_ORIGIN" />. Denne udbyder har muligvis gemt oplysninger om din betalingsmetode. Du kan <ph name="LINK_TEXT" /> af disse oplysninger.</translation>
 <translation id="1055184225775184556">&amp;Fortryd tilføjelse</translation>
 <translation id="1056663316309890343">Fotosoftware</translation>
 <translation id="1056898198331236512">Advarsel</translation>
@@ -633,7 +633,7 @@
 <translation id="2512101340618156538">Ikke tilladt (standard)</translation>
 <translation id="2512413427717747692">Knappen Angiv Chrome som standardbrowser, tryk på Enter for at angive Chrome som systemets standardbrowser i iOS-indstillingerne</translation>
 <translation id="2515629240566999685">Tjekke signalet i dit område</translation>
-<translation id="2515761554693942801">Du har valgt at bekræfte med Touch ID på websites, der anvender <ph name="PROVIDER_ORIGIN" />. Denne udbyder har muligvis gemt oplysninger om din betalingsmetode. Du kan <ph name="LINK_TEXT" /> af disse oplysninger.</translation>
+<translation id="2515761554693942801">Du har valgt at verificere med Touch ID på websites, der anvender <ph name="PROVIDER_ORIGIN" />. Denne udbyder har muligvis gemt oplysninger om din betalingsmetode. Du kan <ph name="LINK_TEXT" /> af disse oplysninger.</translation>
 <translation id="2521385132275182522">Hæftning nederst til højre</translation>
 <translation id="2521736961081452453">Opret formular</translation>
 <translation id="2523886232349826891">Gemmes kun på denne enhed</translation>
@@ -670,7 +670,7 @@
 <translation id="2587841377698384444">Id for Directory API:</translation>
 <translation id="2594318783181750337">Hurtig webvisning:</translation>
 <translation id="2595719060046994702">Denne enhed og konto administreres ikke af et selskab eller en organisation.</translation>
-<translation id="2596415276201385844">For at kunne oprette en sikker forbindelse skal dit ur skal være indstillet korrekt. Det er vigtigt, da de certifikater, som websites bruger til at identificere sig selv, kun er gyldige i bestemte tidsperioder. Da uret på din enhed går forkert, kan Chrome ikke bekræfte disse certifikater.</translation>
+<translation id="2596415276201385844">For at kunne oprette en sikker forbindelse skal dit ur skal være indstillet korrekt. Det er vigtigt, da de certifikater, som websites bruger til at identificere sig selv, kun er gyldige i bestemte tidsperioder. Da uret på din enhed går forkert, kan Chrome ikke verificere disse certifikater.</translation>
 <translation id="2597378329261239068">Dette dokument er adgangskodebeskyttet. Angiv en adgangskode.</translation>
 <translation id="259821504105826686">Foto- og digitalkunst</translation>
 <translation id="2601150049980261779">Romantiske film</translation>
@@ -931,7 +931,7 @@
 <translation id="3282085321714087552">Din organisation <ph name="ENROLLMENT_DOMAIN" /> har sendt nogle oplysninger til følgende websites, f.eks. indstillinger eller politikker.</translation>
 <translation id="3286372614333682499">stående</translation>
 <translation id="3287510313208355388">Download, når du er online</translation>
-<translation id="3288238092761586174"><ph name="URL" /> er muligvis nødt til at gennemføre yderligere trin for at bekræfte din betaling</translation>
+<translation id="3288238092761586174"><ph name="URL" /> er muligvis nødt til at gennemføre yderligere trin for at verificere din betaling</translation>
 <translation id="3293642807462928945">Få flere oplysninger om politikken <ph name="POLICY_NAME" /></translation>
 <translation id="3295444047715739395">Se og administrer dine adgangskoder i Chrome-indstillingerne</translation>
 <translation id="3299098170013242198">Windows Hello er aktiveret med henblik på udfyldning af adgangskoder</translation>
@@ -1660,7 +1660,7 @@
 <translation id="5045550434625856497">Ugyldig adgangskode</translation>
 <translation id="5051305769747448211">Livekomedier</translation>
 <translation id="5056425809654826431">{NUM_FILES,plural, =1{Hvis du vil sende denne fil ved hjælp af Deling tæt på, skal du frigøre plads (<ph name="DISK_SPACE_SIZE" />) på din enhed}one{Hvis du vil sende denne fil ved hjælp af Deling tæt på, skal du frigøre plads (<ph name="DISK_SPACE_SIZE" />) på din enhed}other{Hvis du vil sende disse filer ved hjælp af Deling tæt på, skal du frigøre plads (<ph name="DISK_SPACE_SIZE" />) på din enhed}}</translation>
-<translation id="5060483733937416656">Du har valgt at bekræfte med Windows Hello på websites, der anvender <ph name="PROVIDER_ORIGIN" />. Denne udbyder har muligvis gemt oplysninger om din betalingsmetode. Du kan <ph name="LINK_TEXT" /> af disse oplysninger.</translation>
+<translation id="5060483733937416656">Du har valgt at verificere med Windows Hello på websites, der anvender <ph name="PROVIDER_ORIGIN" />. Denne udbyder har muligvis gemt oplysninger om din betalingsmetode. Du kan <ph name="LINK_TEXT" /> af disse oplysninger.</translation>
 <translation id="5061227663725596739">Mente du <ph name="LOOKALIKE_DOMAIN" />?</translation>
 <translation id="5066056036849835175">Udskrivningshistorik</translation>
 <translation id="5068234115460527047">Hedgefonde</translation>
@@ -1793,6 +1793,7 @@
 <translation id="5344579389779391559">Denne side forsøger muligvis at opkræve penge af dig</translation>
 <translation id="5347645913823149105">Knappen Tilpas skrifttyper i Chrome – tryk på Enter for at tilpasse skriftstørrelsen og skrifttypen i Chrome</translation>
 <translation id="5355557959165512791">Du kan ikke besøge <ph name="SITE" /> lige nu, da dets certifikat er blevet tilbagekaldt. Netværksfejl og angreb er normalt midlertidige, så siden vil sandsynligvis fungere igen senere.</translation>
+<translation id="5356345925629253198">Du kan bruge gemte adresser i alle Google-produkter. Denne adresse gemmes på din Google-konto (<ph name="ACCOUNT" />).</translation>
 <translation id="5357848622083956825">Visuel kunst og design</translation>
 <translation id="536296301121032821">Der kunne ikke gemmes indstillinger for politik</translation>
 <translation id="5363309033720083897">Din administrator har tilladt denne serieport</translation>
@@ -1918,7 +1919,6 @@
 <translation id="5695542892312572833">Vil du bruge Windows Hello til at verificere og gennemføre dit køb?</translation>
 <translation id="5701381305118179107">Centrér</translation>
 <translation id="570530837424789914">Administrer...</translation>
-<translation id="5706906618852913030">Vil du gemme adressen på din konto?</translation>
 <translation id="5707154300732650394">Genoptag din søgning</translation>
 <translation id="57094364128775171">Foreslå stærk adgangskode…</translation>
 <translation id="571403275720188526">(arm64)</translation>
@@ -3143,7 +3143,7 @@
 <translation id="8736059027199600831">30 x 40 tommer</translation>
 <translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" /> – tryk på Tab-tasten efterfulgt af Enter for at åbne et nyt inkognitovindue, så du kan browse privat</translation>
 <translation id="8737685506611670901">Åbne <ph name="PROTOCOL" />-links i stedet for <ph name="REPLACED_HANDLER_TITLE" /></translation>
-<translation id="8738058698779197622">For at kunne oprette en sikker forbindelse skal dit ur være indstillet korrekt. Det er vigtigt, da de certifikater, som websites bruger til at identificere sig selv, kun er gyldige i bestemte tidsperioder. Da uret på din enhed går forkert, kan Chromium ikke bekræfte disse certifikater.</translation>
+<translation id="8738058698779197622">For at kunne oprette en sikker forbindelse skal dit ur være indstillet korrekt. Det er vigtigt, da de certifikater, som websites bruger til at identificere sig selv, kun er gyldige i bestemte tidsperioder. Da uret på din enhed går forkert, kan Chromium ikke verificere disse certifikater.</translation>
 <translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;DNS-adressen&lt;/abbr&gt; for <ph name="HOST_NAME" /> blev ikke fundet. Diagnosticerer problemet.</translation>
 <translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> er din kode til <ph name="ORIGIN" /></translation>
 <translation id="874918643257405732">Tilføj denne fane som bogmærke</translation>
diff --git a/components/strings/components_strings_de.xtb b/components/strings/components_strings_de.xtb
index 42295230..97644886 100644
--- a/components/strings/components_strings_de.xtb
+++ b/components/strings/components_strings_de.xtb
@@ -1917,7 +1917,6 @@
 <translation id="5695542892312572833">Möchtest du zum Bestätigen und Abschließen deines Kaufs Windows Hello verwenden?</translation>
 <translation id="5701381305118179107">Zentrieren</translation>
 <translation id="570530837424789914">Verwalten…</translation>
-<translation id="5706906618852913030">Im Konto speichern?</translation>
 <translation id="5707154300732650394">Weiter stöbern</translation>
 <translation id="57094364128775171">Starkes Passwort vorschlagen…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_el.xtb b/components/strings/components_strings_el.xtb
index 9a0b25b..a609ae6 100644
--- a/components/strings/components_strings_el.xtb
+++ b/components/strings/components_strings_el.xtb
@@ -1920,7 +1920,6 @@
 <translation id="5695542892312572833">Χρήση του Windows Hello για επαλήθευση και ολοκλήρωση της αγοράς σας;</translation>
 <translation id="5701381305118179107">Κέντρο</translation>
 <translation id="570530837424789914">Διαχείριση…</translation>
-<translation id="5706906618852913030">Αποθήκευση στον λογαριασμό;</translation>
 <translation id="5707154300732650394">Συνέχιση της διαδρομής σας</translation>
 <translation id="57094364128775171">Πρόταση για ισχυρό κωδικό πρόσβασης…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_en-GB.xtb b/components/strings/components_strings_en-GB.xtb
index 1f9f485..83b6af0 100644
--- a/components/strings/components_strings_en-GB.xtb
+++ b/components/strings/components_strings_en-GB.xtb
@@ -1793,6 +1793,7 @@
 <translation id="5344579389779391559">This page may try to charge you money</translation>
 <translation id="5347645913823149105">Customise fonts in Chrome button, press Enter to customise font sizes and typefaces in Chrome</translation>
 <translation id="5355557959165512791">You cannot visit <ph name="SITE" /> right now because its certificate has been revoked. Network errors and attacks are usually temporary, so this page will probably work later.</translation>
+<translation id="5356345925629253198">You can use saved addresses across Google products. This address will be saved in your Google Account (<ph name="ACCOUNT" />).</translation>
 <translation id="5357848622083956825">Visual art and design</translation>
 <translation id="536296301121032821">Failed to store policy settings</translation>
 <translation id="5363309033720083897">Serial port allowed by your administrator</translation>
@@ -1918,7 +1919,6 @@
 <translation id="5695542892312572833">Use Windows Hello to verify and complete your purchase?</translation>
 <translation id="5701381305118179107">Centre</translation>
 <translation id="570530837424789914">Manage...</translation>
-<translation id="5706906618852913030">Save in Account?</translation>
 <translation id="5707154300732650394">Resume your journey</translation>
 <translation id="57094364128775171">Suggest strong password…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_es-419.xtb b/components/strings/components_strings_es-419.xtb
index 689bb2f..cafb31b 100644
--- a/components/strings/components_strings_es-419.xtb
+++ b/components/strings/components_strings_es-419.xtb
@@ -770,7 +770,7 @@
 <translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, presiona Tab y, luego, Intro para administrar tu Navegación segura y más en la configuración de Chrome</translation>
 <translation id="2878197950673342043">Plegado de póster</translation>
 <translation id="2878424575911748999">A1</translation>
-<translation id="2879694782644540289">usar el bloqueo de pantalla para completar contraseñas.</translation>
+<translation id="2879694782644540289">usar el bloqueo de pantalla para completar contraseñas</translation>
 <translation id="2881276955470682203">¿Quieres guardar la tarjeta?</translation>
 <translation id="2882949212241984732">Plegado en ventana doble</translation>
 <translation id="2893773853358652045">Cuarto rollo</translation>
@@ -1794,6 +1794,7 @@
 <translation id="5344579389779391559">Es posible que esta página intente cobrarte dinero</translation>
 <translation id="5347645913823149105">Botón Personalizar fuentes en Chrome, presiona Intro para personalizar el tamaño de las fuentes y los tipos de letra en Chrome</translation>
 <translation id="5355557959165512791">No puedes visitar <ph name="SITE" /> ahora porque este certificado se revocó. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta página funcione más tarde.</translation>
+<translation id="5356345925629253198">Puedes usar las direcciones guardadas en todos los productos de Google. Esta dirección se guardará en tu Cuenta de Google (<ph name="ACCOUNT" />).</translation>
 <translation id="5357848622083956825">Artes visuales y diseño</translation>
 <translation id="536296301121032821">Error al almacenar la configuración de la política</translation>
 <translation id="5363309033720083897">Puerto en serie que permite tu administrador</translation>
@@ -1919,7 +1920,6 @@
 <translation id="5695542892312572833">¿Deseas usar Windows Hello para verificar y completar tu compra?</translation>
 <translation id="5701381305118179107">Centrar</translation>
 <translation id="570530837424789914">Administrar…</translation>
-<translation id="5706906618852913030">¿Quieres guardarla en la cuenta?</translation>
 <translation id="5707154300732650394">Reanudar tu exploración</translation>
 <translation id="57094364128775171">Sugerir contraseña segura…</translation>
 <translation id="571403275720188526">(arm64)</translation>
@@ -2542,7 +2542,7 @@
 <translation id="7277998515889183784">Maquillaje y cosméticos</translation>
 <translation id="7285654172857511148"><ph name="CHANGE_GOOGLE_PASSWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, presiona Tab y, luego, Intro para cambiar la contraseña de tu Cuenta de Google</translation>
 <translation id="7292031607255951991">Nombre del destinatario</translation>
-<translation id="7298195798382681320">Recomendada</translation>
+<translation id="7298195798382681320">Recomendado</translation>
 <translation id="7299471494012161875">Periféricos de pantallas conectados</translation>
 <translation id="7300012071106347854">Azul cobalto</translation>
 <translation id="7304030187361489308">Alto</translation>
diff --git a/components/strings/components_strings_es.xtb b/components/strings/components_strings_es.xtb
index f264d20b..6dba629 100644
--- a/components/strings/components_strings_es.xtb
+++ b/components/strings/components_strings_es.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">¿Usar Windows Hello para verificar y completar la compra?</translation>
 <translation id="5701381305118179107">Centrar</translation>
 <translation id="570530837424789914">Gestionar...</translation>
-<translation id="5706906618852913030">¿Guardar en la cuenta?</translation>
 <translation id="5707154300732650394">Reanudar recorrido</translation>
 <translation id="57094364128775171">Sugerir contraseña segura…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_et.xtb b/components/strings/components_strings_et.xtb
index d738829..436114f 100644
--- a/components/strings/components_strings_et.xtb
+++ b/components/strings/components_strings_et.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Kas kasutada ostu kinnitamiseks ja lõpuleviimiseks funktsiooni Windows Hello?</translation>
 <translation id="5701381305118179107">Keskel</translation>
 <translation id="570530837424789914">Halda …</translation>
-<translation id="5706906618852913030">Kas salvestada kontole?</translation>
 <translation id="5707154300732650394">Jätkake oma teekonda</translation>
 <translation id="57094364128775171">Soovita tugevat parooli …</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_eu.xtb b/components/strings/components_strings_eu.xtb
index 82b3a18..b3006618 100644
--- a/components/strings/components_strings_eu.xtb
+++ b/components/strings/components_strings_eu.xtb
@@ -1789,6 +1789,7 @@
 <translation id="5344579389779391559">Baliteke orri hau dirua kobratzen saiatzea</translation>
 <translation id="5347645913823149105">Chrome-n letrak pertsonalizatzeko botoia: sakatu "Sartu" tekla Chrome-ko letren tamaina eta tipoa pertsonalizatzeko</translation>
 <translation id="5355557959165512791">Une honetan ezin zara joan <ph name="SITE" /> webgunera ziurtagiria ukatu egin delako. Sareko erroreak eta erasoak aldi baterakoak izan ohi dira; beraz, geroago funtzionatuko du orriak, segur aski.</translation>
+<translation id="5356345925629253198">Gordetako helbideak Google-ren produktu guztietan erabil ditzakezu. Helbide hau Google-ko kontuan (<ph name="ACCOUNT" />) gordeko da.</translation>
 <translation id="5357848622083956825">Ikusizko artea eta diseinua</translation>
 <translation id="536296301121032821">Ezin izan dira gorde gidalerroaren ezarpenak</translation>
 <translation id="5363309033720083897">Administratzaileak onartu duen serieko ataka</translation>
@@ -1914,7 +1915,6 @@
 <translation id="5695542892312572833">Windows Hello erabili nahi duzu erosketa egiaztatzeko eta osatzeko?</translation>
 <translation id="5701381305118179107">Erdiratu</translation>
 <translation id="570530837424789914">Kudeatu…</translation>
-<translation id="5706906618852913030">Kontuan gorde nahi duzu?</translation>
 <translation id="5707154300732650394">Berrekin bilaketa-ibilbideari</translation>
 <translation id="57094364128775171">Iradoki pasahitz konplexu bat…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_fa.xtb b/components/strings/components_strings_fa.xtb
index 7b9aa91..c831ba7 100644
--- a/components/strings/components_strings_fa.xtb
+++ b/components/strings/components_strings_fa.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">‏برای تأیید و تکمیل خریدتان از Windows Hello استفاده شود؟</translation>
 <translation id="5701381305118179107">مرکز</translation>
 <translation id="570530837424789914">مدیریت…</translation>
-<translation id="5706906618852913030">در حساب ذخیره شود؟</translation>
 <translation id="5707154300732650394">ازسرگیری سفر جستجو</translation>
 <translation id="57094364128775171">پیشنهاد گذرواژه قوی…</translation>
 <translation id="571403275720188526">(arm64)</translation>
@@ -2106,6 +2105,7 @@
 <translation id="6165508094623778733">بیشتر بدانید</translation>
 <translation id="6167577165590485365">آخرین تلاش برای واکشی:</translation>
 <translation id="6169916984152623906">اکنون می‌توانید به‌طور خصوصی مرور کنید و سایر افرادی که از این دستگاه استفاده می‌کنند فعالیت شما را نخواهند دید. بااین‌وجود بارگیری‌ها و نشانک‌ها ذخیره خواهند شد.</translation>
+<translation id="617256461084925519">‏Google Chrome سعی دارد هویت شما را تأیید کند تا بتواند اطلاعات پرداخت شما را تکمیل کند.</translation>
 <translation id="6177128806592000436">اتصال شما به این سایت امن نیست</translation>
 <translation id="6177531123306197852">پاکت سی۲</translation>
 <translation id="6180316780098470077">فاصله زمانی امتحان مجدد</translation>
@@ -2657,6 +2657,7 @@
 <translation id="7518003948725431193">صفحه وبی با این آدرس وب یافت نشد: <ph name="URL" /></translation>
 <translation id="7521387064766892559">جاوا اسکریپت</translation>
 <translation id="7521825010239864438">بخش «<ph name="SECTION" />» پنهان شد</translation>
+<translation id="752189128961566325">‏می‌توانید از آن در محصولات Google استفاده کنید</translation>
 <translation id="7523408071729642236">تولید</translation>
 <translation id="7526934274050461096">اتصال شما به این سایت خصوصی نیست</translation>
 <translation id="7529884293139707752">آموزش در خانه</translation>
@@ -2884,6 +2885,7 @@
 <translation id="8057711352706143257">«<ph name="SOFTWARE_NAME" />» درست پیکربندی نمی‌شود. معمولاً حذف‌ نصب «<ph name="SOFTWARE_NAME" />» مشکل را برطرف می‌کند. <ph name="FURTHER_EXPLANATION" /></translation>
 <translation id="8058009102480785916">تولید موادغذایی</translation>
 <translation id="8058603697124206642">الزامی نیست</translation>
+<translation id="8064892030280197386">هویتتان را به‌تأیید برسانید تا مرورگر بتواند اطلاعات پرداخت شما را تکمیل کند.</translation>
 <translation id="8066225060526005217">تحت‌مدیریت تنظیمات کوکی</translation>
 <translation id="8067872629359326442">‏اخیراً گذرواژه‌تان را در سایتی فریب‌کار وارد کرده‌اید. Chromium می‌تواند کمک کند. برای اینکه گذرواژه‌تان را تغییر دهید و به Google اطلاع دهید که شاید حسابتان درمعرض خطر باشد، روی «محافظت از حساب» کلیک کنید.</translation>
 <translation id="8070439594494267500">نماد برنامه</translation>
diff --git a/components/strings/components_strings_fi.xtb b/components/strings/components_strings_fi.xtb
index a350e02..148cefa 100644
--- a/components/strings/components_strings_fi.xtb
+++ b/components/strings/components_strings_fi.xtb
@@ -1920,7 +1920,6 @@
 <translation id="5695542892312572833">Todennetaanko ja viimeistelläänkö ostos Windows Hellolla?</translation>
 <translation id="5701381305118179107">Keskitä</translation>
 <translation id="570530837424789914">Hallinnoi…</translation>
-<translation id="5706906618852913030">Tallennetaanko tilille?</translation>
 <translation id="5707154300732650394">Jatka toimintoa</translation>
 <translation id="57094364128775171">Ehdota vahvaa salasanaa…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_fil.xtb b/components/strings/components_strings_fil.xtb
index 0cd18b2a7..639b6b7 100644
--- a/components/strings/components_strings_fil.xtb
+++ b/components/strings/components_strings_fil.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Gamitin ang Windows Hello para i-verify at kumpletuhin ang iyong pagbili?</translation>
 <translation id="5701381305118179107">Gitna</translation>
 <translation id="570530837424789914">Pamahalaan...</translation>
-<translation id="5706906618852913030">I-save sa Account?</translation>
 <translation id="5707154300732650394">Ipagpatuloy ang iyong journey</translation>
 <translation id="57094364128775171">Magmungkahi ng malakas na password...</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_fr-CA.xtb b/components/strings/components_strings_fr-CA.xtb
index 396d640..8a416351 100644
--- a/components/strings/components_strings_fr-CA.xtb
+++ b/components/strings/components_strings_fr-CA.xtb
@@ -1793,6 +1793,7 @@
 <translation id="5344579389779391559">L'accès à cette page peut engendrer des frais</translation>
 <translation id="5347645913823149105">Bouton Personnaliser les polices dans Chrome, appuyez sur la touche Entrée pour personnaliser la taille des polices et les caractères dans Chrome</translation>
 <translation id="5355557959165512791">Vous ne pouvez pas consulter le site <ph name="SITE" /> pour le moment, car son certificat a été révoqué. Les erreurs réseau et les attaques sont généralement temporaires, ce qui signifie que cette page devrait fonctionner de nouveau plus tard.</translation>
+<translation id="5356345925629253198">Vous pouvez utiliser les adresses enregistrées avec tous les produits Google. Cette adresse sera enregistrée dans votre compte Google (<ph name="ACCOUNT" />).</translation>
 <translation id="5357848622083956825">Art visuel et design</translation>
 <translation id="536296301121032821">Échec de stockage des paramètres de la règle</translation>
 <translation id="5363309033720083897">Port série autorisé par votre administrateur</translation>
@@ -1918,7 +1919,6 @@
 <translation id="5695542892312572833">Utiliser Windows Hello pour vérifier et finaliser votre achat?</translation>
 <translation id="5701381305118179107">Centrer</translation>
 <translation id="570530837424789914">Gérer...</translation>
-<translation id="5706906618852913030">Enregistrer dans le compte?</translation>
 <translation id="5707154300732650394">Reprendre votre exploration</translation>
 <translation id="57094364128775171">Suggérer un mot de passe fort…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_fr.xtb b/components/strings/components_strings_fr.xtb
index c0407519..3faf3b4 100644
--- a/components/strings/components_strings_fr.xtb
+++ b/components/strings/components_strings_fr.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Utiliser Windows Hello pour valider et finaliser votre achat ?</translation>
 <translation id="5701381305118179107">Centrer</translation>
 <translation id="570530837424789914">Gérer…</translation>
-<translation id="5706906618852913030">Enregistrer dans le compte ?</translation>
 <translation id="5707154300732650394">Reprendre votre parcours</translation>
 <translation id="57094364128775171">Suggérer un mot de passe sécurisé…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_gl.xtb b/components/strings/components_strings_gl.xtb
index aea5b2d..42799aa 100644
--- a/components/strings/components_strings_gl.xtb
+++ b/components/strings/components_strings_gl.xtb
@@ -1793,6 +1793,7 @@
 <translation id="5344579389779391559">Esta páxina pode tentar aplicar cargos</translation>
 <translation id="5347645913823149105">Botón para personalizar os tipos de letra en Chrome. Para personalizar os tamaños e os tipos de letra en Chrome, preme Introducir</translation>
 <translation id="5355557959165512791">Non podes visitar <ph name="SITE" /> neste momento porque se revogou o seu certificado. Normalmente, os erros de rede e os ataques son temporais, polo que é posible que esta páxina funcione máis tarde.</translation>
+<translation id="5356345925629253198">Podes usar os enderezos gardados nos produtos de Google. Este enderezo gardarase na túa Conta de Google (<ph name="ACCOUNT" />).</translation>
 <translation id="5357848622083956825">Arte e deseño visuais</translation>
 <translation id="536296301121032821">Non se puido almacenar a configuración da política</translation>
 <translation id="5363309033720083897">O teu administrador permite o uso do porto en serie</translation>
@@ -1918,7 +1919,6 @@
 <translation id="5695542892312572833">Queres utilizar Windows Hello para verificar e completar a compra?</translation>
 <translation id="5701381305118179107">Centrar</translation>
 <translation id="570530837424789914">Xestiona o contido...</translation>
-<translation id="5706906618852913030">Queres gardalo na conta?</translation>
 <translation id="5707154300732650394">Retomar percorrido</translation>
 <translation id="57094364128775171">Suxerir contrasinal seguro…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_gu.xtb b/components/strings/components_strings_gu.xtb
index d027875..c9751f3 100644
--- a/components/strings/components_strings_gu.xtb
+++ b/components/strings/components_strings_gu.xtb
@@ -1793,6 +1793,7 @@
 <translation id="5344579389779391559">આ પેજ કદાચ તમારી પાસેથી શુલ્ક વસૂલ કરવાનો પ્રયાસ કરી શકે છે</translation>
 <translation id="5347645913823149105">Chromeમાં ફૉન્ટ કસ્ટમાઇઝ કરવા માટેનું બટન, Chromeમાં ફૉન્ટના કદ અને ટાઇપફેસ કસ્ટમાઇઝ કરવા માટે Enter કી દબાવો</translation>
 <translation id="5355557959165512791">તમે અત્યારે <ph name="SITE" />ની મુલાકાત લઈ શકતાં નથી કારણ કે તેનું પ્રમાણપત્ર રદબાતલ કરવામાં આવ્યું છે. નેટવર્કમાં ભૂલ આવવી અને હુમલા થવા સામાન્ય રીતે અસ્થાયી હોય છે, તેથી આ પેજ સંભવિત રૂપે થોડા સમય પછી કાર્ય કરશે.</translation>
+<translation id="5356345925629253198">તમે Googleની બધી પ્રોડક્ટમાં સાચવેલા સરનામાનો ઉપયોગ કરી શકશો. આ સરનામું તમારા Google એકાઉન્ટ (<ph name="ACCOUNT" />)માં સાચવવામાં આવશે.</translation>
 <translation id="5357848622083956825">વિઝ્યુઅલ આર્ટ અને ડિઝાઇન</translation>
 <translation id="536296301121032821">પૉલિસી સેટિંગ સ્ટોર કરવામાં નિષ્ફળ થયાં</translation>
 <translation id="5363309033720083897">તમારા વ્યવસ્થાપક દ્વારા મંજૂરી આપવામાં આવેલો સીરિયલ પોર્ટ</translation>
@@ -1918,7 +1919,6 @@
 <translation id="5695542892312572833">તમારી ખરીદી ચકાસવા અને પૂર્ણ કરવા Windows Helloનો ઉપયોગ કરીએ?</translation>
 <translation id="5701381305118179107">મધ્યમાં</translation>
 <translation id="570530837424789914">મેનેજ કરો…</translation>
-<translation id="5706906618852913030">એકાઉન્ટમાં સાચવીએ?</translation>
 <translation id="5707154300732650394">તમારો પ્રવાસ ફરી શરૂ કરો</translation>
 <translation id="57094364128775171">સશક્ત પાસવર્ડ સૂચવો…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_hi.xtb b/components/strings/components_strings_hi.xtb
index 9513cbc..f0f6476 100644
--- a/components/strings/components_strings_hi.xtb
+++ b/components/strings/components_strings_hi.xtb
@@ -1793,6 +1793,7 @@
 <translation id="5344579389779391559">यह पेज आपसे शुल्क लेने की कोशिश कर सकता है</translation>
 <translation id="5347645913823149105">Chrome बटन में फ़ॉन्ट को पसंद के मुताबिक बनाएं, Chrome में फ़ॉन्ट साइज़ और टाइपफ़ेस को पसंद के मुताबिक बनाने के लिए, Enter दबाएं</translation>
 <translation id="5355557959165512791">आप इस समय <ph name="SITE" /> पर नहीं जा सकते हैं क्योंकि उसका प्रमाणपत्र रद्द कर दिया गया है. नेटवर्क की गड़बड़ी और हमले आमतौर पर कुछ देर के लिए होते हैं, इसलिए मुमकिन है कि यह पेज बाद में काम करे.</translation>
+<translation id="5356345925629253198">सेव किए गए पतों का इस्तेमाल, Google के सभी प्रॉडक्ट के लिए करें. यह पता, आपके Google खाते (<ph name="ACCOUNT" />) में सेव किया जाएगा.</translation>
 <translation id="5357848622083956825">विज़ुअल आर्ट और डिज़ाइन</translation>
 <translation id="536296301121032821">नीति सेटिंग संग्रहित करने में विफल</translation>
 <translation id="5363309033720083897">ऐसा सीरियल पोर्ट जिसकी अनुमति आपके एडमिन ने दी है</translation>
@@ -1918,7 +1919,6 @@
 <translation id="5695542892312572833">क्या आप खरीदारी की पुष्टि करने और उसे पूरा करने के लिए, Windows Hello का इस्तेमाल करना चाहते हैं?</translation>
 <translation id="5701381305118179107">मध्य</translation>
 <translation id="570530837424789914">प्रबंधित करें...</translation>
-<translation id="5706906618852913030">क्या आपको खाते में सेव करना है?</translation>
 <translation id="5707154300732650394">'Chrome इतिहास' में, अपनी गतिविधियां फिर से शुरू करें</translation>
 <translation id="57094364128775171">मज़बूत पासवर्ड सुझाएं…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_hr.xtb b/components/strings/components_strings_hr.xtb
index 340e97a..9dcc3e1 100644
--- a/components/strings/components_strings_hr.xtb
+++ b/components/strings/components_strings_hr.xtb
@@ -1918,7 +1918,6 @@
 <translation id="5695542892312572833">Upotrijebiti značajku Windows Hello za potvrdu i dovršetak kupnje?</translation>
 <translation id="5701381305118179107">Centriraj</translation>
 <translation id="570530837424789914">Upravljajte...</translation>
-<translation id="5706906618852913030">Želite li spremiti na račun?</translation>
 <translation id="5707154300732650394">Nastavite putovanje</translation>
 <translation id="57094364128775171">Predloži snažnu zaporku…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_hu.xtb b/components/strings/components_strings_hu.xtb
index b05bcba..85c0287 100644
--- a/components/strings/components_strings_hu.xtb
+++ b/components/strings/components_strings_hu.xtb
@@ -1791,6 +1791,7 @@
 <translation id="5344579389779391559">Ez az oldal fizetésre próbálhatja meg rávenni</translation>
 <translation id="5347645913823149105">Betűtípusok személyre szabása a Chrome-ban gomb. Nyomja le az Entert a Chrome-ban megjelenő betűméretek és betűképek személyre szabásához.</translation>
 <translation id="5355557959165512791">Pillanatnyilag nem tudja felkeresni a(z) <ph name="SITE" /> webhelyet, mert a webhely tanúsítványát visszavonták. A hálózati hibák és támadások rendszerint átmenetiek, ezért az említett oldal működése később valószínűleg helyreáll.</translation>
+<translation id="5356345925629253198">A mentett címeket használhatja a Google-termékben. Ezt a címet az Ön Google-fiókjába (<ph name="ACCOUNT" />) menti a rendszer.</translation>
 <translation id="5357848622083956825">Vizuális művészet és design</translation>
 <translation id="536296301121032821">Az irányelv-beállítások tárolása sikertelen</translation>
 <translation id="5363309033720083897">Rendszergazda által engedélyezett soros port</translation>
@@ -1916,7 +1917,6 @@
 <translation id="5695542892312572833">Szeretné a Windows Hello használatával igazolni és befejezni vásárlását?</translation>
 <translation id="5701381305118179107">Középre</translation>
 <translation id="570530837424789914">Kezelés…</translation>
-<translation id="5706906618852913030">Mentés a fiókba?</translation>
 <translation id="5707154300732650394">Utazás folytatása</translation>
 <translation id="57094364128775171">Erős jelszó ajánlása…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_hy.xtb b/components/strings/components_strings_hy.xtb
index c2d61e4a..e0d82307 100644
--- a/components/strings/components_strings_hy.xtb
+++ b/components/strings/components_strings_hy.xtb
@@ -1794,6 +1794,7 @@
 <translation id="5344579389779391559">Այս էջում հնարավոր է ձեզնից գումար գանձելու փորձ արվի</translation>
 <translation id="5347645913823149105">«Կարգավորել տառատեսակները Chrome-ում» կոճակ։ Chrome-ում տառատեսակները և դրանց չափերը կարգավորելու համար սեղմեք Enter։</translation>
 <translation id="5355557959165512791">Այս պահին չեք կարող այցելել <ph name="SITE" /> կայք, քանի որ դրա հավաստագիրը հետ է կանչվել։ Ցանցային սխալներն ու հարձակումները սովորաբար ժամանակավոր բնույթ են կրում, և հավանաբար այս էջը հասանելի կլինի ավելի ուշ:</translation>
+<translation id="5356345925629253198">Դուք կարող եք օգտագործել պահված հասցեները Google-ի արտադրանքներում։ Այս հասցեն կպահվի ձեր Google հաշվում (<ph name="ACCOUNT" />)։</translation>
 <translation id="5357848622083956825">Կերպարվեստ և դիզայն</translation>
 <translation id="536296301121032821">Չհաջողվեց պահել կանոնի կարգավորումները</translation>
 <translation id="5363309033720083897">Ադմինիստրատորը թույլատրել է հերթական միացքը</translation>
@@ -1919,7 +1920,6 @@
 <translation id="5695542892312572833">Հաստատե՞լ և ավարտել ձեր գնումը Windows Hello-ի միջոցով</translation>
 <translation id="5701381305118179107">Կենտրոնաբերել</translation>
 <translation id="570530837424789914">Կառավարել...</translation>
-<translation id="5706906618852913030">Պահե՞լ հաշվում</translation>
 <translation id="5707154300732650394">Շարունակել որոնումը</translation>
 <translation id="57094364128775171">Ստեղծել հուսալի գաղտնաբառ…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_id.xtb b/components/strings/components_strings_id.xtb
index 0e24a97..a6f51ff 100644
--- a/components/strings/components_strings_id.xtb
+++ b/components/strings/components_strings_id.xtb
@@ -1792,6 +1792,7 @@
 <translation id="5344579389779391559">Halaman ini mungkin mencoba menagih Anda</translation>
 <translation id="5347645913823149105">Tombol Sesuaikan font di Chrome, tekan Enter untuk menyesuaikan ukuran font dan rupa huruf di Chrome</translation>
 <translation id="5355557959165512791">Anda tidak dapat membuka <ph name="SITE" /> sekarang karena sertifikatnya telah dicabut. Error jaringan dan serangan biasanya bersifat sementara, sehingga halaman ini mungkin akan berfungsi nanti.</translation>
+<translation id="5356345925629253198">Anda dapat menggunakan alamat tersimpan di seluruh produk Google. Alamat ini akan disimpan di Akun Google Anda (<ph name="ACCOUNT" />).</translation>
 <translation id="5357848622083956825">Seni &amp; desain visual</translation>
 <translation id="536296301121032821">Gagal menyimpan setelan kebijakan</translation>
 <translation id="5363309033720083897">Port serial yang diizinkan oleh administrator Anda</translation>
@@ -1917,7 +1918,6 @@
 <translation id="5695542892312572833">Gunakan Windows Hello untuk memverifikasi dan menyelesaikan pembelian Anda?</translation>
 <translation id="5701381305118179107">Tengah</translation>
 <translation id="570530837424789914">Kelola...</translation>
-<translation id="5706906618852913030">Simpan di Akun?</translation>
 <translation id="5707154300732650394">Lanjutkan perjalanan Anda</translation>
 <translation id="57094364128775171">Sarankan sandi yang kuat…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_is.xtb b/components/strings/components_strings_is.xtb
index ce47b52..5b4d8f5 100644
--- a/components/strings/components_strings_is.xtb
+++ b/components/strings/components_strings_is.xtb
@@ -1793,6 +1793,7 @@
 <translation id="5344579389779391559">Þessi síða gæti reynt að rukka þig um greiðslu</translation>
 <translation id="5347645913823149105">Notaðu Chrome hnappinn til að sérsníða leturgerðir, ýttu á Enter til að sérsníða leturstærðir og leturgerðir í Chrome</translation>
 <translation id="5355557959165512791">Þú getur ekki heimsótt <ph name="SITE" /> í augnablikinu vegna þess að þetta vottorð hefur verið afturkallað. Netvillur og árásir eru yfirleitt tímabundnar og því mun þessi síða líklega virka síðar.</translation>
+<translation id="5356345925629253198">Þú getur notað vistuð heimilisföng í Google-vörum. Þetta heimilisfang verður vistað á Google-reikningnum þínum (<ph name="ACCOUNT" />).</translation>
 <translation id="5357848622083956825">Myndlist og hönnun</translation>
 <translation id="536296301121032821">Mistókst að vista reglustillingar</translation>
 <translation id="5363309033720083897">Raðtengi heimilað af stjórnanda</translation>
@@ -1918,7 +1919,6 @@
 <translation id="5695542892312572833">Nota Windows Hello til að staðfesta og ljúka kaupunum?</translation>
 <translation id="5701381305118179107">Miðjujafna</translation>
 <translation id="570530837424789914">Stjórna...</translation>
-<translation id="5706906618852913030">Vista á reikningi?</translation>
 <translation id="5707154300732650394">Haltu ferðinni áfram</translation>
 <translation id="57094364128775171">Tillaga að traustu aðgangsorði…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_it.xtb b/components/strings/components_strings_it.xtb
index 361f6016..7901059 100644
--- a/components/strings/components_strings_it.xtb
+++ b/components/strings/components_strings_it.xtb
@@ -1916,7 +1916,6 @@
 <translation id="5695542892312572833">Vuoi usare Windows Hello per verificare e completare l'acquisto?</translation>
 <translation id="5701381305118179107">Centra</translation>
 <translation id="570530837424789914">Gestisci…</translation>
-<translation id="5706906618852913030">Vuoi salvare nell'account?</translation>
 <translation id="5707154300732650394">Riprendi il percorso</translation>
 <translation id="57094364128775171">Suggerisci password efficace…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_iw.xtb b/components/strings/components_strings_iw.xtb
index 1e8de2e..ee3051f 100644
--- a/components/strings/components_strings_iw.xtb
+++ b/components/strings/components_strings_iw.xtb
@@ -1924,7 +1924,6 @@
 <translation id="5695542892312572833">‏להשתמש ב-Windows Hello כדי לאמת ולהשלים את הרכישה?</translation>
 <translation id="5701381305118179107">מרכז</translation>
 <translation id="570530837424789914">ניהול...</translation>
-<translation id="5706906618852913030">לשמור בחשבון?</translation>
 <translation id="5707154300732650394">להמשך התהליך</translation>
 <translation id="57094364128775171">הצעת סיסמה חזקה…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_ja.xtb b/components/strings/components_strings_ja.xtb
index 3b906d4..f413d621 100644
--- a/components/strings/components_strings_ja.xtb
+++ b/components/strings/components_strings_ja.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Windows Hello を使用して本人確認し、購入手続きを完了しますか?</translation>
 <translation id="5701381305118179107">中央揃え</translation>
 <translation id="570530837424789914">管理...</translation>
-<translation id="5706906618852913030">アカウントに保存しますか?</translation>
 <translation id="5707154300732650394">ジャーニーを再開</translation>
 <translation id="57094364128775171">安全なパスワードを自動生成…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_ka.xtb b/components/strings/components_strings_ka.xtb
index e88db38..9782821 100644
--- a/components/strings/components_strings_ka.xtb
+++ b/components/strings/components_strings_ka.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">გსურთ, გამოიყენოთ Windows Hello შენაძენების დასადასტურებლად და განსახორციელებლად?</translation>
 <translation id="5701381305118179107">ცენტრირება</translation>
 <translation id="570530837424789914">მართვა…</translation>
-<translation id="5706906618852913030">გსურთ ანგარიშში შენახვა?</translation>
 <translation id="5707154300732650394">თქვენი პროცესის გაგრძელება</translation>
 <translation id="57094364128775171">ძლიერი პაროლის შემოთავაზება…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_kk.xtb b/components/strings/components_strings_kk.xtb
index c2ad037..52909db 100644
--- a/components/strings/components_strings_kk.xtb
+++ b/components/strings/components_strings_kk.xtb
@@ -1918,7 +1918,6 @@
 <translation id="5695542892312572833">Сатып алуды растау және аяқтау үшін Windows Hello пайдаланылсын ба?</translation>
 <translation id="5701381305118179107">Ортаға</translation>
 <translation id="570530837424789914">Басқару…</translation>
-<translation id="5706906618852913030">Аккаунтта сақтау керек пе?</translation>
 <translation id="5707154300732650394">Шарлауды жалғастыру</translation>
 <translation id="57094364128775171">Күрделі құпия сөз жасау…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_km.xtb b/components/strings/components_strings_km.xtb
index 1a2da0b..14a5637 100644
--- a/components/strings/components_strings_km.xtb
+++ b/components/strings/components_strings_km.xtb
@@ -1923,7 +1923,6 @@
 <translation id="5695542892312572833">ប្រើ Windows Hello ដើម្បី​ផ្ទៀងផ្ទាត់ និង​បញ្ចប់ការទិញ​របស់អ្នកឬ?</translation>
 <translation id="5701381305118179107">កណ្តាល</translation>
 <translation id="570530837424789914">គ្រប់គ្រង...</translation>
-<translation id="5706906618852913030">រក្សាទុកនៅក្នុងគណនីឬ?</translation>
 <translation id="5707154300732650394">បន្ត​ការស្វែងរក​របស់អ្នក</translation>
 <translation id="57094364128775171">ណែនាំ​ពាក្យសម្ងាត់​ខ្លាំង…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_kn.xtb b/components/strings/components_strings_kn.xtb
index 18c4f2b..c0e18ba 100644
--- a/components/strings/components_strings_kn.xtb
+++ b/components/strings/components_strings_kn.xtb
@@ -1916,7 +1916,6 @@
 <translation id="5695542892312572833">ನಿಮ್ಮ ಖರೀದಿಯನ್ನು ಖಚಿತಪಡಿಸಲು ಮತ್ತು ಪೂರ್ಣಗೊಳಿಸಲು Windows Hello ಬಳಸಬೇಕೆ?</translation>
 <translation id="5701381305118179107">ಮಧ್ಯಕ್ಕೆ</translation>
 <translation id="570530837424789914">ನಿರ್ವಹಿಸಿ...</translation>
-<translation id="5706906618852913030">ಖಾತೆಯಲ್ಲಿ ಉಳಿಸಬೇಕೆ?</translation>
 <translation id="5707154300732650394">ನಿಮ್ಮ ಪ್ರಯಾಣವನ್ನು ಪುನರಾರಂಭಿಸಿ</translation>
 <translation id="57094364128775171">ಸದೃಢವಾದ ಪಾಸ್‌ವರ್ಡ್ ಸೂಚಿಸಿ…</translation>
 <translation id="571403275720188526">(arm64)</translation>
@@ -2102,6 +2101,7 @@
 <translation id="6165508094623778733">ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ</translation>
 <translation id="6167577165590485365">ಕೊನೆಯ ಬಾರಿಗೆ ಪಡೆಯಲು ಪ್ರಯತ್ನಿಸಲಾಗಿದೆ:</translation>
 <translation id="6169916984152623906">ನೀವೀಗ ಖಾಸಗಿಯಾಗಿ ಬ್ರೌಸ್ ಮಾಡಬಹುದು. ಈ ಸಾಧನವನ್ನು ಬಳಸುವ ಬೇರೆ ಯಾರಿಗೂ ನಿಮ್ಮ ಚಟುವಟಿಕೆ ಕಾಣಿಸುವುದಿಲ್ಲ. ಆದರೂ, ಡೌನ್‌ಲೋಡ್‌ಗಳು ಮತ್ತು ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳು ಉಳಿದಿರುತ್ತವೆ.</translation>
+<translation id="617256461084925519">Google Chrome ನಿಮ್ಮ ಪಾವತಿಯ ಮಾಹಿತಿಯನ್ನು ಸೇರಿಸುವ ಸಲುವಾಗಿ ಇದು ನೀವೇ ಎಂದು ದೃಢೀಕರಿಸಲು ಪ್ರಯತ್ನಿಸುತ್ತಿದೆ.</translation>
 <translation id="6177128806592000436">ಈ ಸೈಟ್‌ಗೆ ನಿಮ್ಮ ಸಂಪರ್ಕವು ಸುರಕ್ಷಿತವಾಗಿಲ್ಲ</translation>
 <translation id="6177531123306197852">ಎನ್ವಲಪ್ C2</translation>
 <translation id="6180316780098470077">ಮರುಪ್ರಯತ್ನದ ಮಧ್ಯಂತರ</translation>
@@ -2653,6 +2653,7 @@
 <translation id="7518003948725431193">ಈ ವೆಬ್ ವಿಳಾಸಕ್ಕಾಗಿ ಯಾವುದೇ ವೆಬ್ ಪುಟವು ಕಂಡುಬರಲಿಲ್ಲ: <ph name="URL" /></translation>
 <translation id="7521387064766892559">JavaScript</translation>
 <translation id="7521825010239864438">"<ph name="SECTION" />" ವಿಭಾಗವನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ</translation>
+<translation id="752189128961566325">ನೀವು ಇದನ್ನು Google ಉತ್ಪನ್ನಗಳಾದ್ಯಂತ ಬಳಸಬಹುದು</translation>
 <translation id="7523408071729642236">ಉತ್ಪಾದನೆ</translation>
 <translation id="7526934274050461096">ಈ ಸೈಟ್‌ಗೆ ನಿಮ್ಮ ಸಂಪರ್ಕವು ಖಾಸಗಿಯಾಗಿಲ್ಲ.</translation>
 <translation id="7529884293139707752">ಹೋಮ್‌ಸ್ಕೂಲಿಂಗ್</translation>
@@ -2880,6 +2881,7 @@
 <translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" ಅನ್ನು ಸರಿಯಾಗಿ ಕಾನ್ಫಿಗರ್ ಮಾಡಲಾಗಿಲ್ಲ. ಸಾಮಾನ್ಯವಾಗಿ ಸಮಸ್ಯೆಯನ್ನು ಪರಿಹರಿಸಲು "<ph name="SOFTWARE_NAME" />" ಅನ್ನು ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾಗುತ್ತಿದೆ. <ph name="FURTHER_EXPLANATION" /></translation>
 <translation id="8058009102480785916">ಆಹಾರ ಉತ್ಪಾದನೆ</translation>
 <translation id="8058603697124206642">ಅಗತ್ಯವಿಲ್ಲ</translation>
+<translation id="8064892030280197386">ಇದು ನೀವೇ ಎಂದು ದೃಢೀಕರಿಸಿ, ಆಗ ಅದು ನಿಮ್ಮ ಪಾವತಿಯ ಮಾಹಿತಿಯನ್ನು ಭರ್ತಿಮಾಡಬಹುದು.</translation>
 <translation id="8066225060526005217">ಕುಕೀಗಳ ಸೆಟ್ಟಿಂಗ್‌ಗಳ ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗಿದೆ</translation>
 <translation id="8067872629359326442">ನೀವು ಈಗಷ್ಟೇ ವಂಚನೆ ಮಾಡುವ ಸೈಟ್‌ನಲ್ಲಿ ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ನಮೂದಿಸಿದ್ದೀರಿ. Chromium ಸಹಾಯ ಮಾಡಬಹುದು. ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್ ಬದಲಿಸಲು ಮತ್ತು ನಿಮ್ಮ ಖಾತೆಗೆ ಅಪಾಯ ಉಂಟಾಗಿರಬಹುದು ಎಂದು Google ಗೆ ಸೂಚಿಸಲು, ಖಾತೆ ರಕ್ಷಿಸಿ ಕ್ಲಿಕ್ ಮಾಡಿ.</translation>
 <translation id="8070439594494267500">ಆ್ಯಪ್ ಐಕಾನ್</translation>
diff --git a/components/strings/components_strings_ko.xtb b/components/strings/components_strings_ko.xtb
index a47b54a..36e3eb0e 100644
--- a/components/strings/components_strings_ko.xtb
+++ b/components/strings/components_strings_ko.xtb
@@ -1793,6 +1793,7 @@
 <translation id="5344579389779391559">이 페이지에서 금액을 청구할 수 있습니다.</translation>
 <translation id="5347645913823149105">Chrome의 글꼴 맞춤설정 버튼, Chrome 글꼴 크기와 서체를 맞춤설정하려면 Enter를 누르세요</translation>
 <translation id="5355557959165512791">인증서가 취소되었기 때문에 현재 <ph name="SITE" />에 방문할 수 없습니다. 네트워크 오류와 공격은 대부분 일시적이므로 나중에 이 페이지가 정상적으로 작동할 수 있습니다.</translation>
+<translation id="5356345925629253198">Google 제품 전반에서 저장된 주소를 사용할 수 있습니다. 이 주소는 Google 계정(<ph name="ACCOUNT" />)에 저장됩니다.</translation>
 <translation id="5357848622083956825">시각 예술 및 디자인</translation>
 <translation id="536296301121032821">정책 설정 저장 실패</translation>
 <translation id="5363309033720083897">관리자가 허용한 직렬 포트</translation>
@@ -1918,7 +1919,6 @@
 <translation id="5695542892312572833">Windows Hello를 사용해 구매를 확인하고 완료하시겠습니까?</translation>
 <translation id="5701381305118179107">가운데</translation>
 <translation id="570530837424789914">관리...</translation>
-<translation id="5706906618852913030">계정에 저장하시겠습니까?</translation>
 <translation id="5707154300732650394">탐색 여정 재개</translation>
 <translation id="57094364128775171">강력한 비밀번호 추천...</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_ky.xtb b/components/strings/components_strings_ky.xtb
index cdcb8de4..6900812 100644
--- a/components/strings/components_strings_ky.xtb
+++ b/components/strings/components_strings_ky.xtb
@@ -1792,6 +1792,7 @@
 <translation id="5344579389779391559">Бул баракта акы алынышы мүмкүн</translation>
 <translation id="5347645913823149105">"Chrome'до ариптерди ыңгайлаштыруу" баскычы, Chrome'до ариптерди жана алардын өлчөмүн ыңгайлаштыруу үчүн Enter баскычын басыңыз</translation>
 <translation id="5355557959165512791">Тастыктамасы жоюлгандыктан, <ph name="SITE" /> сайтына азыр кире албайсыз. Адатта тармактагы каталар жана чабуулдар убактылуу көрүнүш болгондуктан, бул баракча кийинчерээк иштеп калышы мүмкүн.</translation>
+<translation id="5356345925629253198">Сакталган даректериңизди Google кызматтарында колдоно аласыз. Бул дарек Google аккаунтуңузда (<ph name="ACCOUNT" />) сакталат.</translation>
 <translation id="5357848622083956825">Визуалдык көркөм өнөр жана дизайн</translation>
 <translation id="536296301121032821">Саясат параметрлери сакталбай калды</translation>
 <translation id="5363309033720083897">Администраторуңуз уруксат берген сериялык порттор</translation>
@@ -1917,7 +1918,6 @@
 <translation id="5695542892312572833">Ырастоо жана сатып алууну бүтүрүү үчүн Window Hello функциясын колдоносузбу?</translation>
 <translation id="5701381305118179107">Борбор</translation>
 <translation id="570530837424789914">Башкаруу…</translation>
-<translation id="5706906618852913030">Аккаунтта сактайсызбы?</translation>
 <translation id="5707154300732650394">Саякатты улантуу</translation>
 <translation id="57094364128775171">Татаал сырсөз сунушталсын…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_lo.xtb b/components/strings/components_strings_lo.xtb
index eb498b13..444dac5 100644
--- a/components/strings/components_strings_lo.xtb
+++ b/components/strings/components_strings_lo.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">ໃຊ້ Windows Hello ເພື່ອຢັ້ງຢືນ ແລະ ເຮັດສຳເລັດການຊື້ຂອງທ່ານບໍ?</translation>
 <translation id="5701381305118179107">ໃຈກາງ</translation>
 <translation id="570530837424789914">ຈັດການ...</translation>
-<translation id="5706906618852913030">ບັນທຶກໃນບັນຊີບໍ?</translation>
 <translation id="5707154300732650394">ສືບຕໍ່ບັນທຶກຂອງທ່ານ</translation>
 <translation id="57094364128775171">ແນະນຳລະຫັດຜ່ານທີ່ເດົາຍາກ…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_lt.xtb b/components/strings/components_strings_lt.xtb
index a2474e8..3a476e9 100644
--- a/components/strings/components_strings_lt.xtb
+++ b/components/strings/components_strings_lt.xtb
@@ -1920,7 +1920,6 @@
 <translation id="5695542892312572833">Naudoti „Windows Hello“ pirkimo procesui patvirtinti ir užbaigti?</translation>
 <translation id="5701381305118179107">Centre</translation>
 <translation id="570530837424789914">Tvarkyti...</translation>
-<translation id="5706906618852913030">Išsaugoti paskyroje?</translation>
 <translation id="5707154300732650394">Tęsti veiksmus</translation>
 <translation id="57094364128775171">Siūlyti sudėtingą slaptažodį…</translation>
 <translation id="571403275720188526">(arm64)</translation>
@@ -2107,6 +2106,7 @@
 <translation id="6165508094623778733">Sužinokite daugiau</translation>
 <translation id="6167577165590485365">Paskutinis bandymas gauti:</translation>
 <translation id="6169916984152623906">Dabar galite naršyti privačiai, o kiti šį įrenginį naudojantys žmonės nematys jūsų veiklos. Tačiau atsisiuntimai ir žymės bus išsaugoti.</translation>
+<translation id="617256461084925519">„Google Chrome“ bando patvirtinti jūsų tapatybę, kad galėtų užpildyti mokėjimo informaciją.</translation>
 <translation id="6177128806592000436">Ryšys su šia svetaine nėra saugus</translation>
 <translation id="6177531123306197852">C2 vokas</translation>
 <translation id="6180316780098470077">Pakartotinio bandymo intervalas</translation>
@@ -2658,6 +2658,7 @@
 <translation id="7518003948725431193">Nerasta nė vieno tinklalapio šiuo žiniatinklio adresu: <ph name="URL" /></translation>
 <translation id="7521387064766892559">„JavaScript“</translation>
 <translation id="7521825010239864438">Skiltis „<ph name="SECTION" />“ paslėpta</translation>
+<translation id="752189128961566325">Jį galite naudoti „Google“ produktuose</translation>
 <translation id="7523408071729642236">Gamyba</translation>
 <translation id="7526934274050461096">Jūsų ryšys su šia svetaine nėra privatus</translation>
 <translation id="7529884293139707752">Mokymasis namuose</translation>
@@ -2885,6 +2886,7 @@
 <translation id="8057711352706143257">„<ph name="SOFTWARE_NAME" />“ netinkamai sukonfigūruota. Pašalinus „<ph name="SOFTWARE_NAME" />“ paprastai pavyksta išspręsti šią problemą. <ph name="FURTHER_EXPLANATION" /></translation>
 <translation id="8058009102480785916">Maisto gamyba</translation>
 <translation id="8058603697124206642">Neprivaloma</translation>
+<translation id="8064892030280197386">patvirtinti jūsų tapatybę, kad galėtų užpildyti mokėjimo informaciją.</translation>
 <translation id="8066225060526005217">Tvarkoma slapukų nustatymais</translation>
 <translation id="8067872629359326442">Ką tik savo slaptažodį įvedėte apgaulingoje svetainėje. „Chromium“ gali padėti. Norėdami pakeisti slaptažodį ir pranešti „Google“, kad jūsų paskyrai gali grėsti pavojus, spustelėkite „Apsaugoti paskyrą“.</translation>
 <translation id="8070439594494267500">Programos piktograma</translation>
diff --git a/components/strings/components_strings_lv.xtb b/components/strings/components_strings_lv.xtb
index 93ccf2c..7459716c 100644
--- a/components/strings/components_strings_lv.xtb
+++ b/components/strings/components_strings_lv.xtb
@@ -1918,7 +1918,6 @@
 <translation id="5695542892312572833">Vai vēlaties izmantot Windows Hello, lai verificētu un pabeigtu pirkumu?</translation>
 <translation id="5701381305118179107">Centrēt</translation>
 <translation id="570530837424789914">Pārvaldīt...</translation>
-<translation id="5706906618852913030">Vai saglabāt kontā?</translation>
 <translation id="5707154300732650394">Atsākt meklēšanas ceļu</translation>
 <translation id="57094364128775171">Ieteikt drošu paroli…</translation>
 <translation id="571403275720188526">(arm64)</translation>
@@ -2105,6 +2104,7 @@
 <translation id="6165508094623778733">Uzzināt vairāk</translation>
 <translation id="6167577165590485365">Pēdējais ienešanas mēģinājums:</translation>
 <translation id="6169916984152623906">Tagad varat privāti pārlūkot saturu, un citas personas, kas izmanto šo ierīci, nevarēs redzēt jūsu darbības. Tomēr lejupielādes un grāmatzīmes tiks saglabātas.</translation>
+<translation id="617256461084925519">Pārlūkā Google Chrome tiek mēģināts verificēt jūsu identitāti, lai varētu ievadīt jūsu maksājumu informāciju.</translation>
 <translation id="6177128806592000436">Savienojums ar šo vietni nav drošs.</translation>
 <translation id="6177531123306197852">Aploksne C2</translation>
 <translation id="6180316780098470077">Intervāls starp atkārtotiem mēģinājumiem</translation>
@@ -2656,6 +2656,7 @@
 <translation id="7518003948725431193">Šādā tīmekļa adresē netika atrasta neviena tīmekļa lapa: <ph name="URL" /></translation>
 <translation id="7521387064766892559">JavaScript</translation>
 <translation id="7521825010239864438">Sadaļa “<ph name="SECTION" />” ir paslēpta</translation>
+<translation id="752189128961566325">Varat to izmantot Google produktos.</translation>
 <translation id="7523408071729642236">Ražošana</translation>
 <translation id="7526934274050461096">Jūsu savienojums ar šo vietni nav privāts.</translation>
 <translation id="7529884293139707752">Mājmācība</translation>
@@ -2883,6 +2884,7 @@
 <translation id="8057711352706143257">Programmatūra <ph name="SOFTWARE_NAME" /> nav pareizi konfigurēta. Atinstalējot programmatūru <ph name="SOFTWARE_NAME" />, parasti problēma tiek novērsta. <ph name="FURTHER_EXPLANATION" /></translation>
 <translation id="8058009102480785916">Pārtikas rūpniecība</translation>
 <translation id="8058603697124206642">nav nepieciešama</translation>
+<translation id="8064892030280197386">verificēt jūsu identitāti, lai varētu ievadīt jūsu maksājumu informāciju.</translation>
 <translation id="8066225060526005217">Tiek pārvaldīta sīkfailu iestatījumos</translation>
 <translation id="8067872629359326442">Jūs tikko ievadījāt savu paroli maldinošā vietnē. Chromium var palīdzēt. Lai mainītu paroli un paziņotu uzņēmumam Google, ka jūsu konts, iespējams, ir apdraudēts, noklikšķiniet uz pogas Aizsargāt kontu.</translation>
 <translation id="8070439594494267500">Lietotnes ikona</translation>
diff --git a/components/strings/components_strings_mk.xtb b/components/strings/components_strings_mk.xtb
index a17bc3d..370d11ca 100644
--- a/components/strings/components_strings_mk.xtb
+++ b/components/strings/components_strings_mk.xtb
@@ -1793,6 +1793,7 @@
 <translation id="5344579389779391559">Страницава можеби ќе се обиде да ви наплати пари</translation>
 <translation id="5347645913823149105">Копче „Приспособи фонтови во Chrome“, притиснете Enter за да ги приспособите големините и типовите на фонтовите во Chrome</translation>
 <translation id="5355557959165512791">Не може да го посетите <ph name="SITE" /> во моментов затоа што неговиот сертификат е повлечен. Грешките на мрежата и нападите обично се привремени, така што страницава веројатно ќе работи подоцна.</translation>
+<translation id="5356345925629253198">Може да ги користите зачуваните адреси на производите на Google. Адресава ќе се зачува во вашата сметка на Google (<ph name="ACCOUNT" />).</translation>
 <translation id="5357848622083956825">Визуелна уметност и дизајн</translation>
 <translation id="536296301121032821">Не успеа да складира поставки за правило</translation>
 <translation id="5363309033720083897">Сериска порта што ја дозволил вашиот администратор</translation>
@@ -1918,7 +1919,6 @@
 <translation id="5695542892312572833">Дали сакате да користите Windows Hello за да го потврдите и завршите купувањето?</translation>
 <translation id="5701381305118179107">Центар</translation>
 <translation id="570530837424789914">Управувајте…</translation>
-<translation id="5706906618852913030">Дали да се зачува во сметката?</translation>
 <translation id="5707154300732650394">Продолжете со патувањето</translation>
 <translation id="57094364128775171">Предложи силна лозинка…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_ml.xtb b/components/strings/components_strings_ml.xtb
index 13b95ff..7bfcc15 100644
--- a/components/strings/components_strings_ml.xtb
+++ b/components/strings/components_strings_ml.xtb
@@ -1918,7 +1918,6 @@
 <translation id="5695542892312572833">പരിശോധിച്ചുറപ്പിക്കാനും വാങ്ങൽ പൂർത്തിയാക്കാനും Windows Hello ഉപയോഗിക്കണോ?</translation>
 <translation id="5701381305118179107">മധ്യഭാഗം</translation>
 <translation id="570530837424789914">മാനേജ് ചെയ്യുക...</translation>
-<translation id="5706906618852913030">അക്കൗണ്ടിൽ സംരക്ഷിക്കണോ?</translation>
 <translation id="5707154300732650394">നിങ്ങളുടെ ജേർണി പുനരാരംഭിക്കുക</translation>
 <translation id="57094364128775171">ശക്തമായ പാസ്‌വേഡ് നിർദ്ദേശിക്കുക…</translation>
 <translation id="571403275720188526">(arm64)</translation>
@@ -2105,6 +2104,7 @@
 <translation id="6165508094623778733">കൂടുതലറിയുക</translation>
 <translation id="6167577165590485365">അവസാനം ലഭ്യമാക്കാൻ ശ്രമിച്ചത്:</translation>
 <translation id="6169916984152623906">നിങ്ങൾക്കിപ്പോൾ സ്വകാര്യമായി ബ്രൗസ് ചെയ്യാം, ഈ ഉപകരണം ഉപയോഗിക്കുന്ന മറ്റ് ആളുകൾക്ക് നിങ്ങളുടെ ആക്‌റ്റിവിറ്റി കാണാനാവില്ല. എന്നാൽ ഡൗൺലോഡുകളും ബുക്ക്‌മാർക്കുകളും സംരക്ഷിക്കപ്പെടും.</translation>
+<translation id="617256461084925519">നിങ്ങളുടെ പേയ്മെന്റ് വിവരങ്ങൾ പൂരിപ്പിക്കുന്നതിനായി Google Chrome ഇത് നിങ്ങളാണെന്ന് പരിശോധിച്ചുറപ്പിക്കുകയാണ്.</translation>
 <translation id="6177128806592000436">ഈ സൈറ്റിലേക്കുള്ള നിങ്ങളുടെ കണക്ഷൻ സുരക്ഷിതമല്ല</translation>
 <translation id="6177531123306197852">Envelope C2</translation>
 <translation id="6180316780098470077">വീണ്ടും ശ്രമിക്കുന്നതിനുള്ള ഇടവേള</translation>
@@ -2654,6 +2654,7 @@
 <translation id="7518003948725431193">വെബ് വിലാസത്തിനായി വെബ്‌പേജൊന്നും കണ്ടെത്തിയില്ല: <ph name="URL" /></translation>
 <translation id="7521387064766892559">JavaScript</translation>
 <translation id="7521825010239864438">"<ph name="SECTION" />" വിഭാഗം മറച്ചിരിക്കുന്നു</translation>
+<translation id="752189128961566325">Google ഉൽപ്പന്നങ്ങളിലുടനീളം നിങ്ങൾക്കിത് ഉപയോഗിക്കാം</translation>
 <translation id="7523408071729642236">ഉത്പാദനം</translation>
 <translation id="7526934274050461096">ഈ സൈറ്റിലേക്കുള്ള നിങ്ങളുടെ കണക്ഷൻ സ്വകാര്യമല്ല</translation>
 <translation id="7529884293139707752">ഹോംസ്‌കൂളിംഗ്</translation>
@@ -2881,6 +2882,7 @@
 <translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" ശരിയായി കോൺഫിഗർ ചെയ്‌‌തിട്ടില്ല. സാധാരണഗതിയിൽ "<ph name="SOFTWARE_NAME" />" അൺഇൻസ്‌റ്റാൾ ചെയ്യുന്നതിലൂടെ ഈ പ്രശ്‌നം പരിഹരിക്കാം. <ph name="FURTHER_EXPLANATION" /></translation>
 <translation id="8058009102480785916">ഭക്ഷ്യോൽപ്പാദനം</translation>
 <translation id="8058603697124206642">ആവശ്യമില്ല</translation>
+<translation id="8064892030280197386">നിങ്ങളുടെ പേയ്മെന്റ് വിവരങ്ങൾ പൂരിപ്പിക്കുന്നതിനായി ഇത് നിങ്ങളാണെന്ന് പരിശോധിച്ചുറപ്പിക്കുക.</translation>
 <translation id="8066225060526005217">കുക്കി ക്രമീകരണം മാനേജ് ചെയ്യുന്നത്</translation>
 <translation id="8067872629359326442">വഞ്ചനാപരമായ സൈറ്റിൽ നിങ്ങൾ ഇപ്പോൾ പാസ്‍വേഡ് നൽകി. Chromium-ന് സഹായിക്കാനാവും. നിങ്ങളുടെ പാസ്‌വേഡ് മാറ്റാനും നിങ്ങളുടെ അക്കൗണ്ട് അപകടത്തിലായിരിക്കാമെന്ന് Google-നെ അറിയിക്കാനും 'അക്കൗണ്ട് പരിരക്ഷിക്കുക' ക്ലിക്ക് ചെയ്യുക.</translation>
 <translation id="8070439594494267500">ആപ്പ് ഐക്കൺ</translation>
diff --git a/components/strings/components_strings_mn.xtb b/components/strings/components_strings_mn.xtb
index e0845d52..32878f0 100644
--- a/components/strings/components_strings_mn.xtb
+++ b/components/strings/components_strings_mn.xtb
@@ -1920,7 +1920,6 @@
 <translation id="5695542892312572833">Та худалдан авалтаа бататгах болон дуусгахын тулд Windows Hello-г ашиглах уу?</translation>
 <translation id="5701381305118179107">Төв</translation>
 <translation id="570530837424789914">Удирдах...</translation>
-<translation id="5706906618852913030">Бүртгэлд хадгалах уу?</translation>
 <translation id="5707154300732650394">Аяллаа үргэлжлүүлэх</translation>
 <translation id="57094364128775171">Хүчтэй нууц үг санал болгох...</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_mr.xtb b/components/strings/components_strings_mr.xtb
index 40768e8..e0026f3 100644
--- a/components/strings/components_strings_mr.xtb
+++ b/components/strings/components_strings_mr.xtb
@@ -1918,7 +1918,6 @@
 <translation id="5695542892312572833">तुमच्या खरेदीची पडताळणी करण्यासाठी आणि ती पूर्ण करण्यासाठी Windows Hello वापरायचे आहे का?</translation>
 <translation id="5701381305118179107">मध्यभागी</translation>
 <translation id="570530837424789914">व्यवस्थापित करा...</translation>
-<translation id="5706906618852913030">खाते मध्ये सेव्ह करायचा आहे का?</translation>
 <translation id="5707154300732650394">तुमचा प्रवास पुन्हा सुरू करा</translation>
 <translation id="57094364128775171">क्लिष्ट पासवर्ड सुचवा…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_ms.xtb b/components/strings/components_strings_ms.xtb
index 2f0ff582..b5442d0 100644
--- a/components/strings/components_strings_ms.xtb
+++ b/components/strings/components_strings_ms.xtb
@@ -1920,7 +1920,6 @@
 <translation id="5695542892312572833">Gunakan Windows Hello untuk mengesahkan dan melengkapkan pembelian anda?</translation>
 <translation id="5701381305118179107">Tengah</translation>
 <translation id="570530837424789914">Urus...</translation>
-<translation id="5706906618852913030">Simpan dalam Account?</translation>
 <translation id="5707154300732650394">Sambung semula perjalanan anda</translation>
 <translation id="57094364128775171">Cadangkan kata laluan yang kukuh…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_my.xtb b/components/strings/components_strings_my.xtb
index e21577ee..1123e71 100644
--- a/components/strings/components_strings_my.xtb
+++ b/components/strings/components_strings_my.xtb
@@ -1920,7 +1920,6 @@
 <translation id="5695542892312572833">သင့်ဝယ်ယူမှုကို စိစစ်ရန်နှင့် အပြီးသတ်ရန် Windows Hello ကို သုံးမလား။</translation>
 <translation id="5701381305118179107">အလယ်</translation>
 <translation id="570530837424789914">စီမံရန်...</translation>
-<translation id="5706906618852913030">အကောင့်တွင် သိမ်းမလား။</translation>
 <translation id="5707154300732650394">သင့်ခရီးစဉ်ကို ဆက်လုပ်ရန်</translation>
 <translation id="57094364128775171">ခိုင်မာသည့် စကားဝှက် အကြံပြုရန်…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_ne.xtb b/components/strings/components_strings_ne.xtb
index 05e7b7e..a995f10 100644
--- a/components/strings/components_strings_ne.xtb
+++ b/components/strings/components_strings_ne.xtb
@@ -1916,7 +1916,6 @@
 <translation id="5695542892312572833">आफ्नो खरिद पुष्टि तथा पूरा गर्न Windows Hello प्रयोग गर्ने हो?</translation>
 <translation id="5701381305118179107">केन्द्र</translation>
 <translation id="570530837424789914">व्यवस्थित गर्नुहोस्...</translation>
-<translation id="5706906618852913030">खातामा सेभ गर्ने हो?</translation>
 <translation id="5707154300732650394">खोज्ने क्रम सुचारु गर्नुहोस्</translation>
 <translation id="57094364128775171">भरपर्दो पासवर्ड सिफारिस गर्नुहोस्…</translation>
 <translation id="571403275720188526">(arm64)</translation>
@@ -2103,6 +2102,7 @@
 <translation id="6165508094623778733">थप जान्नुहोस्</translation>
 <translation id="6167577165590485365">पछिल्लो पटक नीति प्राप्त गर्ने प्रयास गरिएको मिति:</translation>
 <translation id="6169916984152623906">तपाईं अब निजी रूपमा ब्राउज गर्न सक्नुहुन्छ र यो डिभाइसको प्रयोग गर्ने अन्य व्यक्तिहरूले तपाईंको क्रियाकलाप देख्ने छैनन्। यद्यपि, तपाईंका डाउनलोड र बुकमार्कहरू सुरक्षित गरिनेछन्।</translation>
+<translation id="617256461084925519">Google Chrome ले तपाईंको भुक्तानीसम्बन्धी जानकारी भर्न सकोस् भन्नाका लागि यसले तपाईंको पहिचान पुष्टि गर्न खोज्दै छ।</translation>
 <translation id="6177128806592000436">यस साइटमा तपाईँको जडान सुरक्षित छैन</translation>
 <translation id="6177531123306197852">Envelope C2</translation>
 <translation id="6180316780098470077">पुन: प्रयास गर्न पाइने अन्तराल</translation>
@@ -2654,6 +2654,7 @@
 <translation id="7518003948725431193">निम्न वेब ठेगानाको लागि कुनैपनि वेबपृष्ठ फेला परेन: <ph name="URL" /></translation>
 <translation id="7521387064766892559">JavaScript</translation>
 <translation id="7521825010239864438">"<ph name="SECTION" />" नामक खण्ड लुकाइएको छ</translation>
+<translation id="752189128961566325">तपाईं सेभ गरिएको ठेगाना Google का विभिन्न उत्पादनमा प्रयोग गर्न सक्नुहुन्छ</translation>
 <translation id="7523408071729642236">उत्पादन</translation>
 <translation id="7526934274050461096">यो साइटमा तपाईंको जडान निजी होइन</translation>
 <translation id="7529884293139707752">होमस्कुलिङ</translation>
@@ -2881,6 +2882,7 @@
 <translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" सही तरिकाले कन्फिगर गरिएको छैन। सामान्यतया "<ph name="SOFTWARE_NAME" />" को स्थापना रद्द गरेमा समस्याको समाधान हुन्छ। <ph name="FURTHER_EXPLANATION" /></translation>
 <translation id="8058009102480785916">खाद्यवस्तुको उत्पादन</translation>
 <translation id="8058603697124206642">सहमति जनाउनु पर्दैन</translation>
+<translation id="8064892030280197386">Google Chrome ले तपाईंको भुक्तानीसम्बन्धी जानकारी भर्न सकोस् भन्नाका लागि आफ्नो पहिचान पुष्टि गर्नुहोस्।</translation>
 <translation id="8066225060526005217">कुकीसम्बन्धी सेटिङअनुसार व्यवस्थापन गरिन्छ</translation>
 <translation id="8067872629359326442">तपाईंले भर्खरै कुनै भ्रामक साइटमा आफ्नो पासवर्ड प्रविष्टि गर्नुभएको छ। Chromium ले मद्दत गर्न सक्छ। आफ्नो पासवर्ड परिवर्तन गर्न र आफ्नो खाता जोखिममा हुन सक्छ भनेर Google लाई सूचित गर्न खाता सेभ गर्नुहोस् नामक विकल्पमा क्लिक गर्नुहोस्।</translation>
 <translation id="8070439594494267500">एपको आइकन</translation>
diff --git a/components/strings/components_strings_nl.xtb b/components/strings/components_strings_nl.xtb
index bd7a5d0..b93de66 100644
--- a/components/strings/components_strings_nl.xtb
+++ b/components/strings/components_strings_nl.xtb
@@ -1914,7 +1914,6 @@
 <translation id="5695542892312572833">Windows Hello gebruiken om je aankoop te verifiëren en af te ronden?</translation>
 <translation id="5701381305118179107">Centreren</translation>
 <translation id="570530837424789914">Beheren...</translation>
-<translation id="5706906618852913030">Opslaan in account?</translation>
 <translation id="5707154300732650394">Je traject hervatten</translation>
 <translation id="57094364128775171">Sterk wachtwoord voorstellen…</translation>
 <translation id="571403275720188526">(arm64)</translation>
@@ -2100,6 +2099,7 @@
 <translation id="6165508094623778733">Meer informatie</translation>
 <translation id="6167577165590485365">Laatste ophaalpoging:</translation>
 <translation id="6169916984152623906">Je kunt nu privé browsen, zodat andere mensen die dit apparaat gebruiken, jouw activiteit niet kunnen zien. Downloads en bookmarks worden echter wel opgeslagen.</translation>
+<translation id="617256461084925519">Google Chrome probeert te verifiëren dat jij het bent zodat je betalingsgegevens kunnen worden ingevuld.</translation>
 <translation id="6177128806592000436">Je verbinding met deze site is niet beveiligd</translation>
 <translation id="6177531123306197852">Envelop C2</translation>
 <translation id="6180316780098470077">Interval voor nieuwe poging</translation>
@@ -2651,6 +2651,7 @@
 <translation id="7518003948725431193">Er is geen webpagina gevonden voor het webadres: <ph name="URL" /></translation>
 <translation id="7521387064766892559">JavaScript</translation>
 <translation id="7521825010239864438">Het gedeelte '<ph name="SECTION" />' is verborgen</translation>
+<translation id="752189128961566325">Je kunt het gebruiken in meerdere Google-producten</translation>
 <translation id="7523408071729642236">Productie</translation>
 <translation id="7526934274050461096">Je verbinding met deze site is niet privé</translation>
 <translation id="7529884293139707752">Thuisonderwijs</translation>
@@ -2878,6 +2879,7 @@
 <translation id="8057711352706143257">'<ph name="SOFTWARE_NAME" />' is niet correct geconfigureerd. Als je '<ph name="SOFTWARE_NAME" />' verwijdert, wordt het probleem meestal opgelost. <ph name="FURTHER_EXPLANATION" /></translation>
 <translation id="8058009102480785916">Levensmiddelenindustrie</translation>
 <translation id="8058603697124206642">Niet vereist</translation>
+<translation id="8064892030280197386">verifiëren dat jij het bent zodat je betalingsgegevens kunnen worden ingevuld.</translation>
 <translation id="8066225060526005217">Beheerd door cookie-instellingen</translation>
 <translation id="8067872629359326442">Je hebt zojuist je wachtwoord opgegeven op een misleidende site. Chromium kan je laten zien wat je nu kunt doen. Klik op 'Account beschermen' om je wachtwoord te wijzigen en Google te laten weten dat je account mogelijk gevaar loopt.</translation>
 <translation id="8070439594494267500">App-icoon</translation>
diff --git a/components/strings/components_strings_no.xtb b/components/strings/components_strings_no.xtb
index e3eec6b..60df878 100644
--- a/components/strings/components_strings_no.xtb
+++ b/components/strings/components_strings_no.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Vil du bruke Windows Hello for å verifisere og fullføre kjøpet?</translation>
 <translation id="5701381305118179107">Midtstill</translation>
 <translation id="570530837424789914">Administrer…</translation>
-<translation id="5706906618852913030">Lagre i kontoen?</translation>
 <translation id="5707154300732650394">Fortsett reisen</translation>
 <translation id="57094364128775171">Foreslå et sterkt passord…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_or.xtb b/components/strings/components_strings_or.xtb
index b38a6ffc..65449859 100644
--- a/components/strings/components_strings_or.xtb
+++ b/components/strings/components_strings_or.xtb
@@ -1791,6 +1791,7 @@
 <translation id="5344579389779391559">ଏହି ପୃଷ୍ଠା ଆପଣଙ୍କ ଠାରୁ ଶୁଳ୍କ ନେବା ପାଇଁ ଚେଷ୍ଟା କରିପାରେ</translation>
 <translation id="5347645913823149105">"Chromeରେ ଫଣ୍ଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରନ୍ତୁ" ବଟନ, Chromeରେ ଫଣ୍ଟ ଆକାର ଏବଂ ଟାଇପଫେସକୁ କଷ୍ଟମାଇଜ କରିବା ପାଇଁ Enter ଦବାନ୍ତୁ</translation>
 <translation id="5355557959165512791">ବର୍ତ୍ତମାନ, ଆପଣ <ph name="SITE" />କୁ ଯାଇପାରିବେ ନାହିଁ କାରଣ ଏହାର ସାର୍ଟିଫିକେଟ୍‌ ପ୍ରତ୍ୟାହାର କରିନିଆଯାଇଛି। ସାଧାରଣତଃ ନେଟ୍‍ୱର୍କ ତ୍ରୁଟି ଏବଂ ଆକ୍ରମଣ ଅସ୍ଥାୟୀ ଅଟେ, ତେଣୁ ସମ୍ଭବତଃ ଏହି ପୃଷ୍ଠା ପରେ କାର୍ଯ୍ୟ କରିବ।</translation>
+<translation id="5356345925629253198">ସେଭ କରାଯାଇଥିବା ଠିକଣାଗୁଡ଼ିକୁ ଆପଣ ସମଗ୍ର Google ପ୍ରଡକ୍ଟରେ ବ୍ୟବହାର କରିପାରିବେ। ଏହି ଠିକଣାକୁ ଆପଣଙ୍କ Google ଆକାଉଣ୍ଟ (<ph name="ACCOUNT" />)ରେ ସେଭ କରାଯିବ।</translation>
 <translation id="5357848622083956825">ଭିଜୁଆଲ ଆର୍ଟ ଏବଂ ଡିଜାଇନ</translation>
 <translation id="536296301121032821">ନୀତି ସେଟିଂସ୍ ଷ୍ଟୋର୍ କରିବାରେ ବିଫଳ ହେଲା</translation>
 <translation id="5363309033720083897">ଆପଣଙ୍କ ଆଡମିନିଷ୍ଟ୍ରେଟରଙ୍କ ଦ୍ୱାରା ସିରିଅଲ୍ ପୋର୍ଟକୁ ଅନୁମତି ଦିଆଯାଇଛି</translation>
@@ -1916,7 +1917,6 @@
 <translation id="5695542892312572833">ଆପଣଙ୍କ କ୍ରୟକୁ ଯାଞ୍ଚ କରିବା ଏବଂ ସମ୍ପୂର୍ଣ୍ଣ କରିବାକୁ Windows Hello ବ୍ୟବହାର କରିବେ?</translation>
 <translation id="5701381305118179107">କେନ୍ଦ୍ର</translation>
 <translation id="570530837424789914">ପରିଚାଳନା…</translation>
-<translation id="5706906618852913030">ଆକାଉଣ୍ଟରେ ସେଭ କରିବେ?</translation>
 <translation id="5707154300732650394">ଆପଣଙ୍କ ସନ୍ଧାନ ପୁଣି ଆରମ୍ଭ କରନ୍ତୁ</translation>
 <translation id="57094364128775171">ଜଟିଳ ପାସ୍‌ୱର୍ଡ ପରାମର୍ଶ କରନ୍ତୁ…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_pa.xtb b/components/strings/components_strings_pa.xtb
index 6d137c5e..3592329 100644
--- a/components/strings/components_strings_pa.xtb
+++ b/components/strings/components_strings_pa.xtb
@@ -1916,7 +1916,6 @@
 <translation id="5695542892312572833">ਕੀ ਤੁਸੀਂ ਆਪਣੀਆਂ ਖਰੀਦਾਂ ਦੀ ਪੁਸ਼ਟੀ ਕਰਨ ਅਤੇ ਉਹਨਾਂ ਨੂੰ ਪੂਰਾ ਕਰਨ ਲਈ Windows Hello ਵਰਤਣਾ ਚਾਹੁੰਦੇ ਹੋ?</translation>
 <translation id="5701381305118179107">ਕੇਂਦਰ</translation>
 <translation id="570530837424789914">ਪ੍ਰਬੰਧਨ ਕਰੋ...</translation>
-<translation id="5706906618852913030">ਕੀ ਖਾਤੇ ਵਿੱਚ ਰੱਖਿਅਤ ਕਰਨਾ ਹੈ?</translation>
 <translation id="5707154300732650394">ਆਪਣਾ ਖੋਜ ਸਫ਼ਰ ਨੂੰ ਮੁੜ-ਚਾਲੂ ਕਰੋ</translation>
 <translation id="57094364128775171">ਮਜ਼ਬੂਤ ਪਾਸਵਰਡ ਸੁਝਾਓ…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_pl.xtb b/components/strings/components_strings_pl.xtb
index 84395a32..dbe1865 100644
--- a/components/strings/components_strings_pl.xtb
+++ b/components/strings/components_strings_pl.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Czy do zweryfikowania i dokończenia zakupu użyć Windows Hello?</translation>
 <translation id="5701381305118179107">Wyśrodkuj</translation>
 <translation id="570530837424789914">Zarządzaj…</translation>
-<translation id="5706906618852913030">Zapisać na koncie?</translation>
 <translation id="5707154300732650394">Wznów swoją serię czynności</translation>
 <translation id="57094364128775171">Zaproponuj silne hasło…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_pt-BR.xtb b/components/strings/components_strings_pt-BR.xtb
index cd0d56d..b0e959f 100644
--- a/components/strings/components_strings_pt-BR.xtb
+++ b/components/strings/components_strings_pt-BR.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Usar o Windows Hello para verificar e concluir a compra?</translation>
 <translation id="5701381305118179107">Centralizar</translation>
 <translation id="570530837424789914">Gerenciar…</translation>
-<translation id="5706906618852913030">Salvar na conta?</translation>
 <translation id="5707154300732650394">Retomar a jornada</translation>
 <translation id="57094364128775171">Sugerir senha forte…</translation>
 <translation id="571403275720188526">(arm64)</translation>
@@ -3021,7 +3020,7 @@
 <translation id="8398335999901363925">Formas de pagamento disponíveis para preenchimento com um toque abertas na altura máxima.</translation>
 <translation id="8398790343843005537">Encontrar seu smartphone</translation>
 <translation id="8405579342203358118">Gerencie quais informações são sincronizadas nas configurações do Chrome</translation>
-<translation id="8406071103346257942">Parar de usar o bloqueio de tela para preencher senhas</translation>
+<translation id="8406071103346257942">parar de usar o bloqueio de tela para preencher senhas</translation>
 <translation id="8409413588194360210">gerenciadores de pagamento</translation>
 <translation id="8412145213513410671">Falhas (<ph name="CRASH_COUNT" />)</translation>
 <translation id="8412392972487953978">Você deve inserir a mesma senha duas vezes.</translation>
diff --git a/components/strings/components_strings_pt-PT.xtb b/components/strings/components_strings_pt-PT.xtb
index 2c6d435..2bc1835f2 100644
--- a/components/strings/components_strings_pt-PT.xtb
+++ b/components/strings/components_strings_pt-PT.xtb
@@ -1793,6 +1793,7 @@
 <translation id="5344579389779391559">Esta página pode tentar cobrar-lhe dinheiro</translation>
 <translation id="5347645913823149105">Botão Personalizar tipos de letra no Chrome, prima Enter para personalizar os tipos de letra e os respetivos tamanhos no Chrome</translation>
 <translation id="5355557959165512791">Não pode visitar <ph name="SITE" /> neste momento, porque o certificado foi revogado. Os erros de rede e os ataques são geralmente temporários, pelo que esta página deverá funcionar mais tarde.</translation>
+<translation id="5356345925629253198">Pode usar moradas guardadas em produtos Google. Esta morada vai ser guardada na sua Conta Google (<ph name="ACCOUNT" />).</translation>
 <translation id="5357848622083956825">Arte visual e design</translation>
 <translation id="536296301121032821">Falha ao armazenar as definições da política</translation>
 <translation id="5363309033720083897">Porta de série permitida pelo seu administrador</translation>
@@ -1918,7 +1919,6 @@
 <translation id="5695542892312572833">Pretende utilizar o Windows Hello para validar e concluir a sua compra?</translation>
 <translation id="5701381305118179107">Centrar</translation>
 <translation id="570530837424789914">Gerir…</translation>
-<translation id="5706906618852913030">Guardar na conta?</translation>
 <translation id="5707154300732650394">Retomar percurso</translation>
 <translation id="57094364128775171">Sugerir palavra-passe forte…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_ro.xtb b/components/strings/components_strings_ro.xtb
index cb3f643..2281b29 100644
--- a/components/strings/components_strings_ro.xtb
+++ b/components/strings/components_strings_ro.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Folosești Windows Hello ca să confirmi și finalizezi achiziția?</translation>
 <translation id="5701381305118179107">Pe centru</translation>
 <translation id="570530837424789914">Gestionează...</translation>
-<translation id="5706906618852913030">Salvezi în cont?</translation>
 <translation id="5707154300732650394">Continuă-ți parcursul</translation>
 <translation id="57094364128775171">Sugerează o parolă puternică…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_ru.xtb b/components/strings/components_strings_ru.xtb
index c2b65c0..05ad1a8 100644
--- a/components/strings/components_strings_ru.xtb
+++ b/components/strings/components_strings_ru.xtb
@@ -1792,6 +1792,7 @@
 <translation id="5344579389779391559">Если вы откроете эту страницу, с вашего счета могут быть списаны средства</translation>
 <translation id="5347645913823149105">Кнопка "Настроить шрифты в Chrome". Нажмите Ввод, чтобы настроить начертания и размеры шрифтов в Chrome.</translation>
 <translation id="5355557959165512791">Сертификат веб-сайта <ph name="SITE" /> отозван. Открыть сайт в настоящее время нельзя. Сбой мог быть вызван сетевой ошибкой или действиями злоумышленников. Скорее всего, сайт заработает через некоторое время.</translation>
+<translation id="5356345925629253198">Адрес будет сохранен в аккаунте <ph name="ACCOUNT" />. Сохраненные адреса можно использовать в продуктах Google.</translation>
 <translation id="5357848622083956825">Изобразительное искусство и дизайн</translation>
 <translation id="536296301121032821">Не удалось сохранить настройки политики</translation>
 <translation id="5363309033720083897">Последовательный порт разрешен администратором</translation>
@@ -1917,7 +1918,6 @@
 <translation id="5695542892312572833">Использовать Windows Hello для подтверждения покупки?</translation>
 <translation id="5701381305118179107">Выровнять по центру</translation>
 <translation id="570530837424789914">Управление…</translation>
-<translation id="5706906618852913030">Сохранить в аккаунте?</translation>
 <translation id="5707154300732650394">Продолжить поиск в истории</translation>
 <translation id="57094364128775171">Сгенерировать надежный пароль</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_si.xtb b/components/strings/components_strings_si.xtb
index 3364063..e6add87 100644
--- a/components/strings/components_strings_si.xtb
+++ b/components/strings/components_strings_si.xtb
@@ -1793,6 +1793,7 @@
 <translation id="5344579389779391559">මෙම පිටුව ඔබේ මුදල මාරු කිරීමට උත්සාහ කළ හැක</translation>
 <translation id="5347645913823149105">Chrome තුළ අකුරු වර්ගය අභිරුචිකරණය කරන්න බොත්තම, Chrome තුළ අකුරු වර්ග තරම සහ මුහුණත අභිරුචිකරණය කිරීමට Enter ඔබන්න</translation>
 <translation id="5355557959165512791">ඔබට මේ දැන් <ph name="SITE" /> වෙත එහි සහතිකය අහෝසි කර ඇති බැවින් පිවිසිය නොහැක. ජාල දෝෂ සහ ප්‍රහාර සාමාන්‍යයෙන් තාවකාලිකය, එනිසා මෙම පිටුව සමහර විට පසුව වැඩ කරනු ඇත.</translation>
+<translation id="5356345925629253198">ඔබට Google නිෂ්පාදන හරහා සුරැකි ලිපින භාවිතා කළ හැක. මෙම ලිපිනය ඔබේ Google ගිණුමේ (<ph name="ACCOUNT" />) සුරකිනු ඇත.</translation>
 <translation id="5357848622083956825">දෘශ්‍ය කලා සහ මෝස්‌තර</translation>
 <translation id="536296301121032821">ප්‍රතිපත්ති සැකසුම් ගබඩා කිරීමට අසමත් විය</translation>
 <translation id="5363309033720083897">ඔබගේ පරිපාලක විසින් ඉඩ දෙන අනුක්‍රමික තොට</translation>
@@ -1918,7 +1919,6 @@
 <translation id="5695542892312572833">ඔබගේ මිලදී ගැනීම සත්‍යාපනය කිරීමට සහ සම්පූර්ණ කිරීමට Windows Hello භාවිත කරන්නද?</translation>
 <translation id="5701381305118179107">මධ්‍ය</translation>
 <translation id="570530837424789914">කළමනාකරණය කරන්න...</translation>
-<translation id="5706906618852913030">ගිණුමේ සුරකින්න ද?</translation>
 <translation id="5707154300732650394">ඔබගේ සංචාරය නැවත පටන් ගන්න</translation>
 <translation id="57094364128775171">ප්‍රබල මුරපදයක් යෝජනා කරන්න...</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_sk.xtb b/components/strings/components_strings_sk.xtb
index 28d67d5..e810de7d 100644
--- a/components/strings/components_strings_sk.xtb
+++ b/components/strings/components_strings_sk.xtb
@@ -1789,6 +1789,7 @@
 <translation id="5344579389779391559">Táto stránka sa vám môže pokúsiť účtovať poplatky</translation>
 <translation id="5347645913823149105">Tlačidlo na prispôsobenie písma v Chrome, klávesom Enter si prispôsobte veľkosť a typ písma v Chrome</translation>
 <translation id="5355557959165512791">Web <ph name="SITE" /> momentálne nemôžete navštíviť, pretože tento certifikát bol odvolaný. Chyby siete a útoky sú zvyčajne dočasné, takže by táto stránka mala neskôr pravdepodobne fungovať.</translation>
+<translation id="5356345925629253198">V službách Googlu môžete používať uložené adresy. Táto adresa bude uložená do vášho účtu Google (<ph name="ACCOUNT" />).</translation>
 <translation id="5357848622083956825">Výtvarné umenie a dizajn</translation>
 <translation id="536296301121032821">Nastavenia pravidla sa nepodarilo uložiť</translation>
 <translation id="5363309033720083897">Sériový port povolený vaším správcom</translation>
@@ -1914,7 +1915,6 @@
 <translation id="5695542892312572833">Chcete svoj nákup overiť a dokončiť pomocou funkcie Windows Hello?</translation>
 <translation id="5701381305118179107">Na stred</translation>
 <translation id="570530837424789914">Spravovať...</translation>
-<translation id="5706906618852913030">Chcete uložiť v účte?</translation>
 <translation id="5707154300732650394">Pokračovať v ceste</translation>
 <translation id="57094364128775171">Navrhnúť silné heslo…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_sl.xtb b/components/strings/components_strings_sl.xtb
index 57c74548..6f5bce4 100644
--- a/components/strings/components_strings_sl.xtb
+++ b/components/strings/components_strings_sl.xtb
@@ -1920,7 +1920,6 @@
 <translation id="5695542892312572833">Ali želite za potrditev in dokončanje nakupa uporabiti Windows Hello?</translation>
 <translation id="5701381305118179107">Na sredino</translation>
 <translation id="570530837424789914">Upravljanje ...</translation>
-<translation id="5706906618852913030">Želite shraniti v računu?</translation>
 <translation id="5707154300732650394">Nadaljevanje poti</translation>
 <translation id="57094364128775171">Predlagaj zapleteno geslo …</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_sq.xtb b/components/strings/components_strings_sq.xtb
index 3f08afd5..8da739a 100644
--- a/components/strings/components_strings_sq.xtb
+++ b/components/strings/components_strings_sq.xtb
@@ -1793,6 +1793,7 @@
 <translation id="5344579389779391559">Kjo faqe mund të përpiqet të të tarifojë në para</translation>
 <translation id="5347645913823149105">Butoni "Personalizo fontet në Chrome". Shtyp "Enter" për të personalizuar madhësitë e fonteve dhe llojin e karaktereve në Chrome</translation>
 <translation id="5355557959165512791">Nuk mund ta vizitosh <ph name="SITE" /> tani, sepse certifikata e tij është revokuar. Gabimet dhe sulmet në rrjet zakonisht janë të përkohshme, prandaj kjo faqe ndoshta do të punojë më vonë.</translation>
+<translation id="5356345925629253198">Adresat e ruajtura mund t'i përdorësh nëpër produktet e Google. Kjo adresë do të ruhet në "Llogarinë tënde të Google" (<ph name="ACCOUNT" />).</translation>
 <translation id="5357848622083956825">Artet pamore dhe dizajni</translation>
 <translation id="536296301121032821">Dështoi në ruajtjen e cilësimeve të politikës.</translation>
 <translation id="5363309033720083897">Porta seriale e lejuar nga administratori yt</translation>
@@ -1918,7 +1919,6 @@
 <translation id="5695542892312572833">Dëshiron të përdorësh Windows Hello për të verifikuar dhe përfunduar blerjen?</translation>
 <translation id="5701381305118179107">Qendër</translation>
 <translation id="570530837424789914">Menaxho...</translation>
-<translation id="5706906618852913030">Të ruhet te llogaria?</translation>
 <translation id="5707154300732650394">Vazhdo udhëtimin tënd</translation>
 <translation id="57094364128775171">Sugjero fjalëkalim të fortë…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_sr-Latn.xtb b/components/strings/components_strings_sr-Latn.xtb
index c9990f662..c167228 100644
--- a/components/strings/components_strings_sr-Latn.xtb
+++ b/components/strings/components_strings_sr-Latn.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Želite da koristite Windows Hello da biste potvrdili i završili kupovinu?</translation>
 <translation id="5701381305118179107">Centriraj</translation>
 <translation id="570530837424789914">Upravljajte...</translation>
-<translation id="5706906618852913030">Želite da sačuvate na nalogu?</translation>
 <translation id="5707154300732650394">Nastavite put</translation>
 <translation id="57094364128775171">Predloži jaku lozinku…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_sr.xtb b/components/strings/components_strings_sr.xtb
index 7c89e1d..dc92d823 100644
--- a/components/strings/components_strings_sr.xtb
+++ b/components/strings/components_strings_sr.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Желите да користите Windows Hello да бисте потврдили и завршили куповину?</translation>
 <translation id="5701381305118179107">Центрирај</translation>
 <translation id="570530837424789914">Управљајте...</translation>
-<translation id="5706906618852913030">Желите да сачувате на налогу?</translation>
 <translation id="5707154300732650394">Наставите пут</translation>
 <translation id="57094364128775171">Предложи јаку лозинку…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_sv.xtb b/components/strings/components_strings_sv.xtb
index 552e797..f535018 100644
--- a/components/strings/components_strings_sv.xtb
+++ b/components/strings/components_strings_sv.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Vill du verifiera och slutföra köpet med Windows Hello?</translation>
 <translation id="5701381305118179107">Centrera</translation>
 <translation id="570530837424789914">Hantera …</translation>
-<translation id="5706906618852913030">Vill du spara i kontot?</translation>
 <translation id="5707154300732650394">Återuppta sökningen</translation>
 <translation id="57094364128775171">Föreslå ett starkt lösenord …</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_sw.xtb b/components/strings/components_strings_sw.xtb
index 6d31b58..1cff44b 100644
--- a/components/strings/components_strings_sw.xtb
+++ b/components/strings/components_strings_sw.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Ungependa kutumia Windows Hello kuthibitisha na kukamilisha ununuzi wako?</translation>
 <translation id="5701381305118179107">Katikati</translation>
 <translation id="570530837424789914">Dhibiti...</translation>
-<translation id="5706906618852913030">Je, ungependa kuhifadhi kwenye Akaunti?</translation>
 <translation id="5707154300732650394">Endelea na ziara yako</translation>
 <translation id="57094364128775171">Pendekeza nenosiri thabiti…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_ta.xtb b/components/strings/components_strings_ta.xtb
index f02dbfe0..5e3c4b1 100644
--- a/components/strings/components_strings_ta.xtb
+++ b/components/strings/components_strings_ta.xtb
@@ -1915,7 +1915,6 @@
 <translation id="5695542892312572833">உங்கள் பர்ச்சேஸைச் சரிபார்த்து நிறைவுசெய்ய Windows Helloவைப் பயன்படுத்த விரும்புகிறீர்களா?</translation>
 <translation id="5701381305118179107">மையம்</translation>
 <translation id="570530837424789914">நிர்வகி...</translation>
-<translation id="5706906618852913030">கணக்கில் சேமிக்கவா?</translation>
 <translation id="5707154300732650394">உலாவலைத் தொடர்க</translation>
 <translation id="57094364128775171">வலுவான கடவுச்சொல்லைப் பரிந்துரைசெய்…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_te.xtb b/components/strings/components_strings_te.xtb
index 44f6a11..406161a9 100644
--- a/components/strings/components_strings_te.xtb
+++ b/components/strings/components_strings_te.xtb
@@ -1921,7 +1921,6 @@
 <translation id="5695542892312572833">మీ కొనుగోలును వెరిఫై చేసి, పూర్తి చేయడానికి Windows Helloను ఉపయోగించాలా?</translation>
 <translation id="5701381305118179107">మధ్యకు</translation>
 <translation id="570530837424789914">నిర్వహించండి...</translation>
-<translation id="5706906618852913030">ఖాతాలో సేవ్ చేయాలా?</translation>
 <translation id="5707154300732650394">మీ సెర్చ్‌ను కొనసాగించండి</translation>
 <translation id="57094364128775171">బలమైన పాస్‌వర్డ్‌ను సూచించండి…</translation>
 <translation id="571403275720188526">(arm64)</translation>
@@ -2108,6 +2107,7 @@
 <translation id="6165508094623778733">మరింత తెలుసుకోండి</translation>
 <translation id="6167577165590485365">చివరిగా పొందడానికి ప్రయత్నించింది:</translation>
 <translation id="6169916984152623906">‌ఇప్పుడు మీరు వ్యక్తిగతంగా బ్రౌజ్ చేయవచ్చు మరియు ఈ పరికరాన్ని ఉపయోగించే ఇతర వ్యక్తులకు మీ కార్య‌క‌లాపం కనిపించదు. అయినప్పటికీ, డౌన్‌లోడ్‌లు మరియు బుక్‌మార్క్‌లు సేవ్ చేయబడతాయి.</translation>
+<translation id="617256461084925519">ఇది మీరేనని వెరిఫై చేయడానికి Google Chrome ట్రై చేస్తోంది, తద్వారా దీనిని మీ పేమెంట్ సమాచారంలో ఫిల్ చేయవచ్చు.</translation>
 <translation id="6177128806592000436">ఈ సైట్‌తో మీకున్న కనెక్షన్ సురక్షితంగా లేదు</translation>
 <translation id="6177531123306197852">ఎన్వలప్ C2</translation>
 <translation id="6180316780098470077">పునఃప్రయత్నాల మధ్య విరామం</translation>
@@ -2659,6 +2659,7 @@
 <translation id="7518003948725431193">వెబ్ అడ్రస్‌కు వెబ్‌పేజీ కనుగొనబడలేదు: <ph name="URL" /></translation>
 <translation id="7521387064766892559">JavaScript</translation>
 <translation id="7521825010239864438">"<ph name="SECTION" />" విభాగం దాచబడింది</translation>
+<translation id="752189128961566325">దీనిని Google ప్రోడక్ట్‌ల అంతటా మీరు ఉపయోగించవచ్చు</translation>
 <translation id="7523408071729642236">తయారీ</translation>
 <translation id="7526934274050461096">ఈ సైట్‌తో మీకున్న కనెక్షన్ ప్రైవేట్‌గా లేదు</translation>
 <translation id="7529884293139707752">ఇంటి వద్దనే చదువు నేర్చుకోవడం</translation>
@@ -2886,6 +2887,7 @@
 <translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />"ని సరిగ్గా కాన్ఫిగర్ చేయలేదు. సాధారణంగా "<ph name="SOFTWARE_NAME" />"ని అన్ఇన్‌స్టాల్ చేయడం ద్వారా సమస్య పరిష్కారం కావచ్చు. <ph name="FURTHER_EXPLANATION" /></translation>
 <translation id="8058009102480785916">ఆహార ఉత్పత్తి</translation>
 <translation id="8058603697124206642">అవసరం లేదు</translation>
+<translation id="8064892030280197386">ఇది మీరేనని వెరిఫై చేయండం ద్వారా దీనిని మీ పేమెంట్ సమాచారంలో ఫిల్ చేయవచ్చు.</translation>
 <translation id="8066225060526005217">కుక్కీల సెట్టింగ్‌ల ద్వారా మేనేజ్ చేయబడుతోంది</translation>
 <translation id="8067872629359326442">మీరు మోసపూరితమైన సైట్‌లో మీ పాస్‌వర్డ్‌ను ఎంటర్ చేశారు. Chromium సహాయపడగలదు. మీ పాస్‌వర్డ్‌‌ను మార్చి, మీ ఖాతా ప్రమాదంలో ఉండవచ్చని Googleకు తెలియజేయడానికి, 'ఖాతాను సంరక్షించు'ను క్లిక్ చేయండి.</translation>
 <translation id="8070439594494267500">యాప్ చిహ్నం</translation>
diff --git a/components/strings/components_strings_th.xtb b/components/strings/components_strings_th.xtb
index 3658c16..0da51b1 100644
--- a/components/strings/components_strings_th.xtb
+++ b/components/strings/components_strings_th.xtb
@@ -1918,7 +1918,6 @@
 <translation id="5695542892312572833">ใช้ Windows Hello เพื่อยืนยันและทำการซื้อให้เสร็จใช่ไหม</translation>
 <translation id="5701381305118179107">กึ่งกลาง</translation>
 <translation id="570530837424789914">จัดการ...</translation>
-<translation id="5706906618852913030">บันทึกในบัญชีไหม</translation>
 <translation id="5707154300732650394">สำรวจต่อ</translation>
 <translation id="57094364128775171">แนะนำรหัสผ่านที่รัดกุม…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_tr.xtb b/components/strings/components_strings_tr.xtb
index ed5a4ee..e738cf4 100644
--- a/components/strings/components_strings_tr.xtb
+++ b/components/strings/components_strings_tr.xtb
@@ -1793,6 +1793,7 @@
 <translation id="5344579389779391559">Bu sayfa sizden para almaya çalışabilir</translation>
 <translation id="5347645913823149105">Chrome'daki yazı tiplerini özelleştirin düğmesi, Chrome'daki yazı tipi boyutlarını ve yazı tiplerini özelleştirmek için Enter'a basın</translation>
 <translation id="5355557959165512791">Sertifikası iptal edildiği için <ph name="SITE" /> sitesini şu anda ziyaret edemezsiniz. Ağ hataları ve saldırılar genellikle geçici olduğundan, bu sayfa muhtemelen daha sonra çalışacaktır.</translation>
+<translation id="5356345925629253198">Kayıtlı adresleri tüm Google ürünlerinde kullanabilirsiniz. Bu adres Google Hesabınıza (<ph name="ACCOUNT" />) kaydedilir.</translation>
 <translation id="5357848622083956825">Görsel sanatlar ve tasarım</translation>
 <translation id="536296301121032821">Politika ayarları saklanamadı</translation>
 <translation id="5363309033720083897">Yöneticiniz tarafından izin verilen seri bağlantı noktası</translation>
@@ -1918,7 +1919,6 @@
 <translation id="5695542892312572833">Satın alma işleminizi doğrulayıp tamamlamak için Windows Hello kullanılsın mı?</translation>
 <translation id="5701381305118179107">Ortala</translation>
 <translation id="570530837424789914">Yönet...</translation>
-<translation id="5706906618852913030">Hesaba kaydedilsin mi?</translation>
 <translation id="5707154300732650394">Arama yolculuğunuzu devam ettirin</translation>
 <translation id="57094364128775171">Güçlü şifre öner…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_uk.xtb b/components/strings/components_strings_uk.xtb
index 85892359..e0efa2f8 100644
--- a/components/strings/components_strings_uk.xtb
+++ b/components/strings/components_strings_uk.xtb
@@ -1793,6 +1793,7 @@
 <translation id="5344579389779391559">Ця сторінка може спробувати стягнути плату</translation>
 <translation id="5347645913823149105">Кнопка "Налаштувати шрифти в Chrome"; натисніть Enter, щоб налаштувати розміри та гарнітури шрифтів у Chrome.</translation>
 <translation id="5355557959165512791">Зараз не можна перейти на сторінку <ph name="SITE" />, оскільки цей сертифікат відкликано. Помилки мережі й атаки зазвичай тимчасові, тому ця сторінка, скоріш за все, запрацює пізніше.</translation>
+<translation id="5356345925629253198">Ви можете використовувати збережені адреси в усіх продуктах Google. Цю адресу буде збережено у вашому обліковому записі Google (<ph name="ACCOUNT" />).</translation>
 <translation id="5357848622083956825">Образотворче мистецтво та дизайн</translation>
 <translation id="536296301121032821">Помилка збереження налаштувань правила</translation>
 <translation id="5363309033720083897">Адміністратор дозволив цей послідовний порт</translation>
@@ -1918,7 +1919,6 @@
 <translation id="5695542892312572833">Підтвердити й завершити покупку за допомогою Windows Hello?</translation>
 <translation id="5701381305118179107">По центру</translation>
 <translation id="570530837424789914">Керувати…</translation>
-<translation id="5706906618852913030">Зберегти в обліковому записі?</translation>
 <translation id="5707154300732650394">Відновити сеанс</translation>
 <translation id="57094364128775171">Запропонувати надійний пароль…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_ur.xtb b/components/strings/components_strings_ur.xtb
index 65e915f..bf967f0 100644
--- a/components/strings/components_strings_ur.xtb
+++ b/components/strings/components_strings_ur.xtb
@@ -1921,7 +1921,6 @@
 <translation id="5695542892312572833">‏آپ کی خریداری کی توثیق اور اسے مکمل کرنے کیلئے Windows Hello کا استعمال کریں؟</translation>
 <translation id="5701381305118179107">مرکز</translation>
 <translation id="570530837424789914">نظم کریں…</translation>
-<translation id="5706906618852913030">اکاؤنٹ میں محفوظ کریں؟</translation>
 <translation id="5707154300732650394">اپنا صارف کا تجربہ دوبارہ شروع کریں</translation>
 <translation id="57094364128775171">مضبوط پاس ورڈ تجویز کریں…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_uz.xtb b/components/strings/components_strings_uz.xtb
index 4e68fbc..748399d 100644
--- a/components/strings/components_strings_uz.xtb
+++ b/components/strings/components_strings_uz.xtb
@@ -1788,6 +1788,7 @@
 <translation id="5344579389779391559">Bu sahifa sizdan pul talab qilishi mumkin</translation>
 <translation id="5347645913823149105">Chromeda shriftlarni moslash tugmasi, Chromeda shrift oʻlchami va yozuvlarini moslash uchun Enter tugmasini bosing</translation>
 <translation id="5355557959165512791"><ph name="SITE" /> sayti ochilmadi, bu sayt bekor qilingan sertifikatdan foydalanayotgan bo‘lishi mumkin. Bunday xatolik tarmoq xatoligi va saytga hujumlar bo‘layotganda yuz beradi, lekin keyinroq sayt ishlab ketishi mumkin.</translation>
+<translation id="5356345925629253198">Saqlangan manzillardan Google xizmatlarida foydalanish mumkin. Bu manzil Google hisobingizda (<ph name="ACCOUNT" />) saqlanadi.</translation>
 <translation id="5357848622083956825">Vizual sanʼat va dizayn</translation>
 <translation id="536296301121032821">Tartib-qoida parametrlarini saqlab bo‘lmadi</translation>
 <translation id="5363309033720083897">Seriyali port administrator tomonidan ruxsat etilgan</translation>
@@ -1913,7 +1914,6 @@
 <translation id="5695542892312572833">Xaridingiz Windows Hello orqali tasdiqlansin va bajarilsinmi?</translation>
 <translation id="5701381305118179107">Markaz bo‘yicha tartiblash</translation>
 <translation id="570530837424789914">Boshqarish...</translation>
-<translation id="5706906618852913030">Hisobda saqlansinmi?</translation>
 <translation id="5707154300732650394">Tarixni qaytarish</translation>
 <translation id="57094364128775171">Ishonchli parol yaratish…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_vi.xtb b/components/strings/components_strings_vi.xtb
index b07e1a0..ad8acfcf 100644
--- a/components/strings/components_strings_vi.xtb
+++ b/components/strings/components_strings_vi.xtb
@@ -1919,7 +1919,6 @@
 <translation id="5695542892312572833">Dùng Windows Hello để xác minh và hoàn tất giao dịch mua hàng?</translation>
 <translation id="5701381305118179107">Giữa</translation>
 <translation id="570530837424789914">Quản lý...</translation>
-<translation id="5706906618852913030">Lưu trong Tài khoản?</translation>
 <translation id="5707154300732650394">Tiếp tục hành trình của bạn</translation>
 <translation id="57094364128775171">Đề xuất mật khẩu mạnh…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_zh-CN.xtb b/components/strings/components_strings_zh-CN.xtb
index dbde13e..1142d42 100644
--- a/components/strings/components_strings_zh-CN.xtb
+++ b/components/strings/components_strings_zh-CN.xtb
@@ -1340,7 +1340,7 @@
 <translation id="4282346679996504092">针对此商品的提醒已被关闭,相应书签已被移除</translation>
 <translation id="4285498937028063278">取消固定</translation>
 <translation id="428639260510061158">{NUM_CARDS,plural, =1{这张卡已保存到您的 Google 帐号中}other{这些卡已保存到您的 Google 帐号中}}</translation>
-<translation id="4287495839370498922">在 Chrome 中增强广告隐私权</translation>
+<translation id="4287495839370498922">在 Chrome 中加强广告隐私设置</translation>
 <translation id="4287885627794386150">符合试用条件但处于无效状态</translation>
 <translation id="4297502707443874121">第 <ph name="THUMBNAIL_PAGE" /> 页的缩略图</translation>
 <translation id="4298000214066716287">投资</translation>
@@ -1915,7 +1915,6 @@
 <translation id="5695542892312572833">使用 Windows Hello 验证并完成您的购买交易?</translation>
 <translation id="5701381305118179107">居中</translation>
 <translation id="570530837424789914">管理…</translation>
-<translation id="5706906618852913030">要保存到帐号吗?</translation>
 <translation id="5707154300732650394">继续您的历程</translation>
 <translation id="57094364128775171">建议安全系数高的密码…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_zh-HK.xtb b/components/strings/components_strings_zh-HK.xtb
index e648e8d..2b1aac44 100644
--- a/components/strings/components_strings_zh-HK.xtb
+++ b/components/strings/components_strings_zh-HK.xtb
@@ -1918,7 +1918,6 @@
 <translation id="5695542892312572833">要使用 Windows Hello 驗證並完成購買嗎?</translation>
 <translation id="5701381305118179107">置中</translation>
 <translation id="570530837424789914">管理…</translation>
-<translation id="5706906618852913030">要儲存在帳戶中嗎?</translation>
 <translation id="5707154300732650394">恢復瀏覽過程</translation>
 <translation id="57094364128775171">建議安全性強的密碼…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/strings/components_strings_zh-TW.xtb b/components/strings/components_strings_zh-TW.xtb
index 9c70658f..002badc1 100644
--- a/components/strings/components_strings_zh-TW.xtb
+++ b/components/strings/components_strings_zh-TW.xtb
@@ -918,7 +918,7 @@
 <translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />;按下 Tab 鍵再按下 Enter 鍵即可在 Google 日曆中快速建立新活動</translation>
 <translation id="3261488570342242926">瞭解虛擬卡片</translation>
 <translation id="3264837738038045344">「管理 Chrome 設定」按鈕;按下 Enter 鍵即可前往 Chrome 設定</translation>
-<translation id="3266367459139339908">我們推出了多項新方法,限制網站可為放送個人化廣告取得哪些資訊,例如:</translation>
+<translation id="3266367459139339908">我們推出了一些新的機制,限制網站在放送個人化廣告時,可以取得哪些與使用者相關的資訊,例如:</translation>
 <translation id="3266793032086590337">值 (衝突)</translation>
 <translation id="3266972086368072861">{NUM_COOKIES,plural, =0{未封鎖任何網站 (包括相關網站)}=1{已封鎖 1 個網站 (包括相關網站)}other{已封鎖 # 個網站 (包括相關網站)}}</translation>
 <translation id="3268451620468152448">開啟的分頁</translation>
@@ -1092,7 +1092,7 @@
 <translation id="3678342917559046352">副檔名無效:副檔名的格式必須為 &lt;extension_id&gt;、&lt;extension_id&gt; 或 &lt;update_url&gt; 其中之一。</translation>
 <translation id="3678529606614285348">在新的無痕式視窗中開啟網頁 (Ctrl + Shift + N 鍵)</translation>
 <translation id="3681007416295224113">憑證資訊</translation>
-<translation id="3681421644246505351">Chrome 會根據你近期的瀏覽記錄記下感興趣的主題。</translation>
+<translation id="3681421644246505351">Chrome 會根據你近期的瀏覽記錄,記下你感興趣的主題。</translation>
 <translation id="3693327506115126094">選擇身分驗證方式</translation>
 <translation id="3701427423622901115">已確認重設。</translation>
 <translation id="3704162925118123524">您可能需要造訪目前所使用網路的登入網頁。</translation>
@@ -1210,7 +1210,7 @@
 <translation id="3987940399970879459">不到 1 MB</translation>
 <translation id="3990250421422698716">撞頁偏移</translation>
 <translation id="3992684624889376114">為何顯示此頁</translation>
-<translation id="399952081411886534">其他讓廣告更有隱私的功能</translation>
+<translation id="399952081411886534">其他有助於保障使用者隱私的廣告控管機制</translation>
 <translation id="4000598935132966791">進一步瞭解受管理瀏覽器中的網站限制</translation>
 <translation id="4006465311664329701">儲存在 Google Pay 的付款方式、優惠和地址資訊</translation>
 <translation id="4010758435855888356">要授予儲存空間存取權嗎?</translation>
@@ -1918,7 +1918,6 @@
 <translation id="5695542892312572833">要使用 Windows Hello 驗證並完成購物嗎?</translation>
 <translation id="5701381305118179107">置中</translation>
 <translation id="570530837424789914">管理...</translation>
-<translation id="5706906618852913030">要儲存到帳戶中嗎?</translation>
 <translation id="5707154300732650394">繼續瀏覽歷程</translation>
 <translation id="57094364128775171">建議高強度密碼…</translation>
 <translation id="571403275720188526">(arm64)</translation>
@@ -2572,7 +2571,7 @@
 <translation id="7365849542400970216">知道你的裝置使用狀態嗎?</translation>
 <translation id="7366117520888504990">198 x 275 公釐</translation>
 <translation id="7366362069757178916">付款處理常式</translation>
-<translation id="7367985555340314048">Chrome 會根據你最近的瀏覽記錄推測感興趣的主題,做為網站放送個人化廣告的依據</translation>
+<translation id="7367985555340314048">Chrome 會根據你最近的瀏覽記錄推測你感興趣的主題,做為網站放送個人化廣告的依據</translation>
 <translation id="7372973238305370288">搜尋結果</translation>
 <translation id="7374461526650987610">通訊協定處理常式</translation>
 <translation id="7374733840632556089">發生這個問題是因為你或其他人在裝置上安裝了具有風險的憑證。已知這個憑證是用於監控及攔截網路資訊,且不受 Chrome 信任。雖然有部分監控活動屬於正當行為 (例如學校或公司網路上的監控機制),Chrome 仍想確保你知曉此一情況,即使你無法阻止這類監控活動。任何存取網路的瀏覽器或應用程式都可能受到監控。</translation>
@@ -2786,7 +2785,7 @@
 <translation id="7791543448312431591">新增</translation>
 <translation id="7798389633136518089">由於這個政策並非透過雲端來源設定,因此遭到忽略。</translation>
 <translation id="7800304661137206267">連線採用 <ph name="CIPHER" /> 加密,並設有 <ph name="MAC" /> 訊息驗證及 <ph name="KX" /> 金鑰交換機制。</translation>
-<translation id="7800977246388195491">Chrome 會根據你近期的瀏覽記錄記下感興趣的主題。此外,你造訪的網站可以判斷你喜歡的內容。在此之後,網站就能要求取得這項資訊,據此向你放送個人化廣告。你可以選擇要根據哪些主題和網站顯示廣告。</translation>
+<translation id="7800977246388195491">Chrome 會根據你近期的瀏覽記錄,記下你感興趣的主題。此外,你造訪的網站可以判斷你喜歡的內容。在此之後,網站就能要求取得這項資訊,據此向你放送個人化廣告。你可以選擇要根據哪些主題和網站顯示廣告。</translation>
 <translation id="7802523362929240268">網站合法</translation>
 <translation id="7802989406998618639">請輸入<ph name="SIDE_OF_CARD" />的 <ph name="NUMBER_OF_DIGITS" /> 位數安全碼,讓銀行驗證你的身分</translation>
 <translation id="780301667611848630">不用了,謝謝</translation>
@@ -3094,7 +3093,7 @@
 <translation id="860043288473659153">持卡人姓名</translation>
 <translation id="8601027005147870853"><ph name="BEGIN_BOLD" />我們使用的資料:<ph name="END_BOLD" />你在這部裝置上透過 Chrome 造訪的網站活動。</translation>
 <translation id="8606726445206553943">使用您的 MIDI 裝置</translation>
-<translation id="8606988009912891950">廣告主題可協助網站向你顯示相關廣告,同時保護你的瀏覽記錄和身分。Chrome 可以根據你近期的瀏覽記錄,記下感興趣的主題。在此之後,你造訪的網站就可以要求 Chrome 提供相關主題,據此向你放送個人化廣告。</translation>
+<translation id="8606988009912891950">廣告主題可協助網站向你顯示相關廣告,同時保護你的瀏覽記錄和身分。Chrome 可以根據你近期的瀏覽記錄,記下你感興趣的主題。在此之後,你造訪的網站就可以要求 Chrome 提供相關主題,據此向你放送個人化廣告。</translation>
 <translation id="8617269623452051934">你的裝置使用狀態</translation>
 <translation id="861775596732816396">粗細:4</translation>
 <translation id="8620276786115098679">Envelope Kaku 7</translation>
diff --git a/components/strings/components_strings_zu.xtb b/components/strings/components_strings_zu.xtb
index 4f52740..8bdf2e5 100644
--- a/components/strings/components_strings_zu.xtb
+++ b/components/strings/components_strings_zu.xtb
@@ -1916,7 +1916,6 @@
 <translation id="5695542892312572833">Usebenzisa i-Windows Hello ukuze uqinisekise futhi uqede ukuthenga kwakho?</translation>
 <translation id="5701381305118179107">Maphakathi</translation>
 <translation id="570530837424789914">Phatha...</translation>
-<translation id="5706906618852913030">Londoloza ku-akhawunti?</translation>
 <translation id="5707154300732650394">Qhubeka nohambo lwakho</translation>
 <translation id="57094364128775171">Iphakamisa iphasiwedi eqinile…</translation>
 <translation id="571403275720188526">(arm64)</translation>
diff --git a/components/variations/active_field_trials.cc b/components/variations/active_field_trials.cc
index f4c612b9e..b7ec746 100644
--- a/components/variations/active_field_trials.cc
+++ b/components/variations/active_field_trials.cc
@@ -9,7 +9,7 @@
 #include <vector>
 
 #include "base/containers/contains.h"
-#include "base/lazy_instance.h"
+#include "base/no_destructor.h"
 #include "base/ranges/algorithm.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
@@ -22,7 +22,10 @@
 
 namespace {
 
-base::LazyInstance<std::string>::Leaky g_seed_version;
+std::string& GetSeedVersionInternal() {
+  static base::NoDestructor<std::string> seed_version;
+  return *seed_version;
+}
 
 void AppendActiveGroupIdsAsStrings(
     const std::vector<ActiveGroupId> name_group_ids,
@@ -55,23 +58,22 @@
   }
 }
 
-void GetFieldTrialActiveGroupIds(base::StringPiece suffix,
-                                 std::vector<ActiveGroupId>* name_group_ids) {
+void GetFieldTrialActiveGroupIds(
+    base::StringPiece suffix,
+    const base::FieldTrial::ActiveGroups& active_groups,
+    std::vector<ActiveGroupId>* name_group_ids) {
   DCHECK(name_group_ids->empty());
-  // A note on thread safety: Since GetActiveFieldTrialGroups() is thread
-  // safe, and we operate on a separate list of that data, this function is
-  // technically thread safe as well, with respect to the FieldTrialList data.
-  base::FieldTrial::ActiveGroups active_groups;
-  base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
   GetFieldTrialActiveGroupIdsForActiveGroups(suffix, active_groups,
                                              name_group_ids);
 }
 
-void GetFieldTrialActiveGroupIdsAsStrings(base::StringPiece suffix,
-                                          std::vector<std::string>* output) {
+void GetFieldTrialActiveGroupIdsAsStrings(
+    base::StringPiece suffix,
+    const base::FieldTrial::ActiveGroups& active_groups,
+    std::vector<std::string>* output) {
   DCHECK(output->empty());
   std::vector<ActiveGroupId> name_group_ids;
-  GetFieldTrialActiveGroupIds(suffix, &name_group_ids);
+  GetFieldTrialActiveGroupIds(suffix, active_groups, &name_group_ids);
   AppendActiveGroupIdsAsStrings(name_group_ids, output);
 }
 
@@ -103,11 +105,11 @@
 }
 
 void SetSeedVersion(const std::string& seed_version) {
-  g_seed_version.Get() = seed_version;
+  GetSeedVersionInternal() = seed_version;
 }
 
 const std::string& GetSeedVersion() {
-  return g_seed_version.Get();
+  return GetSeedVersionInternal();
 }
 
 namespace testing {
diff --git a/components/variations/active_field_trials.h b/components/variations/active_field_trials.h
index 008bd44a..8af8790 100644
--- a/components/variations/active_field_trials.h
+++ b/components/variations/active_field_trials.h
@@ -49,23 +49,33 @@
     std::vector<ActiveGroupId>* name_group_ids);
 
 // Fills the supplied vector |name_group_ids| (which must be empty when called)
-// with unique ActiveGroupIds for each Field Trial that has a chosen group.
-// Field Trials for which a group has not been chosen yet are NOT returned in
-// this list. Field trial names are suffixed with |suffix| before hashing is
-// executed.
+// with unique ActiveGroupIds for the provided |active_groups|.
+// Field trial names are suffixed with |suffix| before hashing is executed.
+//
+// TODO(b/274900786): split this into two methods - a default one excluding low
+// anonymity trials, which does require |active_groups| to be supplied, and one
+// which takes |active_groups|.
 COMPONENT_EXPORT(VARIATIONS)
-void GetFieldTrialActiveGroupIds(base::StringPiece suffix,
-                                 std::vector<ActiveGroupId>* name_group_ids);
+void GetFieldTrialActiveGroupIds(
+    base::StringPiece suffix,
+    const base::FieldTrial::ActiveGroups& active_groups,
+    std::vector<ActiveGroupId>* name_group_ids);
 
 // Fills the supplied vector |output| (which must be empty when called) with
-// unique string representations of ActiveGroupIds for each Field Trial that
-// has a chosen group. The strings are formatted as "<TrialName>-<GroupName>",
-// with the names as hex strings. Field Trials for which a group has not been
-// chosen yet are NOT returned in this list. Field trial names are suffixed with
-// |suffix| before hashing is executed.
+// unique string representations of ActiveGroupIds for for the provided
+// |active_groups|.
+// The strings are formatted as "<TrialName>-<GroupName>", with the names as hex
+// strings. Field trial names are suffixed with |suffix| before hashing is
+// executed.
+//
+// TODO(b/274900786): split this into two methods - a default one excluding low
+// anonymity trials, which does require |active_groups| to be supplied, and one
+// which takes |active_groups|.
 COMPONENT_EXPORT(VARIATIONS)
-void GetFieldTrialActiveGroupIdsAsStrings(base::StringPiece suffix,
-                                          std::vector<std::string>* output);
+void GetFieldTrialActiveGroupIdsAsStrings(
+    base::StringPiece suffix,
+    const base::FieldTrial::ActiveGroups& active_groups,
+    std::vector<std::string>* output);
 
 // TODO(rkaplow): Support suffixing for synthetic trials.
 // Fills the supplied vector |output| (which must be empty when called) with
diff --git a/components/variations/child_process_field_trial_syncer.cc b/components/variations/child_process_field_trial_syncer.cc
index 9ceaa85d..b7305da 100644
--- a/components/variations/child_process_field_trial_syncer.cc
+++ b/components/variations/child_process_field_trial_syncer.cc
@@ -11,6 +11,7 @@
 #include "base/base_switches.h"
 #include "base/command_line.h"
 #include "base/containers/contains.h"
+#include "base/metrics/field_trial_list_including_low_anonymity.h"
 #include "components/variations/variations_crash_keys.h"
 #include "third_party/abseil-cpp/absl/base/attributes.h"
 
@@ -52,7 +53,12 @@
   variations::InitCrashKeys();
 
   // Listen for field trial activations to report them to the browser.
-  base::FieldTrialList::AddObserver(this);
+  // All trials (including low anonymity ones) are required so that the browser
+  // and child processes have a consistent view.
+  //
+  // See also TODO(crbug.com/1431156) at
+  // |FieldTrialSynchronizer::FieldTrialSynchronizer()|.
+  base::FieldTrialListIncludingLowAnonymity::AddObserver(this);
 
   // Some field trials may have been activated before this point. Notify the
   // browser of these activations now. To detect these, take the set difference
@@ -66,7 +72,8 @@
   }
 
   base::FieldTrial::ActiveGroups current_active_trials;
-  base::FieldTrialList::GetActiveFieldTrialGroups(&current_active_trials);
+  base::FieldTrialListIncludingLowAnonymity::GetActiveFieldTrialGroups(
+      &current_active_trials);
   for (const auto& trial : current_active_trials) {
     if (!base::Contains(initially_active_trials_set, trial.trial_name))
       activated_callback_.Run(trial.trial_name);
diff --git a/components/variations/variations_crash_keys.cc b/components/variations/variations_crash_keys.cc
index 1b6dbdd..df5cbb5 100644
--- a/components/variations/variations_crash_keys.cc
+++ b/components/variations/variations_crash_keys.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "base/debug/leak_annotations.h"
+#include "base/metrics/field_trial_list_including_low_anonymity.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/sequence_checker.h"
 #include "base/strings/string_number_conversions.h"
@@ -56,6 +57,8 @@
   return base::StringPrintf("%x-%x,", active_group.name, active_group.group);
 }
 
+}  // namespace
+
 class VariationsCrashKeys final : public base::FieldTrialList::Observer {
  public:
   VariationsCrashKeys();
@@ -114,7 +117,8 @@
 
 VariationsCrashKeys::VariationsCrashKeys() {
   base::FieldTrial::ActiveGroups active_groups;
-  base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  base::FieldTrialListIncludingLowAnonymity::GetActiveFieldTrialGroups(
+      &active_groups);
   for (const auto& entry : active_groups) {
     AppendFieldTrial(entry.trial_name, entry.group_name);
   }
@@ -126,11 +130,11 @@
   UpdateCrashKeys();
 
   ui_thread_task_runner_ = base::SequencedTaskRunner::GetCurrentDefault();
-  base::FieldTrialList::AddObserver(this);
+  base::FieldTrialListIncludingLowAnonymity::AddObserver(this);
 }
 
 VariationsCrashKeys::~VariationsCrashKeys() {
-  base::FieldTrialList::RemoveObserver(this);
+  base::FieldTrialListIncludingLowAnonymity::RemoveObserver(this);
   g_num_variations_crash_key.Clear();
   g_variations_crash_key.Clear();
 }
@@ -224,8 +228,6 @@
 // there's no benefit in cleaning it up at exit.
 VariationsCrashKeys* g_variations_crash_keys = nullptr;
 
-}  // namespace
-
 const char kNumExperimentsKey[] = "num-experiments";
 const char kExperimentListKey[] = "variations";
 
diff --git a/components/variations/variations_ids_provider.cc b/components/variations/variations_ids_provider.cc
index 58c22c06..bb07c5ede 100644
--- a/components/variations/variations_ids_provider.cc
+++ b/components/variations/variations_ids_provider.cc
@@ -324,6 +324,11 @@
   DCHECK(success);
 
   base::FieldTrial::ActiveGroups initial_groups;
+  // These field trial group IDs may be sent to Google servers for web-visible
+  // studies.
+  // Low anonymity trials cannot be web-visible (enforced server-side), but as
+  // an additional safeguard we do not include them in the list of field trials
+  // we fetch here.
   base::FieldTrialList::GetActiveFieldTrialGroups(&initial_groups);
 
   for (const auto& entry : initial_groups) {
diff --git a/components/variations/variations_seed_processor.cc b/components/variations/variations_seed_processor.cc
index ac30d7ab..e915ec59 100644
--- a/components/variations/variations_seed_processor.cc
+++ b/components/variations/variations_seed_processor.cc
@@ -216,6 +216,12 @@
   return false;
 }
 
+bool StudyIsLowAnonymity(const Study& study) {
+  // Studies which are set based on Google group membership are potentially low
+  // anonymity (as the groups could in theory have a small number of members).
+  return study.filter().google_group_size() > 0;
+}
+
 // Creates a placeholder trial that indicates the feature conflict.
 //
 // This forcibly associates |trial_name| with the |kFeatureConflictGroupName|
@@ -225,9 +231,10 @@
 // Trials may be associated with this group due to toggling flags in
 // chrome://flags that are associated with the trial's features, or if there
 // are different trials associated with the same feature.
-void CreateTrialWithFeatureConflictGroup(const std::string& trial_name) {
+void CreateTrialWithFeatureConflictGroup(const Study& study) {
   base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
-      trial_name, internal::kFeatureConflictGroupName);
+      study.name(), internal::kFeatureConflictGroupName,
+      StudyIsLowAnonymity(study));
   DCHECK(trial);
   // Activate immediately to make the conflict obvious in metrics logs.
   trial->Activate();
@@ -301,13 +308,13 @@
       const auto& features = experiment.feature_association();
       for (const std::string& feature_name : features.enable_feature()) {
         if (feature_list->HasAssociatedFieldTrialByFeatureName(feature_name)) {
-          CreateTrialWithFeatureConflictGroup(study.name());
+          CreateTrialWithFeatureConflictGroup(study);
           return;
         }
       }
       for (const std::string& feature_name : features.disable_feature()) {
         if (feature_list->HasAssociatedFieldTrialByFeatureName(feature_name)) {
-          CreateTrialWithFeatureConflictGroup(study.name());
+          CreateTrialWithFeatureConflictGroup(study);
           return;
         }
       }
@@ -320,7 +327,7 @@
   for (const auto& experiment : study.experiment()) {
     if (ShouldForceExperiment(experiment, *command_line, *feature_list)) {
       base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
-          study.name(), experiment.name());
+          study.name(), experiment.name(), StudyIsLowAnonymity(study));
       // If |trial| is null, then there might already be a trial forced to a
       // different group (e.g. via --force-fieldtrials). Break out of the loop,
       // but don't return, so that variation ids and params for the selected
@@ -354,7 +361,7 @@
       base::FieldTrialList::FactoryGetFieldTrial(
           study.name(), processed_study.total_probability(),
           processed_study.GetDefaultExperimentName(), entropy_provider,
-          study.randomization_seed()));
+          study.randomization_seed(), StudyIsLowAnonymity(study)));
 
   bool has_overrides = false;
   bool enables_or_disables_features = false;
diff --git a/components/variations/variations_seed_processor_unittest.cc b/components/variations/variations_seed_processor_unittest.cc
index 870fe9a2..9fb60c9 100644
--- a/components/variations/variations_seed_processor_unittest.cc
+++ b/components/variations/variations_seed_processor_unittest.cc
@@ -18,10 +18,12 @@
 #include "base/format_macros.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
+#include "base/metrics/field_trial_list_including_low_anonymity.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/mock_entropy_provider.h"
 #include "base/test/scoped_feature_list.h"
@@ -96,6 +98,34 @@
   return trial ? trial->group_name() : "";
 }
 
+// Create a filterable state for use in these tests.
+// This differs from |CreateDummyClientFilterableState()| by setting membership
+// of a specific google group (which some tests rely on).
+uint64_t kExampleGoogleGroup = 123456;
+std::unique_ptr<ClientFilterableState> CreateTestClientFilterableState() {
+  auto client_state = std::make_unique<ClientFilterableState>(
+      base::BindOnce([] { return false; }), base::BindOnce([] {
+        return base::flat_set<uint64_t>({kExampleGoogleGroup});
+      }));
+  client_state->locale = "en-CA";
+  client_state->reference_date = base::Time::Now();
+  client_state->version = base::Version("20.0.0.0");
+  client_state->channel = Study::STABLE;
+  client_state->form_factor = Study::PHONE;
+  return client_state;
+}
+
+// Add a filter to |study| that filters on a Google group which matches the
+// client filterable state.
+void AddGoogleGroupFilter(Study& study) {
+  Study::Filter* filter = study.mutable_filter();
+  filter->add_google_group(kExampleGoogleGroup);
+  // Also add a platform filter that matches both the environments we're
+  // testing in the typed tests.
+  filter->add_platform(Study::PLATFORM_ANDROID);
+  filter->add_platform(Study::PLATFORM_ANDROID_WEBVIEW);
+}
+
 class TestOverrideStringCallback {
  public:
   typedef std::map<uint32_t, std::u16string> OverrideMap;
@@ -137,7 +167,7 @@
       const VariationsSeed& seed,
       base::FeatureList* feature_list,
       const VariationsSeedProcessor::UIStringOverrideCallback& callback) {
-    auto client_state = CreateDummyClientFilterableState();
+    auto client_state = CreateTestClientFilterableState();
     client_state->platform = Study::PLATFORM_ANDROID;
 
     MockEntropyProviders entropy_providers({
@@ -161,7 +191,7 @@
       const VariationsSeed& seed,
       base::FeatureList* feature_list,
       const VariationsSeedProcessor::UIStringOverrideCallback& callback) {
-    auto client_state = CreateDummyClientFilterableState();
+    auto client_state = CreateTestClientFilterableState();
     client_state->platform = Study::PLATFORM_ANDROID_WEBVIEW;
 
     MockEntropyProviders entropy_providers({
@@ -205,6 +235,19 @@
   TestOverrideStringCallback override_callback_;
 };
 
+// This is exposed on the test class rather than called directly from tests
+// because |FieldTrialListIncludingLowAnonymity| needs to friend the call site
+// but |FRIEND_TEST| / |FRIEND_TEST_ALL_PREFIXES| doesn't work with
+// |TYPED_TEST|.
+class VariationsSeedProcessorTestLowAnonymityHelper {
+ public:
+  static void GetActiveFieldTrialGroups(
+      base::FieldTrial::ActiveGroups* active_groups) {
+    base::FieldTrialListIncludingLowAnonymity::GetActiveFieldTrialGroups(
+        active_groups);
+  }
+};
+
 using EnvironmentTypes =
     ::testing::Types<ChromeEnvironment, WebViewEnvironment>;
 TYPED_TEST_SUITE(VariationsSeedProcessorTest, EnvironmentTypes);
@@ -291,6 +334,29 @@
             base::FieldTrialList::FindFullName(kFlagStudyName));
 }
 
+// Test that the group for kForcingFlag1 is forced.
+TYPED_TEST(VariationsSeedProcessorTest, ForceGroupWithFlag1_LowAnonymity) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag1);
+
+  VariationsSeed seed;
+  Study* study = CreateStudyWithFlagGroups(100, 0, 0, &seed);
+  AddGoogleGroupFilter(*study);
+  this->CreateTrialsFromSeed(seed);
+  EXPECT_EQ(kFlagGroup1Name,
+            base::FieldTrialList::FindFullName(kFlagStudyName));
+
+  // This study should be marked as low anonymity, and therefore only returned
+  // by |FieldTrialListIncludingLowAnonymity|.
+  base::FieldTrial::ActiveGroups active_groups;
+  base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_EQ(active_groups.size(), 0u);
+
+  base::FieldTrial::ActiveGroups active_groups_including_low_anonymity;
+  VariationsSeedProcessorTestLowAnonymityHelper::GetActiveFieldTrialGroups(
+      &active_groups_including_low_anonymity);
+  EXPECT_EQ(active_groups_including_low_anonymity.size(), 1u);
+}
+
 // Test that the group for kForcingFlag2 is forced.
 TYPED_TEST(VariationsSeedProcessorTest, ForceGroupWithFlag2) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag2);
@@ -1425,6 +1491,7 @@
   server_side_study->set_default_experiment_name("A");
   server_side_study->set_activation_type(
       Study_ActivationType_ACTIVATE_ON_STARTUP);
+  AddGoogleGroupFilter(*server_side_study);
   Study::Experiment* experiment2 =
       AddExperiment("A", /*probability=*/1, server_side_study);
   experiment2->mutable_feature_association()->add_enable_feature(kFeature.name);
@@ -1443,6 +1510,18 @@
   ASSERT_TRUE(base::FieldTrialList::IsTrialActive(server_side_study->name()));
   EXPECT_EQ(base::FieldTrialList::Find(server_side_study->name())->group_name(),
             internal::kFeatureConflictGroupName);
+
+  // Only one of the studies is returned by the default field trial list (as
+  // the second is low-anonymity).
+  base::FieldTrial::ActiveGroups active_groups;
+  base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_EQ(active_groups.size(), 1u);
+
+  // Both studies are returned by in the full list including low anonymity.
+  base::FieldTrial::ActiveGroups active_groups_including_low_anonymity;
+  VariationsSeedProcessorTestLowAnonymityHelper::GetActiveFieldTrialGroups(
+      &active_groups_including_low_anonymity);
+  EXPECT_EQ(active_groups_including_low_anonymity.size(), 2u);
 }
 
 TYPED_TEST(VariationsSeedProcessorTest,
@@ -1466,6 +1545,7 @@
   server_side_study->set_default_experiment_name("A");
   server_side_study->set_activation_type(
       Study_ActivationType_ACTIVATE_ON_STARTUP);
+  AddGoogleGroupFilter(*server_side_study);
   Study::Experiment* experiment2 =
       AddExperiment("A", /*probability=*/1, server_side_study);
   experiment2->mutable_feature_association()->add_disable_feature(
@@ -1485,6 +1565,18 @@
   ASSERT_TRUE(base::FieldTrialList::IsTrialActive(server_side_study->name()));
   EXPECT_EQ(base::FieldTrialList::Find(server_side_study->name())->group_name(),
             internal::kFeatureConflictGroupName);
+
+  // Only one of the studies is returned by the default field trial list (as
+  // the second is low-anonymity).
+  base::FieldTrial::ActiveGroups active_groups;
+  base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_EQ(active_groups.size(), 1u);
+
+  // Both studies are returned by in the full list including low anonymity.
+  base::FieldTrial::ActiveGroups active_groups_including_low_anonymity;
+  VariationsSeedProcessorTestLowAnonymityHelper::GetActiveFieldTrialGroups(
+      &active_groups_including_low_anonymity);
+  EXPECT_EQ(active_groups_including_low_anonymity.size(), 2u);
 }
 
 TYPED_TEST(VariationsSeedProcessorTest, OutOfBoundsLayer) {
@@ -1518,4 +1610,62 @@
                                       1);
 }
 
+TYPED_TEST(VariationsSeedProcessorTest,
+           StudyWithGoogleGroupFilterIsLowAnonymity) {
+  VariationsSeed seed;
+  Study* study = seed.add_study();
+  study->set_name("A");
+  study->set_default_experiment_name("Default");
+  study->set_activation_type(Study::ACTIVATE_ON_STARTUP);
+  AddExperiment("AA", 100, study);
+  AddExperiment("Default", 0, study);
+  AddGoogleGroupFilter(*study);
+
+  this->CreateTrialsFromSeed(seed);
+
+  // This study should be marked as low anonymity, and therefore only returned
+  // by |FieldTrialListIncludingLowAnonymity|.
+  base::FieldTrial::ActiveGroups active_groups;
+  base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_EQ(active_groups.size(), 0u);
+
+  base::FieldTrial::ActiveGroups active_groups_including_low_anonymity;
+  VariationsSeedProcessorTestLowAnonymityHelper::GetActiveFieldTrialGroups(
+      &active_groups_including_low_anonymity);
+  EXPECT_EQ(active_groups_including_low_anonymity.size(), 1u);
+}
+
+TYPED_TEST(VariationsSeedProcessorTest,
+           StudyWithExcludeGoogleGroupFilterIsNotLowAnonymity) {
+  VariationsSeed seed;
+  Study* study = seed.add_study();
+  study->set_name("A");
+  study->set_default_experiment_name("Default");
+  study->set_activation_type(Study::ACTIVATE_ON_STARTUP);
+  AddExperiment("AA", 100, study);
+  AddExperiment("Default", 0, study);
+
+  // Add a study filter that excludes a Google group, which this client is not
+  // a member of (i.e. the client does select this study).
+  Study::Filter* filter = study->mutable_filter();
+  filter->add_exclude_google_group(987654);
+  // Also add a platform filter that matches both the environments we're
+  // testing in the typed tests.
+  filter->add_platform(Study::PLATFORM_ANDROID);
+  filter->add_platform(Study::PLATFORM_ANDROID_WEBVIEW);
+
+  this->CreateTrialsFromSeed(seed);
+
+  // This study should not be marked as low anonymity, and therefore is returned
+  // by both APIs.
+  base::FieldTrial::ActiveGroups active_groups;
+  base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_EQ(active_groups.size(), 1u);
+
+  base::FieldTrial::ActiveGroups active_groups_including_low_anonymity;
+  VariationsSeedProcessorTestLowAnonymityHelper::GetActiveFieldTrialGroups(
+      &active_groups_including_low_anonymity);
+  EXPECT_EQ(active_groups_including_low_anonymity.size(), 1u);
+}
+
 }  // namespace variations
diff --git a/components/variations/variations_seed_simulator.cc b/components/variations/variations_seed_simulator.cc
index d318a5f..12d9fbe 100644
--- a/components/variations/variations_seed_simulator.cc
+++ b/components/variations/variations_seed_simulator.cc
@@ -9,6 +9,7 @@
 #include <map>
 
 #include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_list_including_low_anonymity.h"
 #include "base/metrics/field_trial_params.h"
 #include "components/variations/client_filterable_state.h"
 #include "components/variations/processed_study.h"
@@ -28,15 +29,6 @@
   CHANGED_KILL_CRITICAL,
 };
 
-// Fills in |current_state| with the current process' active field trials, as a
-// map of trial names to group names.
-void GetCurrentTrialState(std::map<std::string, std::string>* current_state) {
-  base::FieldTrial::ActiveGroups trial_groups;
-  base::FieldTrialList::GetActiveFieldTrialGroups(&trial_groups);
-  for (auto& group : trial_groups)
-    (*current_state)[group.trial_name] = group.group_name;
-}
-
 // Simulate group assignment for the specified study with PERMANENT consistency.
 // Returns the experiment group that will be selected. Mirrors logic in
 // VariationsSeedProcessor::CreateTrialFromStudy().
@@ -163,12 +155,21 @@
   return NO_CHANGE;
 }
 
+}  // namespace
+
 SeedSimulationResult ComputeDifferences(
     const std::vector<ProcessedStudy>& processed_studies,
     const VariationsLayers& layers,
     const EntropyProviders& entropy_providers) {
+  // Fill in |current_state| with the current process' active field trials, as a
+  // map of trial names to group names.
   std::map<std::string, std::string> current_state;
-  GetCurrentTrialState(&current_state);
+  base::FieldTrial::ActiveGroups trial_groups;
+  base::FieldTrialListIncludingLowAnonymity::GetActiveFieldTrialGroups(
+      &trial_groups);
+  for (auto& group : trial_groups) {
+    current_state[group.trial_name] = group.group_name;
+  }
 
   SeedSimulationResult result;
   for (const auto& processed_study : processed_studies) {
@@ -219,8 +220,6 @@
   return result;
 }
 
-}  // namespace
-
 SeedSimulationResult SimulateSeedStudies(
     const VariationsSeed& seed,
     const ClientFilterableState& client_state,
diff --git a/components/version_ui/version_handler_helper.cc b/components/version_ui/version_handler_helper.cc
index 98c1607..7ca35f1 100644
--- a/components/version_ui/version_handler_helper.cc
+++ b/components/version_ui/version_handler_helper.cc
@@ -9,6 +9,7 @@
 
 #include "base/base_switches.h"
 #include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_list_including_low_anonymity.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "components/variations/active_field_trials.h"
@@ -31,10 +32,12 @@
 
 base::Value::List GetVariationsList() {
   std::vector<std::string> variations;
-#if !defined(NDEBUG)
   base::FieldTrial::ActiveGroups active_groups;
-  base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
-
+  // Include low anonymity trial groups in the version string, as it is only
+  // displayed locally (and is useful for diagnostics purposes).
+  base::FieldTrialListIncludingLowAnonymity::GetActiveFieldTrialGroups(
+      &active_groups);
+#if !defined(NDEBUG)
   const unsigned char kNonBreakingHyphenUTF8[] = {0xE2, 0x80, 0x91, '\0'};
   const std::string kNonBreakingHyphenUTF8String(
       reinterpret_cast<const char*>(kNonBreakingHyphenUTF8));
@@ -46,7 +49,7 @@
 #else
   // In release mode, display the hashes only.
   variations::GetFieldTrialActiveGroupIdsAsStrings(base::StringPiece(),
-                                                   &variations);
+                                                   active_groups, &variations);
 #endif
 
   base::Value::List variations_list;
diff --git a/content/browser/download/download_manager_impl_unittest.cc b/content/browser/download/download_manager_impl_unittest.cc
index c939893..5caec3c 100644
--- a/content/browser/download/download_manager_impl_unittest.cc
+++ b/content/browser/download/download_manager_impl_unittest.cc
@@ -17,13 +17,13 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
-#include "base/guid.h"
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/gmock_callback_support.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/uuid.h"
 #include "build/build_config.h"
 #include "components/download/public/common/download_create_info.h"
 #include "components/download/public/common/download_features.h"
@@ -262,7 +262,8 @@
   EXPECT_CALL(*result, GetId())
       .WillRepeatedly(Return(download_id));
   EXPECT_CALL(*result, GetGuid())
-      .WillRepeatedly(ReturnRefOfCopy(base::GenerateGUID()));
+      .WillRepeatedly(
+          ReturnRefOfCopy(base::Uuid::GenerateRandomV4().AsLowercaseString()));
   EXPECT_CALL(*result, GetUrlChain())
       .WillRepeatedly(ReturnRefOfCopy(std::vector<GURL>()));
   EXPECT_CALL(*result, GetReferrerUrl())
diff --git a/content/browser/download/mhtml_generation_manager.cc b/content/browser/download/mhtml_generation_manager.cc
index e9f52ae..dfc3c87f 100644
--- a/content/browser/download/mhtml_generation_manager.cc
+++ b/content/browser/download/mhtml_generation_manager.cc
@@ -10,7 +10,6 @@
 #include "base/containers/queue.h"
 #include "base/files/file.h"
 #include "base/functional/bind.h"
-#include "base/guid.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
@@ -19,6 +18,7 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "base/types/optional_util.h"
+#include "base/uuid.h"
 #include "components/download/public/common/download_task_runner.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/download/mhtml_extra_parts_impl.h"
@@ -356,7 +356,7 @@
       params_(params),
       frame_tree_node_id_of_busy_frame_(FrameTreeNode::kFrameTreeNodeInvalidId),
       mhtml_boundary_marker_(net::GenerateMimeMultipartBoundary()),
-      salt_(base::GenerateGUID()),
+      salt_(base::Uuid::GenerateRandomV4().AsLowercaseString()),
       callback_(std::move(callback)),
       is_finished_(false),
       waiting_on_data_streaming_(false) {
diff --git a/content/browser/fenced_frame/fenced_frame_config.cc b/content/browser/fenced_frame/fenced_frame_config.cc
index 9b887b58..7e516a9 100644
--- a/content/browser/fenced_frame/fenced_frame_config.cc
+++ b/content/browser/fenced_frame/fenced_frame_config.cc
@@ -4,10 +4,10 @@
 
 #include "content/browser/fenced_frame/fenced_frame_config.h"
 #include "base/functional/callback.h"
-#include "base/guid.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
+#include "base/uuid.h"
 #include "content/browser/fenced_frame/fenced_frame_reporter.h"
 #include "third_party/blink/public/common/interest_group/ad_auction_constants.h"
 
@@ -17,7 +17,7 @@
 
 GURL GenerateUrnUuid() {
   return GURL(kUrnUuidPrefix +
-              base::GUID::GenerateRandomV4().AsLowercaseString());
+              base::Uuid::GenerateRandomV4().AsLowercaseString());
 }
 
 namespace {
diff --git a/content/browser/field_trial_synchronizer.cc b/content/browser/field_trial_synchronizer.cc
index 5b14e3f..cc8f7a2 100644
--- a/content/browser/field_trial_synchronizer.cc
+++ b/content/browser/field_trial_synchronizer.cc
@@ -6,6 +6,8 @@
 
 #include "base/check_op.h"
 #include "base/functional/bind.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_list_including_low_anonymity.h"
 #include "base/threading/thread.h"
 #include "components/metrics/persistent_system_profile.h"
 #include "components/variations/variations_client.h"
@@ -31,10 +33,19 @@
   // need to be on the UI thread.
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  // Note this in the persistent profile as it will take a while for a new
-  // "complete" profile to be generated.
-  metrics::GlobalPersistentSystemProfile::GetInstance()->AddFieldTrial(
-      field_trial_name, group_name);
+  // Low anonymity field trials must not be written to persistent data,
+  // otherwise they might end up being logged in metrics.
+  //
+  // TODO(crbug.com/1431156): split this out into a separate class that
+  // registers using |FieldTrialList::AddObserver()| (and so doesn't get told
+  // about low anonymity trials at all).
+  base::FieldTrial* trial = base::FieldTrialList::Find(field_trial_name);
+  if (trial && !trial->is_low_anonymity()) {
+    // Note this in the persistent profile as it will take a while for a new
+    // "complete" profile to be generated.
+    metrics::GlobalPersistentSystemProfile::GetInstance()->AddFieldTrial(
+        field_trial_name, group_name);
+  }
 
   for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
        !it.IsAtEnd(); it.Advance()) {
@@ -61,7 +72,10 @@
 }
 
 FieldTrialSynchronizer::FieldTrialSynchronizer() {
-  bool success = base::FieldTrialList::AddObserver(this);
+  // TODO(crbug.com/1431156): consider whether there is a need to exclude low
+  // anonymity field trials from non-browser processes (or to plumb through the
+  // anonymity property for more fine-grained access).
+  bool success = base::FieldTrialListIncludingLowAnonymity::AddObserver(this);
   // Ensure the observer was actually registered.
   DCHECK(success);
 
diff --git a/content/ppapi_plugin/ppapi_blink_platform_impl.cc b/content/ppapi_plugin/ppapi_blink_platform_impl.cc
index e82eb15b..615e5b0 100644
--- a/content/ppapi_plugin/ppapi_blink_platform_impl.cc
+++ b/content/ppapi_plugin/ppapi_blink_platform_impl.cc
@@ -39,9 +39,10 @@
   mojo::PendingRemote<font_service::mojom::FontService> font_service;
   ChildThread::Get()->BindHostReceiver(
       font_service.InitWithNewPipeAndPassReceiver());
-  font_loader_ = sk_make_sp<font_service::FontLoader>(std::move(font_service));
-  SkFontConfigInterface::SetGlobal(font_loader_);
-  sandbox_support_ = std::make_unique<WebSandboxSupportLinux>(font_loader_);
+  sk_sp<font_service::FontLoader> font_loader =
+      sk_make_sp<font_service::FontLoader>(std::move(font_service));
+  SkFontConfigInterface::SetGlobal(font_loader);
+  sandbox_support_ = std::make_unique<WebSandboxSupportLinux>(font_loader);
 #elif BUILDFLAG(IS_MAC)
   sandbox_support_ = std::make_unique<WebSandboxSupportMac>();
 #endif
diff --git a/content/ppapi_plugin/ppapi_blink_platform_impl.h b/content/ppapi_plugin/ppapi_blink_platform_impl.h
index 465d153..c1edbed 100644
--- a/content/ppapi_plugin/ppapi_blink_platform_impl.h
+++ b/content/ppapi_plugin/ppapi_blink_platform_impl.h
@@ -12,11 +12,6 @@
 #include "build/build_config.h"
 #include "content/child/blink_platform_impl.h"
 
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-#include "components/services/font/public/cpp/font_loader.h"
-#include "third_party/skia/include/core/SkRefCnt.h"
-#endif
-
 namespace content {
 
 class PpapiBlinkPlatformImpl : public BlinkPlatformImpl {
@@ -41,10 +36,6 @@
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
   std::unique_ptr<blink::WebSandboxSupport> sandbox_support_;
 #endif
-
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-  sk_sp<font_service::FontLoader> font_loader_;
-#endif
 };
 
 }  // namespace content
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/MessagePayload.java b/content/public/android/java/src/org/chromium/content_public/browser/MessagePayload.java
index 4167521c..a427b9b 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/MessagePayload.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/MessagePayload.java
@@ -11,7 +11,7 @@
 
 /**
  * Represents a JavaScript message payload.
- * Currently only STRING is supported.
+ * Currently only String and ArrayBuffer is supported.
  */
 public final class MessagePayload {
     @MessagePayloadType
@@ -32,6 +32,9 @@
         mArrayBuffer = null;
     }
 
+    /**
+     * Create a MessagePayload ArrayBuffer type.
+     */
     public MessagePayload(@NonNull byte[] arrayBuffer) {
         Objects.requireNonNull(arrayBuffer, "arrayBuffer cannot be null.");
         mType = MessagePayloadType.ARRAY_BUFFER;
@@ -65,7 +68,7 @@
     }
 
     @NonNull
-    private static String typeToString(@MessagePayloadType int type) {
+    public static String typeToString(@MessagePayloadType int type) {
         switch (type) {
             case MessagePayloadType.STRING:
                 return "String";
@@ -74,6 +77,6 @@
             case MessagePayloadType.INVALID:
                 return "Invalid";
         }
-        throw new RuntimeException("Unknown type: " + type);
+        throw new IllegalArgumentException("Unknown type: " + type);
     }
 }
diff --git a/content/renderer/render_process_impl.cc b/content/renderer/render_process_impl.cc
index 94016c74..1592898 100644
--- a/content/renderer/render_process_impl.cc
+++ b/content/renderer/render_process_impl.cc
@@ -193,9 +193,6 @@
   v8::V8::SetFlagsFromString(kImportAssertionsFlag,
                              sizeof(kImportAssertionsFlag));
 
-  constexpr char kAtomicsFlag[] = "--harmony-atomics";
-  v8::V8::SetFlagsFromString(kAtomicsFlag, sizeof(kAtomicsFlag));
-
   bool enable_shared_array_buffer_unconditionally =
       base::FeatureList::IsEnabled(features::kSharedArrayBuffer);
 
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index decef7b..bc927b23 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -178,15 +178,18 @@
       sudden_termination_disables_(0),
       is_locked_to_site_(false),
       main_thread_scheduler_(main_thread_scheduler) {
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+  sk_sp<font_service::FontLoader> font_loader;
+#endif
+
   // RenderThread may not exist in some tests.
   if (RenderThreadImpl::current()) {
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
     mojo::PendingRemote<font_service::mojom::FontService> font_service;
     RenderThreadImpl::current()->BindHostReceiver(
         font_service.InitWithNewPipeAndPassReceiver());
-    font_loader_ =
-        sk_make_sp<font_service::FontLoader>(std::move(font_service));
-    SkFontConfigInterface::SetGlobal(font_loader_);
+    font_loader = sk_make_sp<font_service::FontLoader>(std::move(font_service));
+    SkFontConfigInterface::SetGlobal(font_loader);
 #endif
   }
 
@@ -195,7 +198,7 @@
 #if BUILDFLAG(IS_MAC)
     sandbox_support_ = std::make_unique<WebSandboxSupportMac>();
 #else
-    sandbox_support_ = std::make_unique<WebSandboxSupportLinux>(font_loader_);
+    sandbox_support_ = std::make_unique<WebSandboxSupportLinux>(font_loader);
 #endif
   } else {
     DVLOG(1) << "Disabling sandbox support for testing.";
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index a15ca021..594e30a4 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -31,11 +31,6 @@
 #include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
 #include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom.h"
 
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-#include "components/services/font/public/cpp/font_loader.h"  // nogncheck
-#include "third_party/skia/include/core/SkRefCnt.h"           // nogncheck
-#endif
-
 namespace blink {
 namespace scheduler {
 class WebThreadScheduler;
@@ -262,10 +257,6 @@
   mutable base::WaitableEvent io_thread_id_ready_event_;
   base::PlatformThreadId io_thread_id_ = base::kInvalidThreadId;
 
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-  sk_sp<font_service::FontLoader> font_loader_;
-#endif
-
   // Thread to run the VideoFrameCompositor on.
   std::unique_ptr<base::Thread> video_frame_compositor_thread_;
 
diff --git a/content/shell/app/shell_main.cc b/content/shell/app/shell_main.cc
index 352dc26..55d06f7 100644
--- a/content/shell/app/shell_main.cc
+++ b/content/shell/app/shell_main.cc
@@ -15,6 +15,8 @@
 
 #if BUILDFLAG(IS_IOS)
 #include "base/at_exit.h"                                 // nogncheck
+#include "base/command_line.h"                            // nogncheck
+#include "content/public/common/content_switches.h"       // nogncheck
 #include "content/shell/app/ios/shell_application_ios.h"
 #endif
 
@@ -48,8 +50,23 @@
   // Create this here since it's needed to start the crash handler.
   base::AtExitManager at_exit;
 
-  // We will create the ContentMainRunner once the UIApplication is ready.
-  return RunShellApplication(argc, argv);
+  // Check if this is the browser process or a subprocess. Only the browser
+  // browser should run UIApplicationMain.
+  base::CommandLine::Init(argc, argv);
+  auto type = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+      switches::kProcessType);
+
+  // The browser process has no --process-type argument.
+  if (type.empty()) {
+    // We will create the ContentMainRunner once the UIApplication is ready.
+    return RunShellApplication(argc, argv);
+  } else {
+    content::ShellMainDelegate delegate;
+    content::ContentMainParams params(&delegate);
+    params.argc = argc;
+    params.argv = argv;
+    return content::ContentMain(std::move(params));
+  }
 }
 
 #else
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index 7111f523..37632ad 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -481,6 +481,7 @@
 crbug.com/772651 [ mac nvidia ] conformance/glsl/bugs/vector-scalar-arithmetic-inside-loop-complex.html [ Failure ]
 crbug.com/795052 [ mac nvidia-0xfe9 ] conformance2/uniforms/draw-with-uniform-blocks.html [ Failure ]
 crbug.com/1037650 [ mac nvidia-0xfe9 ] conformance2/textures/canvas_sub_rectangle/* [ RetryOnFailure ]
+crbug.com/1414878 [ mac nvidia-0xfe9 ] conformance2/textures/video/* [ RetryOnFailure ]
 
 crbug.com/1338004 [ mac nvidia-0xfe9 passthrough ] deqp/functional/gles3/multisample/fbo_4_samples.html [ RetryOnFailure ]
 
diff --git a/content/utility/utility_blink_platform_with_sandbox_support_impl.cc b/content/utility/utility_blink_platform_with_sandbox_support_impl.cc
index 54f66df..3f94c7b 100644
--- a/content/utility/utility_blink_platform_with_sandbox_support_impl.cc
+++ b/content/utility/utility_blink_platform_with_sandbox_support_impl.cc
@@ -21,9 +21,10 @@
   mojo::PendingRemote<font_service::mojom::FontService> font_service;
   UtilityThread::Get()->BindHostReceiver(
       font_service.InitWithNewPipeAndPassReceiver());
-  font_loader_ = sk_make_sp<font_service::FontLoader>(std::move(font_service));
-  SkFontConfigInterface::SetGlobal(font_loader_);
-  sandbox_support_ = std::make_unique<WebSandboxSupportLinux>(font_loader_);
+  sk_sp<font_service::FontLoader> font_loader =
+      sk_make_sp<font_service::FontLoader>(std::move(font_service));
+  SkFontConfigInterface::SetGlobal(font_loader);
+  sandbox_support_ = std::make_unique<WebSandboxSupportLinux>(font_loader);
 #elif BUILDFLAG(IS_MAC)
   sandbox_support_ = std::make_unique<WebSandboxSupportMac>();
 #endif
diff --git a/content/utility/utility_blink_platform_with_sandbox_support_impl.h b/content/utility/utility_blink_platform_with_sandbox_support_impl.h
index 8519b104..8eafe41 100644
--- a/content/utility/utility_blink_platform_with_sandbox_support_impl.h
+++ b/content/utility/utility_blink_platform_with_sandbox_support_impl.h
@@ -10,11 +10,6 @@
 #include "build/build_config.h"
 #include "third_party/blink/public/platform/platform.h"
 
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-#include "components/services/font/public/cpp/font_loader.h"  // nogncheck
-#include "third_party/skia/include/core/SkRefCnt.h"           // nogncheck
-#endif
-
 namespace blink {
 class WebSandboxSupport;
 }
@@ -41,9 +36,6 @@
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
   std::unique_ptr<blink::WebSandboxSupport> sandbox_support_;
 #endif
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-  sk_sp<font_service::FontLoader> font_loader_;
-#endif
 };
 
 }  // namespace content
diff --git a/device/bluetooth/floss/floss_sdp_types.cc b/device/bluetooth/floss/floss_sdp_types.cc
index 3dd2c30..abeecb9 100644
--- a/device/bluetooth/floss/floss_sdp_types.cc
+++ b/device/bluetooth/floss/floss_sdp_types.cc
@@ -51,29 +51,39 @@
 constexpr char kSdpDipRecordPropVersion[] = "version";
 constexpr char kSdpDipRecordPropPrimaryRecord[] = "primary_record";
 
-absl::optional<device::BluetoothUUID> GetUUIDFromSdpRecord(
+absl::optional<floss::BtSdpHeaderOverlay> GetHeaderOverlayFromSdpRecord(
     const floss::BtSdpRecord& record) {
   if (absl::holds_alternative<floss::BtSdpHeaderOverlay>(record)) {
-    return absl::get<floss::BtSdpHeaderOverlay>(record).uuid;
+    return absl::get<floss::BtSdpHeaderOverlay>(record);
   } else if (absl::holds_alternative<floss::BtSdpMasRecord>(record)) {
-    return absl::get<floss::BtSdpMasRecord>(record).hdr.uuid;
+    return absl::get<floss::BtSdpMasRecord>(record).hdr;
   } else if (absl::holds_alternative<floss::BtSdpMnsRecord>(record)) {
-    return absl::get<floss::BtSdpMnsRecord>(record).hdr.uuid;
+    return absl::get<floss::BtSdpMnsRecord>(record).hdr;
   } else if (absl::holds_alternative<floss::BtSdpPseRecord>(record)) {
-    return absl::get<floss::BtSdpPseRecord>(record).hdr.uuid;
+    return absl::get<floss::BtSdpPseRecord>(record).hdr;
   } else if (absl::holds_alternative<floss::BtSdpPceRecord>(record)) {
-    return absl::get<floss::BtSdpPceRecord>(record).hdr.uuid;
+    return absl::get<floss::BtSdpPceRecord>(record).hdr;
   } else if (absl::holds_alternative<floss::BtSdpOpsRecord>(record)) {
-    return absl::get<floss::BtSdpOpsRecord>(record).hdr.uuid;
+    return absl::get<floss::BtSdpOpsRecord>(record).hdr;
   } else if (absl::holds_alternative<floss::BtSdpSapRecord>(record)) {
-    return absl::get<floss::BtSdpSapRecord>(record).hdr.uuid;
+    return absl::get<floss::BtSdpSapRecord>(record).hdr;
   } else if (absl::holds_alternative<floss::BtSdpDipRecord>(record)) {
-    return absl::get<floss::BtSdpDipRecord>(record).hdr.uuid;
+    return absl::get<floss::BtSdpDipRecord>(record).hdr;
   } else {
     return absl::nullopt;
   }
 }
 
+absl::optional<device::BluetoothUUID> GetUUIDFromSdpRecord(
+    const floss::BtSdpRecord& record) {
+  absl::optional<floss::BtSdpHeaderOverlay> header =
+      GetHeaderOverlayFromSdpRecord(record);
+  if (!header.has_value()) {
+    return absl::nullopt;
+  }
+  return header->uuid;
+}
+
 template <>
 bool FlossDBusClient::ReadDBusParam(dbus::MessageReader* reader,
                                     BtSdpType* sdp_type) {
diff --git a/device/bluetooth/floss/floss_sdp_types.h b/device/bluetooth/floss/floss_sdp_types.h
index aeed541..ee38eccb 100644
--- a/device/bluetooth/floss/floss_sdp_types.h
+++ b/device/bluetooth/floss/floss_sdp_types.h
@@ -92,6 +92,8 @@
                                   BtSdpOpsRecord,
                                   BtSdpSapRecord,
                                   BtSdpDipRecord>;
+absl::optional<floss::BtSdpHeaderOverlay> DEVICE_BLUETOOTH_EXPORT
+GetHeaderOverlayFromSdpRecord(const floss::BtSdpRecord& record);
 
 absl::optional<device::BluetoothUUID> DEVICE_BLUETOOTH_EXPORT
 GetUUIDFromSdpRecord(const floss::BtSdpRecord& record);
diff --git a/device/bluetooth/floss/floss_socket_manager.cc b/device/bluetooth/floss/floss_socket_manager.cc
index d204c27..052e0fd 100644
--- a/device/bluetooth/floss/floss_socket_manager.cc
+++ b/device/bluetooth/floss/floss_socket_manager.cc
@@ -292,6 +292,21 @@
   return info;
 }
 
+int FlossSocketManager::GetRawFlossFlagsFromBluetoothFlags(bool encrypt,
+                                                           bool auth,
+                                                           bool auth_mitm,
+                                                           bool auth_16_digit,
+                                                           bool no_sdp) {
+  int flags = 0;
+  return flags |
+         (encrypt ? static_cast<int>(SocketFlags::kSocketFlagsEncrypt) : 0) |
+         (auth ? static_cast<int>(SocketFlags::kSocketFlagsAuth) : 0) |
+         (auth_mitm ? static_cast<int>(SocketFlags::kSocketFlagsAuthMitm) : 0) |
+         (auth_16_digit ? static_cast<int>(SocketFlags::kSocketFlagsAuth16Digit)
+                        : 0) |
+         (no_sdp ? static_cast<int>(SocketFlags::kSocketFlagsNoSdp) : 0);
+}
+
 FlossSocketManager::FlossListeningSocket::FlossListeningSocket() = default;
 FlossSocketManager::FlossListeningSocket::FlossListeningSocket(
     const FlossListeningSocket&) = default;
diff --git a/device/bluetooth/floss/floss_socket_manager.h b/device/bluetooth/floss/floss_socket_manager.h
index 42207e8..63baab29 100644
--- a/device/bluetooth/floss/floss_socket_manager.h
+++ b/device/bluetooth/floss/floss_socket_manager.h
@@ -57,6 +57,21 @@
     kSecure,
   };
 
+  // Flags for changing how Floss constructs a socket.
+  enum class SocketFlags : int {
+    kSocketFlagsEncrypt = 1 << 0,
+    kSocketFlagsAuth = 1 << 1,
+    kSocketFlagsNoSdp = 1 << 2,
+    kSocketFlagsAuthMitm = 1 << 3,
+    kSocketFlagsAuth16Digit = 1 << 4
+  };
+
+  static int GetRawFlossFlagsFromBluetoothFlags(bool encrypt,
+                                                bool auth,
+                                                bool auth_mitm,
+                                                bool auth_16_digit,
+                                                bool no_sdp);
+
   // Represents a listening socket.
   struct FlossListeningSocket {
     SocketId id = FlossSocketManager::kInvalidSocketId;
diff --git a/device/fido/mac/authenticator_unittest.mm b/device/fido/mac/authenticator_unittest.mm
index db8cfc5ee..b4b7e99 100644
--- a/device/fido/mac/authenticator_unittest.mm
+++ b/device/fido/mac/authenticator_unittest.mm
@@ -6,9 +6,11 @@
 
 #include "base/test/task_environment.h"
 #include "base/test/with_feature_override.h"
+#include "device/fido/authenticator_get_assertion_response.h"
 #include "device/fido/ctap_get_assertion_request.h"
 #include "device/fido/discoverable_credential_metadata.h"
 #include "device/fido/features.h"
+#include "device/fido/fido_constants.h"
 #include "device/fido/fido_request_handler_base.h"
 #include "device/fido/fido_types.h"
 #include "device/fido/mac/authenticator_config.h"
@@ -25,6 +27,9 @@
 using GetInfoCallback =
     test::TestCallbackReceiver<std::vector<DiscoverableCredentialMetadata>,
                                FidoRequestHandlerBase::RecognizedCredential>;
+using GetAssertionCallback = test::StatusAndValueCallbackReceiver<
+    CtapDeviceResponseCode,
+    std::vector<AuthenticatorGetAssertionResponse>>;
 
 constexpr char kRp1[] = "one.com";
 constexpr char kRp2[] = "two.com";
@@ -156,6 +161,15 @@
   }
 }
 
+TEST_P(TouchIdAuthenticatorTest, GetAssertionEmpty) {
+  GetAssertionCallback callback;
+  CtapGetAssertionRequest request(kRp1, "{json: true}");
+  authenticator_->GetAssertion(std::move(request), CtapGetAssertionOptions(),
+                               callback.callback());
+  callback.WaitForCallback();
+  EXPECT_EQ(callback.status(), CtapDeviceResponseCode::kCtap2ErrNoCredentials);
+}
+
 INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(TouchIdAuthenticatorTest);
 
 }  // namespace
diff --git a/device/fido/mac/credential_metadata.cc b/device/fido/mac/credential_metadata.cc
index 85a54de..e6dfa95 100644
--- a/device/fido/mac/credential_metadata.cc
+++ b/device/fido/mac/credential_metadata.cc
@@ -458,10 +458,9 @@
       Cryptor(secret).Seal(Cryptor::Algorithm::kAes256GcmSiv, fixed_zero_nonce,
                            pt, /*authenticated_data=*/{});
 
-  // HexEncode to ensure that the result is valid UTF-8. Values of keychain
-  // field that stores the encrypted RP ID (kSecAttrLabel) are CFStringRef. The
-  // expected encoding is undocumented but must be UTF-8 (see `_ImportKey()` in
-  // https://opensource.apple.com/source/libsecurity_keychain/libsecurity_keychain-55050.2/lib/SecItem.cpp).
+  // HexEncode to ensure that the result is valid UTF-8. The result of this
+  // function will be converted to an NSString via SysUTF8ToNSString and
+  // therefore must be valid for that.
   return base::HexEncode(ct.data(), ct.size());
 }
 
diff --git a/device/fido/mac/credential_metadata.h b/device/fido/mac/credential_metadata.h
index fe5498a0..2a618bb 100644
--- a/device/fido/mac/credential_metadata.h
+++ b/device/fido/mac/credential_metadata.h
@@ -170,8 +170,9 @@
                                           base::span<const uint8_t> user_id);
 
 // EncodeRpId encodes the given RP ID for storage in the macOS keychain. The
-// returned value is a UTF-8 string, to ensure it can be set as the
-// `kSecAttrLabel` value of a keychain item.
+// returned value is guaranteed to be a valid UTF-8 string, to ensure it can
+// safely be converted to an NSString and used as a string property in a
+// parameters dictionary.
 COMPONENT_EXPORT(DEVICE_FIDO)
 std::string EncodeRpId(const std::string& secret, const std::string& rp_id);
 
diff --git a/device/fido/mac/credential_store.h b/device/fido/mac/credential_store.h
index 53bff06..f487405 100644
--- a/device/fido/mac/credential_store.h
+++ b/device/fido/mac/credential_store.h
@@ -6,6 +6,7 @@
 #define DEVICE_FIDO_MAC_CREDENTIAL_STORE_H_
 
 #include <list>
+#include <memory>
 #include <set>
 #include <string>
 #include <utility>
@@ -24,8 +25,6 @@
 
 #if defined(__OBJC__)
 @class LAContext;
-#else
-class LAContext;
 #endif
 
 // This enum represents the error or success statuses of calling
@@ -89,13 +88,13 @@
   TouchIdCredentialStore& operator=(const TouchIdCredentialStore&) = delete;
   ~TouchIdCredentialStore() override;
 
+#if defined(__OBJC__)
   // An LAContext that has been successfully evaluated using |TouchIdContext|
-  // may be passed in |authenticaton_context|, in order to authorize
+  // may be passed in |authentication_context|, in order to authorize
   // credentials returned by the `Find*` instance methods for signing without
   // triggering a Touch ID prompt.
-  void set_authentication_context(LAContext* authentication_context) {
-    authentication_context_ = authentication_context;
-  }
+  void SetAuthenticationContext(LAContext* authentication_context);
+#endif  // __OBJC__
 
   // CreateCredential inserts a new credential into the keychain. It returns
   // the new credential and its public key, or absl::nullopt if an error
@@ -128,7 +127,7 @@
 
   // FindResidentCredentials returns the client-side discoverable credentials
   // for the given |rp_id|. If |rp_id| is not specified, all resident
-  // credentials are returned. base::nulltopt is returned if an error occurred.
+  // credentials are returned. nullopt is returned if an error occurred.
   absl::optional<std::list<Credential>> FindResidentCredentials(
       const absl::optional<std::string>& rp_id) const;
 
@@ -169,7 +168,9 @@
       const std::set<std::vector<uint8_t>>& credential_ids) const;
 
   AuthenticatorConfig config_;
-  LAContext* authentication_context_ = nullptr;
+
+  struct ObjCStorage;
+  std::unique_ptr<ObjCStorage> objc_storage_;
 };
 
 }  // namespace device::fido::mac
diff --git a/device/fido/mac/credential_store.mm b/device/fido/mac/credential_store.mm
index 3e10753..1798b7c 100644
--- a/device/fido/mac/credential_store.mm
+++ b/device/fido/mac/credential_store.mm
@@ -15,6 +15,7 @@
 #include "base/mac/foundation_util.h"
 #include "base/mac/mac_logging.h"
 #include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/sys_string_conversions.h"
@@ -45,9 +46,6 @@
   CFDictionarySetValue(query, kSecAttrAccessGroup,
                        base::SysUTF8ToNSString(config.keychain_access_group));
   if (rp_id) {
-    // Values of `kSecAttrLabel` are CFStringRef. The expected encoding is
-    // undocumented but must be UTF-8; see `_ImportKey()` in
-    // https://opensource.apple.com/source/libsecurity_keychain/libsecurity_keychain-55050.2/lib/SecItem.cpp)
     CFDictionarySetValue(
         query, kSecAttrLabel,
         base::SysUTF8ToNSString(EncodeRpId(config.metadata_secret, *rp_id)));
@@ -197,10 +195,20 @@
   return metadata.version < CredentialMetadata::Version::kV4;
 }
 
+struct TouchIdCredentialStore::ObjCStorage {
+  base::scoped_nsobject<LAContext> authentication_context_;
+};
+
 TouchIdCredentialStore::TouchIdCredentialStore(AuthenticatorConfig config)
-    : config_(std::move(config)) {}
+    : config_(std::move(config)),
+      objc_storage_(std::make_unique<ObjCStorage>()) {}
 TouchIdCredentialStore::~TouchIdCredentialStore() = default;
 
+void TouchIdCredentialStore::SetAuthenticationContext(
+    LAContext* authentication_context) {
+  objc_storage_->authentication_context_.reset([authentication_context retain]);
+}
+
 absl::optional<std::pair<Credential, base::ScopedCFTypeRef<SecKeyRef>>>
 TouchIdCredentialStore::CreateCredential(
     const std::string& rp_id,
@@ -245,14 +253,15 @@
       base::FeatureList::IsEnabled(kWebAuthnMacPlatformAuthenticatorOptionalUv)
           ? kSecAccessControlPrivateKeyUsage
           : kSecAccessControlPrivateKeyUsage | kSecAccessControlUserPresence;
-  CFDictionarySetValue(
-      private_key_params, kSecAttrAccessControl,
+  base::ScopedCFTypeRef<SecAccessControlRef> access_control(
       SecAccessControlCreateWithFlags(
           kCFAllocatorDefault, kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
-          flags, nullptr));
-  if (authentication_context_) {
+          flags, /*error=*/nullptr));
+  CFDictionarySetValue(private_key_params, kSecAttrAccessControl,
+                       access_control);
+  if (objc_storage_->authentication_context_) {
     CFDictionarySetValue(private_key_params, kSecUseAuthenticationContext,
-                         authentication_context_);
+                         objc_storage_->authentication_context_);
   }
   base::ScopedCFTypeRef<CFErrorRef> cferr;
   base::ScopedCFTypeRef<SecKeyRef> private_key =
@@ -323,15 +332,16 @@
   // Credential can only be used when the device is unlocked. Private key is
   // available for signing after user authorization with biometrics or
   // password.
-  CFDictionarySetValue(
-      private_key_params, kSecAttrAccessControl,
+  base::ScopedCFTypeRef<SecAccessControlRef> access_control(
       SecAccessControlCreateWithFlags(
           kCFAllocatorDefault, kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
           kSecAccessControlPrivateKeyUsage | kSecAccessControlUserPresence,
-          nullptr));
-  if (authentication_context_) {
+          /*error=*/nullptr));
+  CFDictionarySetValue(private_key_params, kSecAttrAccessControl,
+                       access_control);
+  if (objc_storage_->authentication_context_) {
     CFDictionarySetValue(private_key_params, kSecUseAuthenticationContext,
-                         authentication_context_);
+                         objc_storage_->authentication_context_);
   }
   base::ScopedCFTypeRef<CFErrorRef> cferr;
   base::ScopedCFTypeRef<SecKeyRef> private_key =
@@ -492,9 +502,9 @@
   // `kSecAttrLabel` attribute wouldn't match the encoded RP ID.
   base::ScopedCFTypeRef<CFMutableDictionaryRef> query =
       DefaultKeychainQuery(config_, rp_id);
-  if (authentication_context_) {
+  if (objc_storage_->authentication_context_) {
     CFDictionarySetValue(query, kSecUseAuthenticationContext,
-                         authentication_context_);
+                         objc_storage_->authentication_context_);
   }
   CFDictionarySetValue(query, kSecReturnRef, @YES);
   CFDictionarySetValue(query, kSecReturnAttributes, @YES);
@@ -596,9 +606,8 @@
     base::ScopedCFTypeRef<SecKeyRef> private_key(key,
                                                  base::scoped_policy::RETAIN);
 
-    credentials.emplace_back(
-        Credential{std::move(private_key), std::move(credential_id),
-                   std::move(*metadata), std::move(rp_id_value)});
+    credentials.emplace_back(std::move(private_key), std::move(credential_id),
+                             std::move(*metadata), std::move(rp_id_value));
   }
   return std::move(credentials);
 }
diff --git a/device/fido/mac/get_assertion_operation.mm b/device/fido/mac/get_assertion_operation.mm
index 63e32855..99c326d2 100644
--- a/device/fido/mac/get_assertion_operation.mm
+++ b/device/fido/mac/get_assertion_operation.mm
@@ -55,9 +55,8 @@
   }
 
   if (credentials->empty()) {
-    // TouchIdAuthenticator::HasCredentialForGetAssertionRequest() is
-    // invoked first to ensure this doesn't occur.
-    NOTREACHED();
+    // This can happen if e.g. a credential is deleted after it is shown to the
+    // user on the account picker.
     std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrNoCredentials,
                              {});
     return;
@@ -96,7 +95,7 @@
 
   // Re-fetch credentials with the now evaluated LAContext, so that making
   // signatures does not trigger yet another Touch ID prompt.
-  credential_store_->set_authentication_context(
+  credential_store_->SetAuthenticationContext(
       touch_id_context_->authentication_context());
 
   absl::optional<std::list<Credential>> credentials =
diff --git a/device/fido/mac/make_credential_operation.mm b/device/fido/mac/make_credential_operation.mm
index 8aec60c..9532995c 100644
--- a/device/fido/mac/make_credential_operation.mm
+++ b/device/fido/mac/make_credential_operation.mm
@@ -82,7 +82,7 @@
   // Setting an authentication context authorizes credentials returned from the
   // credential store for signing without triggering yet another Touch ID
   // prompt.
-  credential_store_->set_authentication_context(
+  credential_store_->SetAuthenticationContext(
       touch_id_context_->authentication_context());
 
   CreateCredential(/*has_uv=*/true);
diff --git a/device/fido/strings/fido_strings_da.xtb b/device/fido/strings/fido_strings_da.xtb
index 5d86e40..6b0adf4 100644
--- a/device/fido/strings/fido_strings_da.xtb
+++ b/device/fido/strings/fido_strings_da.xtb
@@ -1,5 +1,5 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="da">
-<translation id="6082592655150610743">bekræfte din identitet i <ph name="APP_NAME" /></translation>
+<translation id="6082592655150610743">verificere din identitet i <ph name="APP_NAME" /></translation>
 </translationbundle>
\ No newline at end of file
diff --git a/docs/fuchsia/build_instructions.md b/docs/fuchsia/build_instructions.md
index 4977c6dc..8e117c5 100644
--- a/docs/fuchsia/build_instructions.md
+++ b/docs/fuchsia/build_instructions.md
@@ -276,7 +276,7 @@
 If you have a Fuchsia checkout and build, there are GN arguments in Chromium
 that make working with both Fuchsia and Chromium checkouts easier.
 
-* `default_fuchsia_build_dir_for_installation`. Point this to an output
+* `default_fuchsia_out_dir`. Point this to an output
   directory in Fuchsia. For instance. `/path/to/src/fuchsia/out/qemu-x64`. This
   will automatically add the `--fuchsia-out-dir` flag to wrapper scripts.
 * `default_fuchsia_device_node_name`. Set this to a Fuchsia device node name.
diff --git a/docs/images/webui_build_pipeline.png b/docs/images/webui_build_pipeline.png
index 57d286ab..1493f16 100644
--- a/docs/images/webui_build_pipeline.png
+++ b/docs/images/webui_build_pipeline.png
Binary files differ
diff --git a/docs/webui_build_configuration.md b/docs/webui_build_configuration.md
index b87e4a3f..e20abc6 100644
--- a/docs/webui_build_configuration.md
+++ b/docs/webui_build_configuration.md
@@ -311,6 +311,40 @@
 }
 ```
 
+### **minify_js**
+```
+This rule is used to minify Javascript files to reduce build size.
+Also generates a manifest file to |target_gen_dir| named
+minify_js_manifest.json. Note that this should not be used alongside
+optimize_webui, which minifies files in addition to bundling them.
+```
+
+#### **Arguments**
+```
+in_folder: The location of the input files to be minified.
+in_files: The list of JS files to minify with respect to the |in_folder|.
+out_folder: The location where minified files will be outputted.
+deps: Targets generating any files being minified.
+```
+
+#### **Example**
+```
+import("//ui/webui/resources/tools/minify_js.gni")
+import ("//chrome/common/features.gni")
+
+# minify_js should generally only be called when the optimize_webui
+# GN flag is enabled.
+if (optimize_webui) {
+  minify_js("build") {
+    in_files = [ "my_webui.js" ]
+    in_folder = "$target_gen_dir/tsc"
+    # Assumes the JS files were generated by a ts_library target called
+    # build_ts.
+    deps = [ ":build_ts" ]
+  }
+}
+```
+
 ### **generate_grd**
 ```
 This rule is used to list the WebUI resources that need to be served at runtime
@@ -439,6 +473,7 @@
 ts_library("build_ts")
 merge_js_source_maps("merge_source_maps")
 optimize_webui("build_bundle")
+minify_js("build_min_js")
 generate_grd("build_grd")
 generate_grd("build_grdp")
 grit("resources")
@@ -502,6 +537,8 @@
           invoked with the |minify| flag on, to minify HTML/CSS code.
           If |optimize_webui_in_files| is provided then optimize_webui() will be
           invoked to bundle+minify JS code (using Rollup and Terser).
+          If |optimize_webui_in_files| is not provided then minify_js() will be
+          invoked to minify JS code (using Terser).
           |optimize_webui_host| must be specified if |optimize_webui_in_files|
           is provided.
 optimize_webui_excludes: See |excludes| in optimize_webui(). Optional.
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index 3bf6e8d..8eb64109 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -1101,11 +1101,12 @@
     content::BrowserContext* browser_context,
     int rules_registry_id,
     scoped_refptr<WebRequestRulesRegistry> rules_registry) {
-  RulesRegistryKey key(browser_context, rules_registry_id);
-  if (rules_registry.get())
+  RulesRegistryKey key(BrowserContextID(browser_context), rules_registry_id);
+  if (rules_registry.get()) {
     rules_registries_[key] = rules_registry;
-  else
+  } else {
     rules_registries_.erase(key);
+  }
 }
 
 int ExtensionWebRequestEventRouter::OnBeforeRequest(
@@ -1930,13 +1931,6 @@
                                    : std::move(removed_listeners.front());
 }
 
-// static
-ExtensionWebRequestEventRouter::BrowserContextID
-ExtensionWebRequestEventRouter::GetBrowserContextID(
-    const content::BrowserContext* browser_context) {
-  return reinterpret_cast<BrowserContextID>(browser_context);
-}
-
 void ExtensionWebRequestEventRouter::RemoveLazyListener(
     content::BrowserContext* original_context,
     const ExtensionId& extension_id,
@@ -2709,7 +2703,8 @@
                               ? request->web_view_rules_registry_id
                               : RulesRegistryService::kDefaultRulesRegistryID;
 
-  RulesRegistryKey rules_key(browser_context, rules_registry_id);
+  RulesRegistryKey rules_key(BrowserContextID(browser_context),
+                             rules_registry_id);
   // If this check fails, check that the active stages are up to date in
   // extensions/browser/api/declarative_webrequest/request_stage.h .
   DCHECK(request_stage & kActiveStages);
@@ -2731,8 +2726,8 @@
 
   content::BrowserContext* cross_browser_context =
       GetCrossBrowserContext(browser_context);
-  RulesRegistryKey cross_browser_context_rules_key(cross_browser_context,
-                                                   rules_registry_id);
+  RulesRegistryKey cross_browser_context_rules_key(
+      BrowserContextID(cross_browser_context), rules_registry_id);
   if (cross_browser_context) {
     auto it = rules_registries_.find(cross_browser_context_rules_key);
     if (it != rules_registries_.end())
diff --git a/extensions/browser/api/web_request/web_request_api.h b/extensions/browser/api/web_request/web_request_api.h
index 519e058..0da0615 100644
--- a/extensions/browser/api/web_request/web_request_api.h
+++ b/extensions/browser/api/web_request/web_request_api.h
@@ -306,6 +306,12 @@
   // only, and are never deferenced.
   using BrowserContextID = std::uintptr_t;
 
+  static BrowserContextID GetBrowserContextID(
+      content::BrowserContext* browser_context) {
+    return reinterpret_cast<BrowserContextID>(
+        static_cast<void*>(browser_context));
+  }
+
   // The events denoting the lifecycle of a given network request.
   enum EventTypes {
     kInvalidEvent = 0,
@@ -744,9 +750,6 @@
       RawListeners* listeners_out,
       int* extra_info_spec_out);
 
-  static BrowserContextID GetBrowserContextID(
-      const content::BrowserContext* browser_context);
-
   // Decrements the count of event handlers blocking the given request. When the
   // count reaches 0, we stop blocking the request and proceed it using the
   // method requested by the extension with the highest precedence. Precedence
@@ -835,7 +838,7 @@
 
   CallbacksForPageLoad callbacks_for_page_load_;
 
-  typedef std::pair<content::BrowserContext*, int> RulesRegistryKey;
+  typedef std::pair<BrowserContextID, int> RulesRegistryKey;
   // Maps each browser_context (and OTRBrowserContext) and a webview key to its
   // respective rules registry.
   std::map<RulesRegistryKey,
diff --git a/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.cc b/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.cc
index 251f93d..c0d02ee 100644
--- a/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/angle_vulkan_image_backing.cc
@@ -64,10 +64,11 @@
 class AngleVulkanImageBacking::SkiaAngleVulkanImageRepresentation
     : public SkiaImageRepresentation {
  public:
-  SkiaAngleVulkanImageRepresentation(SharedImageManager* manager,
+  SkiaAngleVulkanImageRepresentation(GrDirectContext* gr_context,
+                                     SharedImageManager* manager,
                                      AngleVulkanImageBacking* backing,
                                      MemoryTypeTracker* tracker)
-      : SkiaImageRepresentation(manager, backing, tracker),
+      : SkiaImageRepresentation(gr_context, manager, backing, tracker),
         context_state_(backing_impl()->context_state_) {}
 
   ~SkiaAngleVulkanImageRepresentation() override = default;
@@ -354,8 +355,8 @@
     scoped_refptr<SharedContextState> context_state) {
   if (context_state->GrContextIsVulkan()) {
     DCHECK_EQ(context_state_, context_state.get());
-    return std::make_unique<SkiaAngleVulkanImageRepresentation>(manager, this,
-                                                                tracker);
+    return std::make_unique<SkiaAngleVulkanImageRepresentation>(
+        context_state->gr_context(), manager, this, tracker);
   }
   // If it is not vulkan context, it must be GL context being used with Skia
   // over passthrough command decoder.
diff --git a/gpu/command_buffer/service/shared_image/compound_image_backing.cc b/gpu/command_buffer/service/shared_image/compound_image_backing.cc
index 5d43c972d..7a27e64 100644
--- a/gpu/command_buffer/service/shared_image/compound_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/compound_image_backing.cc
@@ -159,11 +159,12 @@
 class WrappedSkiaCompoundImageRepresentation : public SkiaImageRepresentation {
  public:
   WrappedSkiaCompoundImageRepresentation(
+      GrDirectContext* gr_context,
       SharedImageManager* manager,
       SharedImageBacking* backing,
       MemoryTypeTracker* tracker,
       std::unique_ptr<SkiaImageRepresentation> wrapped)
-      : SkiaImageRepresentation(manager, backing, tracker),
+      : SkiaImageRepresentation(gr_context, manager, backing, tracker),
         wrapped_(std::move(wrapped)) {
     DCHECK(wrapped_);
   }
@@ -562,13 +563,13 @@
   if (!backing)
     return nullptr;
 
-  auto real_rep =
-      backing->ProduceSkiaGanesh(manager, tracker, std::move(context_state));
+  auto real_rep = backing->ProduceSkiaGanesh(manager, tracker, context_state);
   if (!real_rep)
     return nullptr;
 
+  auto* gr_context = context_state ? context_state->gr_context() : nullptr;
   return std::make_unique<WrappedSkiaCompoundImageRepresentation>(
-      manager, this, tracker, std::move(real_rep));
+      gr_context, manager, this, tracker, std::move(real_rep));
 }
 
 std::unique_ptr<OverlayImageRepresentation>
diff --git a/gpu/command_buffer/service/shared_image/dcomp_surface_image_representation.cc b/gpu/command_buffer/service/shared_image/dcomp_surface_image_representation.cc
index 0c67146..9f36528b 100644
--- a/gpu/command_buffer/service/shared_image/dcomp_surface_image_representation.cc
+++ b/gpu/command_buffer/service/shared_image/dcomp_surface_image_representation.cc
@@ -47,7 +47,10 @@
     SharedImageManager* manager,
     SharedImageBacking* backing,
     MemoryTypeTracker* tracker)
-    : SkiaImageRepresentation(manager, backing, tracker),
+    : SkiaImageRepresentation(context_state->gr_context(),
+                              manager,
+                              backing,
+                              tracker),
       context_state_(std::move(context_state)) {
   DCHECK(context_state_);
 }
diff --git a/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc b/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc
index 5bae2a2..18ff05b 100644
--- a/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/external_vk_image_backing.cc
@@ -818,7 +818,7 @@
     // should also be using Vulkan.
     DCHECK_EQ(context_state_, context_state);
     return std::make_unique<ExternalVkImageSkiaImageRepresentation>(
-        manager, this, tracker);
+        context_state->gr_context(), manager, this, tracker);
   }
   // If it is not vulkan context, it must be GL context being used with Skia
   // over passthrough command decoder.
diff --git a/gpu/command_buffer/service/shared_image/external_vk_image_skia_representation.cc b/gpu/command_buffer/service/shared_image/external_vk_image_skia_representation.cc
index b84721a..3aa31d3d 100644
--- a/gpu/command_buffer/service/shared_image/external_vk_image_skia_representation.cc
+++ b/gpu/command_buffer/service/shared_image/external_vk_image_skia_representation.cc
@@ -18,10 +18,11 @@
 namespace gpu {
 
 ExternalVkImageSkiaImageRepresentation::ExternalVkImageSkiaImageRepresentation(
+    GrDirectContext* gr_context,
     SharedImageManager* manager,
     SharedImageBacking* backing,
     MemoryTypeTracker* tracker)
-    : SkiaImageRepresentation(manager, backing, tracker),
+    : SkiaImageRepresentation(gr_context, manager, backing, tracker),
       context_state_(backing_impl()->context_state()) {}
 
 ExternalVkImageSkiaImageRepresentation::
diff --git a/gpu/command_buffer/service/shared_image/external_vk_image_skia_representation.h b/gpu/command_buffer/service/shared_image/external_vk_image_skia_representation.h
index 2aeadf3..e040167 100644
--- a/gpu/command_buffer/service/shared_image/external_vk_image_skia_representation.h
+++ b/gpu/command_buffer/service/shared_image/external_vk_image_skia_representation.h
@@ -15,7 +15,8 @@
 
 class ExternalVkImageSkiaImageRepresentation : public SkiaImageRepresentation {
  public:
-  ExternalVkImageSkiaImageRepresentation(SharedImageManager* manager,
+  ExternalVkImageSkiaImageRepresentation(GrDirectContext* gr_context,
+                                         SharedImageManager* manager,
                                          SharedImageBacking* backing,
                                          MemoryTypeTracker* tracker);
   ~ExternalVkImageSkiaImageRepresentation() override;
diff --git a/gpu/command_buffer/service/shared_image/gl_texture_common_representations.cc b/gpu/command_buffer/service/shared_image/gl_texture_common_representations.cc
index e61f9239..6ae98604 100644
--- a/gpu/command_buffer/service/shared_image/gl_texture_common_representations.cc
+++ b/gpu/command_buffer/service/shared_image/gl_texture_common_representations.cc
@@ -110,7 +110,10 @@
     scoped_refptr<SharedContextState> context_state,
     std::vector<sk_sp<SkPromiseImageTexture>> promise_textures,
     MemoryTypeTracker* tracker)
-    : SkiaImageRepresentation(manager, backing, tracker),
+    : SkiaImageRepresentation(context_state->gr_context(),
+                              manager,
+                              backing,
+                              tracker),
       client_(client),
       context_state_(std::move(context_state)),
       promise_textures_(std::move(promise_textures)) {
diff --git a/gpu/command_buffer/service/shared_image/iosurface_image_backing.mm b/gpu/command_buffer/service/shared_image/iosurface_image_backing.mm
index ae8fe7b..d847004a 100644
--- a/gpu/command_buffer/service/shared_image/iosurface_image_backing.mm
+++ b/gpu/command_buffer/service/shared_image/iosurface_image_backing.mm
@@ -194,7 +194,10 @@
     scoped_refptr<SharedContextState> context_state,
     std::vector<sk_sp<SkPromiseImageTexture>> promise_textures,
     MemoryTypeTracker* tracker)
-    : SkiaImageRepresentation(manager, backing, tracker),
+    : SkiaImageRepresentation(context_state->gr_context(),
+                              manager,
+                              backing,
+                              tracker),
       egl_state_(egl_state),
       context_state_(std::move(context_state)),
       promise_textures_(promise_textures) {
diff --git a/gpu/command_buffer/service/shared_image/raw_draw_image_backing.cc b/gpu/command_buffer/service/shared_image/raw_draw_image_backing.cc
index f00dd81..032d4844 100644
--- a/gpu/command_buffer/service/shared_image/raw_draw_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/raw_draw_image_backing.cc
@@ -58,10 +58,11 @@
 class RawDrawImageBacking::SkiaRawDrawImageRepresentation
     : public SkiaImageRepresentation {
  public:
-  SkiaRawDrawImageRepresentation(SharedImageManager* manager,
+  SkiaRawDrawImageRepresentation(GrDirectContext* gr_context,
+                                 SharedImageManager* manager,
                                  SharedImageBacking* backing,
                                  MemoryTypeTracker* tracker)
-      : SkiaImageRepresentation(manager, backing, tracker) {}
+      : SkiaImageRepresentation(gr_context, manager, backing, tracker) {}
 
   bool SupportsMultipleConcurrentReadAccess() override { return true; }
 
@@ -153,8 +154,8 @@
   if (!context_state_)
     context_state_ = context_state;
   DCHECK(context_state_ == context_state);
-  return std::make_unique<SkiaRawDrawImageRepresentation>(manager, this,
-                                                          tracker);
+  return std::make_unique<SkiaRawDrawImageRepresentation>(
+      context_state->gr_context(), manager, this, tracker);
 }
 
 void RawDrawImageBacking::ResetPaintOpBuffer() {
diff --git a/gpu/command_buffer/service/shared_image/shared_image_representation.cc b/gpu/command_buffer/service/shared_image/shared_image_representation.cc
index 50bde77..e76fb00e 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_representation.cc
+++ b/gpu/command_buffer/service/shared_image/shared_image_representation.cc
@@ -22,6 +22,9 @@
 
 namespace gpu {
 
+///////////////////////////////////////////////////////////////////////////////
+// SharedImageRepresentation
+
 SharedImageRepresentation::SharedImageRepresentation(
     SharedImageManager* manager,
     SharedImageBacking* backing,
@@ -55,6 +58,9 @@
   return static_cast<size_t>(format().NumberOfPlanes());
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// GLTextureImageRepresentationBase
+
 std::unique_ptr<GLTextureImageRepresentation::ScopedAccess>
 GLTextureImageRepresentationBase::BeginScopedAccess(
     GLenum mode,
@@ -87,6 +93,9 @@
   return false;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// GLTextureImageRepresentation
+
 gpu::TextureBase* GLTextureImageRepresentation::GetTextureBase(
     int plane_index) {
   return GetTexture(plane_index);
@@ -115,6 +124,9 @@
     texture->SetLevelClearedRect(texture->target(), 0, cleared_rect);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// GLTexturePassthroughImageRepresentation
+
 gpu::TextureBase* GLTexturePassthroughImageRepresentation::GetTextureBase(
     int plane_index) {
   return GetTexturePassthrough(plane_index).get();
@@ -131,6 +143,18 @@
   return false;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// SkiaImageRepresentation
+
+SkiaImageRepresentation::SkiaImageRepresentation(GrDirectContext* gr_context,
+                                                 SharedImageManager* manager,
+                                                 SharedImageBacking* backing,
+                                                 MemoryTypeTracker* tracker)
+    : SharedImageRepresentation(manager, backing, tracker),
+      gr_context_(gr_context) {}
+
+SkiaImageRepresentation::~SkiaImageRepresentation() = default;
+
 bool SkiaImageRepresentation::SupportsMultipleConcurrentReadAccess() {
   return false;
 }
@@ -364,6 +388,9 @@
       std::move(promise_image_textures), std::move(end_state));
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// OverlayImageRepresentation
+
 #if BUILDFLAG(IS_ANDROID)
 AHardwareBuffer* OverlayImageRepresentation::GetAHardwareBuffer() {
   NOTREACHED();
@@ -427,6 +454,9 @@
       std::move(acquire_fence));
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// DawnImageRepresentation
+
 DawnImageRepresentation::ScopedAccess::ScopedAccess(
     base::PassKey<DawnImageRepresentation> /* pass_key */,
     DawnImageRepresentation* representation,
@@ -460,6 +490,9 @@
       base::PassKey<DawnImageRepresentation>(), this, texture);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// SharedImageRepresentationFactoryRef
+
 SharedImageRepresentationFactoryRef::SharedImageRepresentationFactoryRef(
     SharedImageManager* manager,
     SharedImageBacking* backing,
@@ -483,6 +516,9 @@
   }
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// VaapiImageRepresentation
+
 VaapiImageRepresentation::VaapiImageRepresentation(
     SharedImageManager* manager,
     SharedImageBacking* backing,
@@ -513,6 +549,9 @@
       base::PassKey<VaapiImageRepresentation>(), this);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// MemoryImageRepresentation
+
 MemoryImageRepresentation::ScopedReadAccess::ScopedReadAccess(
     base::PassKey<MemoryImageRepresentation> pass_key,
     MemoryImageRepresentation* representation,
@@ -527,6 +566,9 @@
       base::PassKey<MemoryImageRepresentation>(), this, BeginReadAccess());
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// RasterImageRepresentation
+
 RasterImageRepresentation::ScopedReadAccess::ScopedReadAccess(
     base::PassKey<RasterImageRepresentation> pass_key,
     RasterImageRepresentation* representation,
@@ -574,6 +616,9 @@
                        surface_props, clear_color, visible));
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// VideoDecodeImageRepresentation
+
 VideoDecodeImageRepresentation::VideoDecodeImageRepresentation(
     SharedImageManager* manager,
     SharedImageBacking* backing,
diff --git a/gpu/command_buffer/service/shared_image/shared_image_representation.h b/gpu/command_buffer/service/shared_image/shared_image_representation.h
index b5b6ed08..01fd346 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_representation.h
+++ b/gpu/command_buffer/service/shared_image/shared_image_representation.h
@@ -19,6 +19,7 @@
 #include "gpu/gpu_gles2_export.h"
 #include "third_party/skia/include/core/SkImage.h"
 #include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/gpu/GrDirectContext.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
@@ -73,6 +74,9 @@
   kWrite,
 };
 
+///////////////////////////////////////////////////////////////////////////////
+// SharedImageRepresentation
+
 // A representation of a SharedImageBacking for use with a specific use case /
 // api.
 class GPU_GLES2_EXPORT SharedImageRepresentation {
@@ -154,6 +158,8 @@
   bool has_scoped_access_ = false;
 };
 
+///////////////////////////////////////////////////////////////////////////////
+// SharedImageRepresentationFactoryRef
 class SharedImageRepresentationFactoryRef : public SharedImageRepresentation {
  public:
   SharedImageRepresentationFactoryRef(SharedImageManager* manager,
@@ -179,6 +185,9 @@
   const bool is_primary_;
 };
 
+///////////////////////////////////////////////////////////////////////////////
+// GLTextureImageRepresentationBase
+
 class GPU_GLES2_EXPORT GLTextureImageRepresentationBase
     : public SharedImageRepresentation {
  public:
@@ -227,6 +236,9 @@
   virtual bool SupportsMultipleConcurrentReadAccess();
 };
 
+///////////////////////////////////////////////////////////////////////////////
+// GLTextureImageRepresentation
+
 class GPU_GLES2_EXPORT GLTextureImageRepresentation
     : public GLTextureImageRepresentationBase {
  public:
@@ -249,6 +261,9 @@
   void UpdateClearedStateOnEndAccess() override;
 };
 
+///////////////////////////////////////////////////////////////////////////////
+// GLTexturePassthroughImageRepresentation
+
 class GPU_GLES2_EXPORT GLTexturePassthroughImageRepresentation
     : public GLTextureImageRepresentationBase {
  public:
@@ -275,6 +290,9 @@
   friend class WrappedGLTexturePassthroughCompoundImageRepresentation;
 };
 
+///////////////////////////////////////////////////////////////////////////////
+// SkiaImageRepresentation
+
 class GPU_GLES2_EXPORT SkiaImageRepresentation
     : public SharedImageRepresentation {
  public:
@@ -357,10 +375,11 @@
     std::unique_ptr<GrBackendSurfaceMutableState> end_state_;
   };
 
-  SkiaImageRepresentation(SharedImageManager* manager,
+  SkiaImageRepresentation(GrDirectContext* gr_context,
+                          SharedImageManager* manager,
                           SharedImageBacking* backing,
-                          MemoryTypeTracker* tracker)
-      : SharedImageRepresentation(manager, backing, tracker) {}
+                          MemoryTypeTracker* tracker);
+  ~SkiaImageRepresentation() override;
 
   // Note: See BeginWriteAccess below for a description of the semaphore
   // parameters.
@@ -444,8 +463,13 @@
       std::vector<GrBackendSemaphore>* end_semaphores,
       std::unique_ptr<GrBackendSurfaceMutableState>* end_state) = 0;
   virtual void EndReadAccess() = 0;
+
+  raw_ptr<GrDirectContext> gr_context_ = nullptr;
 };
 
+///////////////////////////////////////////////////////////////////////////////
+// DawnImageRepresentation
+
 class GPU_GLES2_EXPORT DawnImageRepresentation
     : public SharedImageRepresentation {
  public:
@@ -490,6 +514,9 @@
   virtual void EndAccess() = 0;
 };
 
+///////////////////////////////////////////////////////////////////////////////
+// OverlayImageRepresentation
+
 class GPU_GLES2_EXPORT OverlayImageRepresentation
     : public SharedImageRepresentation {
  public:
@@ -582,6 +609,9 @@
 #endif
 };
 
+///////////////////////////////////////////////////////////////////////////////
+// LegacyOverlayImageRepresentation
+
 #if BUILDFLAG(IS_ANDROID)
 class GPU_GLES2_EXPORT LegacyOverlayImageRepresentation
     : public SharedImageRepresentation {
@@ -601,6 +631,9 @@
 };
 #endif
 
+///////////////////////////////////////////////////////////////////////////////
+// MemoryImageRepresentation
+
 class GPU_GLES2_EXPORT MemoryImageRepresentation
     : public SharedImageRepresentation {
  public:
@@ -648,6 +681,9 @@
       scoped_refptr<gfx::NativePixmap> pixmap) = 0;
 };
 
+///////////////////////////////////////////////////////////////////////////////
+// VaapiImageRepresentation
+
 // Representation of a SharedImageBacking as a VA-API surface.
 // This representation is currently only supported by OzoneImageBacking.
 //
@@ -691,6 +727,9 @@
   virtual void BeginAccess() = 0;
 };
 
+///////////////////////////////////////////////////////////////////////////////
+// RasterImageRepresentation
+
 // Representation of a SharedImageBacking for raster work.
 // This representation is used for raster work and compositor. The raster work
 // will be converted to a cc::PaintOpBuffer and stored in the
@@ -769,6 +808,9 @@
   virtual void EndWriteAccess(base::OnceClosure callback) = 0;
 };
 
+///////////////////////////////////////////////////////////////////////////////
+// VideoDecodeImageRepresentation
+
 class GPU_GLES2_EXPORT VideoDecodeImageRepresentation
     : public SharedImageRepresentation {
  public:
diff --git a/gpu/command_buffer/service/shared_image/skia_gl_image_representation.cc b/gpu/command_buffer/service/shared_image/skia_gl_image_representation.cc
index 83502c7..688d39c 100644
--- a/gpu/command_buffer/service/shared_image/skia_gl_image_representation.cc
+++ b/gpu/command_buffer/service/shared_image/skia_gl_image_representation.cc
@@ -97,7 +97,10 @@
     SharedImageManager* manager,
     SharedImageBacking* backing,
     MemoryTypeTracker* tracker)
-    : SkiaImageRepresentation(manager, backing, tracker),
+    : SkiaImageRepresentation(context_state->gr_context(),
+                              manager,
+                              backing,
+                              tracker),
       gl_representation_(std::move(gl_representation)),
       promise_textures_(std::move(promise_textures)),
       context_state_(std::move(context_state)) {
diff --git a/gpu/command_buffer/service/shared_image/skia_vk_android_image_representation.cc b/gpu/command_buffer/service/shared_image/skia_vk_android_image_representation.cc
index 2c301c5..3289273 100644
--- a/gpu/command_buffer/service/shared_image/skia_vk_android_image_representation.cc
+++ b/gpu/command_buffer/service/shared_image/skia_vk_android_image_representation.cc
@@ -34,7 +34,10 @@
     AndroidImageBacking* backing,
     scoped_refptr<SharedContextState> context_state,
     MemoryTypeTracker* tracker)
-    : SkiaImageRepresentation(manager, backing, tracker),
+    : SkiaImageRepresentation(context_state->gr_context(),
+                              manager,
+                              backing,
+                              tracker),
       context_state_(std::move(context_state)) {
   DCHECK(backing);
   DCHECK(context_state_);
diff --git a/gpu/command_buffer/service/shared_image/skia_vk_ozone_image_representation.cc b/gpu/command_buffer/service/shared_image/skia_vk_ozone_image_representation.cc
index 9aba4ed..212769e9 100644
--- a/gpu/command_buffer/service/shared_image/skia_vk_ozone_image_representation.cc
+++ b/gpu/command_buffer/service/shared_image/skia_vk_ozone_image_representation.cc
@@ -34,7 +34,10 @@
     scoped_refptr<SharedContextState> context_state,
     std::unique_ptr<VulkanImage> vulkan_image,
     MemoryTypeTracker* tracker)
-    : SkiaImageRepresentation(manager, backing, tracker),
+    : SkiaImageRepresentation(context_state->gr_context(),
+                              manager,
+                              backing,
+                              tracker),
       vulkan_image_(std::move(vulkan_image)),
       context_state_(std::move(context_state)) {
   DCHECK(backing);
diff --git a/gpu/command_buffer/service/shared_image/test_image_backing.cc b/gpu/command_buffer/service/shared_image/test_image_backing.cc
index c70b06b2..13cbac6 100644
--- a/gpu/command_buffer/service/shared_image/test_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/test_image_backing.cc
@@ -63,10 +63,11 @@
 
 class TestSkiaImageRepresentation : public SkiaImageRepresentation {
  public:
-  TestSkiaImageRepresentation(SharedImageManager* manager,
+  TestSkiaImageRepresentation(GrDirectContext* gr_context,
+                              SharedImageManager* manager,
                               SharedImageBacking* backing,
                               MemoryTypeTracker* tracker)
-      : SkiaImageRepresentation(manager, backing, tracker) {}
+      : SkiaImageRepresentation(gr_context, manager, backing, tracker) {}
 
  protected:
   std::vector<sk_sp<SkSurface>> BeginWriteAccess(
@@ -294,7 +295,9 @@
     SharedImageManager* manager,
     MemoryTypeTracker* tracker,
     scoped_refptr<SharedContextState> context_state) {
-  return std::make_unique<TestSkiaImageRepresentation>(manager, this, tracker);
+  return std::make_unique<TestSkiaImageRepresentation>(
+      context_state ? context_state->gr_context() : nullptr, manager, this,
+      tracker);
 }
 
 std::unique_ptr<DawnImageRepresentation> TestImageBacking::ProduceDawn(
diff --git a/gpu/command_buffer/service/shared_image/wrapped_sk_image_backing.cc b/gpu/command_buffer/service/shared_image/wrapped_sk_image_backing.cc
index 0b0b6f44..fe224bc 100644
--- a/gpu/command_buffer/service/shared_image/wrapped_sk_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/wrapped_sk_image_backing.cc
@@ -47,7 +47,10 @@
                               SharedImageBacking* backing,
                               MemoryTypeTracker* tracker,
                               scoped_refptr<SharedContextState> context_state)
-      : SkiaImageRepresentation(manager, backing, tracker),
+      : SkiaImageRepresentation(context_state->gr_context(),
+                                manager,
+                                backing,
+                                tracker),
         context_state_(std::move(context_state)) {}
 
   ~SkiaImageRepresentationImpl() override { DCHECK(write_surfaces_.empty()); }
diff --git a/gpu/ipc/client/client_shared_image_interface.cc b/gpu/ipc/client/client_shared_image_interface.cc
index 68101e1..39312a9 100644
--- a/gpu/ipc/client/client_shared_image_interface.cc
+++ b/gpu/ipc/client/client_shared_image_interface.cc
@@ -166,8 +166,9 @@
 
   {
     base::AutoLock lock(lock_);
-    DCHECK_NE(mailboxes_.count(mailbox), 0u);
-    mailboxes_.erase(mailbox);
+    auto it = mailboxes_.find(mailbox);
+    CHECK(it != mailboxes_.end());
+    mailboxes_.erase(it);
   }
   proxy_->DestroySharedImage(sync_token, mailbox);
 }
@@ -196,7 +197,6 @@
     return mailbox;
 
   base::AutoLock lock(lock_);
-  DCHECK_EQ(mailboxes_.count(mailbox), 0u);
   mailboxes_.insert(mailbox);
   return mailbox;
 }
diff --git a/gpu/ipc/client/client_shared_image_interface.h b/gpu/ipc/client/client_shared_image_interface.h
index d6c0341a..50057a2 100644
--- a/gpu/ipc/client/client_shared_image_interface.h
+++ b/gpu/ipc/client/client_shared_image_interface.h
@@ -5,7 +5,8 @@
 #ifndef GPU_IPC_CLIENT_CLIENT_SHARED_IMAGE_INTERFACE_H_
 #define GPU_IPC_CLIENT_CLIENT_SHARED_IMAGE_INTERFACE_H_
 
-#include "base/containers/flat_set.h"
+#include <set>
+
 #include "base/memory/raw_ptr.h"
 #include "base/synchronization/lock.h"
 #include "base/thread_annotations.h"
@@ -97,7 +98,7 @@
   const raw_ptr<SharedImageInterfaceProxy> proxy_;
 
   base::Lock lock_;
-  base::flat_set<Mailbox> mailboxes_ GUARDED_BY(lock_);
+  std::multiset<Mailbox> mailboxes_ GUARDED_BY(lock_);
 };
 
 }  // namespace gpu
diff --git a/gpu/ipc/client/shared_image_interface_proxy.cc b/gpu/ipc/client/shared_image_interface_proxy.cc
index 6ae605c..5e99fe10 100644
--- a/gpu/ipc/client/shared_image_interface_proxy.cc
+++ b/gpu/ipc/client/shared_image_interface_proxy.cc
@@ -290,13 +290,44 @@
   {
     base::AutoLock lock(lock_);
 
-    DCHECK_NE(mailbox_to_usage_.count(mailbox), 0u);
-    mailbox_to_usage_.erase(mailbox);
+    auto it = mailbox_infos_.find(mailbox);
+    CHECK(it != mailbox_infos_.end());
+    auto& info = it->second;
 
-    last_flush_id_ = host_->EnqueueDeferredMessage(
-        mojom::DeferredRequestParams::NewSharedImageRequest(
-            mojom::DeferredSharedImageRequest::NewDestroySharedImage(mailbox)),
-        std::move(dependencies));
+    CHECK_GT(info.ref_count, 0);
+    if (--info.ref_count == 0) {
+      info.destruction_sync_tokens.insert(info.destruction_sync_tokens.end(),
+                                          dependencies.begin(),
+                                          dependencies.end());
+
+      last_flush_id_ = host_->EnqueueDeferredMessage(
+          mojom::DeferredRequestParams::NewSharedImageRequest(
+              mojom::DeferredSharedImageRequest::NewDestroySharedImage(
+                  mailbox)),
+          std::move(info.destruction_sync_tokens));
+
+      mailbox_infos_.erase(it);
+    } else if (!dependencies.empty()) {
+      constexpr size_t kMaxSyncTokens = 4;
+      // Avoid accumulating too many SyncTokens in case where client
+      // continiously adds and removes refs, but never reaches the zero. This
+      // will ensure that all subsequent calls (including DestroySharedImage)
+      // are happening after sync tokens are released.
+      // We flush only old SyncTokens here, as they are more likely to pass
+      // already, to reduce potential stalls.
+      if (info.destruction_sync_tokens.size() > kMaxSyncTokens) {
+        last_flush_id_ = host_->EnqueueDeferredMessage(
+            mojom::DeferredRequestParams::NewSharedImageRequest(
+                mojom::DeferredSharedImageRequest::NewNop(0)),
+            std::move(info.destruction_sync_tokens));
+
+        info.destruction_sync_tokens.clear();
+      }
+
+      info.destruction_sync_tokens.insert(info.destruction_sync_tokens.end(),
+                                          dependencies.begin(),
+                                          dependencies.end());
+    }
   }
 }
 
@@ -488,24 +519,39 @@
       GenerateDependenciesFromSyncToken(std::move(sync_token), host_);
   {
     base::AutoLock lock(lock_);
-    AddMailbox(mailbox, usage);
-    // Note: we enqueue the IPC under the lock to guarantee monotonicity of the
-    // release ids as seen by the service.
-    last_flush_id_ = host_->EnqueueDeferredMessage(
-        mojom::DeferredRequestParams::NewSharedImageRequest(
-            mojom::DeferredSharedImageRequest::NewAddReferenceToSharedImage(
-                mojom::AddReferenceToSharedImageParams::New(
-                    mailbox, ++next_release_id_))),
-        std::move(dependencies));
+    if (AddMailboxOrAddReference(mailbox, usage)) {
+      // Note: we enqueue the IPC under the lock to guarantee monotonicity of
+      // the release ids as seen by the service.
+      last_flush_id_ = host_->EnqueueDeferredMessage(
+          mojom::DeferredRequestParams::NewSharedImageRequest(
+              mojom::DeferredSharedImageRequest::NewAddReferenceToSharedImage(
+                  mojom::AddReferenceToSharedImageParams::New(
+                      mailbox, ++next_release_id_))),
+          std::move(dependencies));
+    }
   }
 }
 
 void SharedImageInterfaceProxy::AddMailbox(const Mailbox& mailbox,
                                            uint32_t usage) {
+  bool added = AddMailboxOrAddReference(mailbox, usage);
+  CHECK(added);
+}
+
+bool SharedImageInterfaceProxy::AddMailboxOrAddReference(const Mailbox& mailbox,
+                                                         uint32_t usage) {
   lock_.AssertAcquired();
 
-  DCHECK_EQ(mailbox_to_usage_.count(mailbox), 0u);
-  mailbox_to_usage_[mailbox] = usage;
+  auto& info = mailbox_infos_[mailbox];
+  if (++info.ref_count == 1) {
+    // If we just added this mailbox, initialize usage.
+    info.usage = usage;
+  }
+
+  // Usage can't be changed.
+  CHECK_EQ(info.usage, usage);
+
+  return info.ref_count == 1;
 }
 
 uint32_t SharedImageInterfaceProxy::UsageForMailbox(const Mailbox& mailbox) {
@@ -513,10 +559,11 @@
 
   // The mailbox may have been destroyed if the context on which the shared
   // image was created is deleted.
-  auto it = mailbox_to_usage_.find(mailbox);
-  if (it == mailbox_to_usage_.end())
+  auto it = mailbox_infos_.find(mailbox);
+  if (it == mailbox_infos_.end()) {
     return 0u;
-  return it->second;
+  }
+  return it->second.usage;
 }
 
 void SharedImageInterfaceProxy::NotifyMailboxAdded(const Mailbox& mailbox,
@@ -525,4 +572,13 @@
   AddMailbox(mailbox, usage);
 }
 
+SharedImageInterfaceProxy::SharedImageInfo::SharedImageInfo() = default;
+SharedImageInterfaceProxy::SharedImageInfo::~SharedImageInfo() = default;
+
+SharedImageInterfaceProxy::SharedImageInfo::SharedImageInfo(SharedImageInfo&&) =
+    default;
+SharedImageInterfaceProxy::SharedImageInfo&
+SharedImageInterfaceProxy::SharedImageInfo::operator=(SharedImageInfo&&) =
+    default;
+
 }  // namespace gpu
diff --git a/gpu/ipc/client/shared_image_interface_proxy.h b/gpu/ipc/client/shared_image_interface_proxy.h
index 27bc957..dcf788184 100644
--- a/gpu/ipc/client/shared_image_interface_proxy.h
+++ b/gpu/ipc/client/shared_image_interface_proxy.h
@@ -98,6 +98,21 @@
   void NotifyMailboxAdded(const Mailbox& mailbox, uint32_t usage);
 
  private:
+  struct SharedImageInfo {
+    SharedImageInfo();
+    ~SharedImageInfo();
+
+    SharedImageInfo(SharedImageInfo&&);
+    SharedImageInfo& operator=(SharedImageInfo&&);
+
+    SharedImageInfo(const SharedImageInfo&) = delete;
+    SharedImageInfo& operator=(const SharedImageInfo&) = delete;
+
+    int ref_count = 0;
+    uint32_t usage = 0;
+    std::vector<SyncToken> destruction_sync_tokens;
+  };
+
   bool GetSHMForPixelData(base::span<const uint8_t> pixel_data,
                           size_t* shm_offset,
                           bool* done_with_shm) EXCLUSIVE_LOCKS_REQUIRED(lock_);
@@ -105,6 +120,11 @@
   void AddMailbox(const Mailbox& mailbox, uint32_t usage)
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
+  // Returns true if it's first time mailbox was added.
+  [[nodiscard]] bool AddMailboxOrAddReference(const Mailbox& mailbox,
+                                              uint32_t usage)
+      EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
   const raw_ptr<GpuChannelHost> host_;
   const int32_t route_id_;
   base::Lock lock_;
@@ -116,7 +136,7 @@
   // The offset into |upload_buffer_| at which data is no longer used.
   size_t upload_buffer_offset_ GUARDED_BY(lock_) = 0;
 
-  base::flat_map<Mailbox, uint32_t> mailbox_to_usage_ GUARDED_BY(lock_);
+  base::flat_map<Mailbox, SharedImageInfo> mailbox_infos_ GUARDED_BY(lock_);
 };
 
 }  // namespace gpu
diff --git "a/infra/config/generated/builders/ci/Dawn Mac x64 DEPS Release \050AMD\051/properties.json" "b/infra/config/generated/builders/ci/Dawn Mac x64 DEPS Release \050AMD\051/properties.json"
index acdae74..54041d7 100644
--- "a/infra/config/generated/builders/ci/Dawn Mac x64 DEPS Release \050AMD\051/properties.json"
+++ "b/infra/config/generated/builders/ci/Dawn Mac x64 DEPS Release \050AMD\051/properties.json"
@@ -66,6 +66,12 @@
           "builder": "Dawn Mac x64 DEPS Release (AMD)",
           "project": "chromium"
         }
+      ],
+      "mirroring_builder_group_and_names": [
+        {
+          "builder": "dawn-mac-x64-deps-rel",
+          "group": "tryserver.chromium.dawn"
+        }
       ]
     }
   },
diff --git "a/infra/config/generated/builders/ci/Dawn Mac x64 Release \050AMD\051/properties.json" "b/infra/config/generated/builders/ci/Dawn Mac x64 Release \050AMD\051/properties.json"
index 848aa18..563642d 100644
--- "a/infra/config/generated/builders/ci/Dawn Mac x64 Release \050AMD\051/properties.json"
+++ "b/infra/config/generated/builders/ci/Dawn Mac x64 Release \050AMD\051/properties.json"
@@ -69,6 +69,12 @@
           "builder": "Dawn Mac x64 Release (AMD)",
           "project": "chromium"
         }
+      ],
+      "mirroring_builder_group_and_names": [
+        {
+          "builder": "mac-dawn-rel",
+          "group": "tryserver.chromium.dawn"
+        }
       ]
     }
   },
diff --git a/infra/config/generated/builders/try/dawn-android-arm-deps-rel/properties.json b/infra/config/generated/builders/try/dawn-android-arm-deps-rel/properties.json
index f3ba88a..ca8f911c 100644
--- a/infra/config/generated/builders/try/dawn-android-arm-deps-rel/properties.json
+++ b/infra/config/generated/builders/try/dawn-android-arm-deps-rel/properties.json
@@ -54,5 +54,6 @@
     ]
   },
   "builder_group": "tryserver.chromium.dawn",
-  "recipe": "chromium_trybot"
+  "recipe": "chromium_trybot",
+  "root_solution_revision": "refs/heads/main"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/dawn-linux-x64-deps-rel/properties.json b/infra/config/generated/builders/try/dawn-linux-x64-deps-rel/properties.json
index 9bb3ec1..826248d 100644
--- a/infra/config/generated/builders/try/dawn-linux-x64-deps-rel/properties.json
+++ b/infra/config/generated/builders/try/dawn-linux-x64-deps-rel/properties.json
@@ -125,5 +125,6 @@
     ]
   },
   "builder_group": "tryserver.chromium.dawn",
-  "recipe": "chromium_trybot"
+  "recipe": "chromium_trybot",
+  "root_solution_revision": "refs/heads/main"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/dawn-mac-x64-deps-rel/properties.json b/infra/config/generated/builders/try/dawn-mac-x64-deps-rel/properties.json
index d48feee..32e3ecd 100644
--- a/infra/config/generated/builders/try/dawn-mac-x64-deps-rel/properties.json
+++ b/infra/config/generated/builders/try/dawn-mac-x64-deps-rel/properties.json
@@ -31,6 +31,36 @@
           {
             "builder_id": {
               "bucket": "ci",
+              "builder": "Dawn Mac x64 DEPS Release (AMD)",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-dawn-archive",
+              "builder_group": "chromium.dawn",
+              "execution_mode": "TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium",
+                "target_bits": 64,
+                "target_platform": "mac"
+              },
+              "legacy_gclient_config": {
+                "config": "chromium"
+              },
+              "parent": {
+                "bucket": "ci",
+                "builder": "Dawn Mac x64 DEPS Builder",
+                "project": "chromium"
+              },
+              "run_tests_serially": true
+            }
+          },
+          {
+            "builder_id": {
+              "bucket": "ci",
               "builder": "Dawn Mac x64 DEPS Release (Intel)",
               "project": "chromium"
             },
@@ -70,6 +100,11 @@
       "builder_ids_in_scope_for_testing": [
         {
           "bucket": "ci",
+          "builder": "Dawn Mac x64 DEPS Release (AMD)",
+          "project": "chromium"
+        },
+        {
+          "bucket": "ci",
           "builder": "Dawn Mac x64 DEPS Release (Intel)",
           "project": "chromium"
         }
@@ -91,5 +126,6 @@
     ]
   },
   "builder_group": "tryserver.chromium.dawn",
-  "recipe": "chromium_trybot"
+  "recipe": "chromium_trybot",
+  "root_solution_revision": "refs/heads/main"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/dawn-win10-x64-deps-rel/properties.json b/infra/config/generated/builders/try/dawn-win10-x64-deps-rel/properties.json
index f9667a13..e01fa19 100644
--- a/infra/config/generated/builders/try/dawn-win10-x64-deps-rel/properties.json
+++ b/infra/config/generated/builders/try/dawn-win10-x64-deps-rel/properties.json
@@ -125,5 +125,6 @@
     ]
   },
   "builder_group": "tryserver.chromium.dawn",
-  "recipe": "chromium_trybot"
+  "recipe": "chromium_trybot",
+  "root_solution_revision": "refs/heads/main"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/dawn-win10-x86-deps-rel/properties.json b/infra/config/generated/builders/try/dawn-win10-x86-deps-rel/properties.json
index 2212218a..ede156c 100644
--- a/infra/config/generated/builders/try/dawn-win10-x86-deps-rel/properties.json
+++ b/infra/config/generated/builders/try/dawn-win10-x86-deps-rel/properties.json
@@ -125,5 +125,6 @@
     ]
   },
   "builder_group": "tryserver.chromium.dawn",
-  "recipe": "chromium_trybot"
+  "recipe": "chromium_trybot",
+  "root_solution_revision": "refs/heads/main"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/mac-dawn-rel/properties.json b/infra/config/generated/builders/try/mac-dawn-rel/properties.json
index ef2d7af5..c959fc65 100644
--- a/infra/config/generated/builders/try/mac-dawn-rel/properties.json
+++ b/infra/config/generated/builders/try/mac-dawn-rel/properties.json
@@ -34,6 +34,36 @@
           {
             "builder_id": {
               "bucket": "ci",
+              "builder": "Dawn Mac x64 Release (AMD)",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-dawn-archive",
+              "builder_group": "chromium.dawn",
+              "execution_mode": "TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium",
+                "target_bits": 64,
+                "target_platform": "mac"
+              },
+              "legacy_gclient_config": {
+                "config": "chromium"
+              },
+              "parent": {
+                "bucket": "ci",
+                "builder": "Dawn Mac x64 Builder",
+                "project": "chromium"
+              },
+              "run_tests_serially": true
+            }
+          },
+          {
+            "builder_id": {
+              "bucket": "ci",
               "builder": "Dawn Mac x64 Release (Intel)",
               "project": "chromium"
             },
@@ -73,6 +103,11 @@
       "builder_ids_in_scope_for_testing": [
         {
           "bucket": "ci",
+          "builder": "Dawn Mac x64 Release (AMD)",
+          "project": "chromium"
+        },
+        {
+          "bucket": "ci",
           "builder": "Dawn Mac x64 Release (Intel)",
           "project": "chromium"
         }
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 2784826..0e47ed59 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -55542,12 +55542,61 @@
         '        "builder": "android-12-x64-rel",'
         '        "project": "chromium"'
         '      }'
-        '    },'
+        '    }'
+        '  ]'
+        '}'
+      service_account: "reviver-builder@chops-service-accounts.iam.gserviceaccount.com"
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+    }
+    builders {
+      name: "android-x64-launcher"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "cores:8"
+      dimensions: "os:Ubuntu-18.04"
+      dimensions: "pool:luci.chromium.ci"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/main"
+        cmd: "luciexe"
+      }
+      properties:
+        '{'
+        '  "$recipe_engine/resultdb/test_presentation": {'
+        '    "column_keys": [],'
+        '    "grouping_keys": ['
+        '      "status",'
+        '      "v.test_suite"'
+        '    ]'
+        '  },'
+        '  "recipe": "chromium_polymorphic/launcher",'
+        '  "runner_builder": {'
+        '    "bucket": "reviver",'
+        '    "builder": "runner",'
+        '    "project": "chromium"'
+        '  },'
+        '  "target_builders": ['
         '    {'
         '      "builder_id": {'
         '        "bucket": "ci",'
-        '        "builder": "android-12l-x64-dbg-tests",'
+        '        "builder": "Android x64 Builder (dbg)",'
         '        "project": "chromium"'
+        '      },'
+        '      "dimensions": {'
+        '        "cpu": "x86-64",'
+        '        "os": "Ubuntu-18.04"'
+        '      },'
+        '      "tester_filter": {'
+        '        "testers": ['
+        '          {'
+        '            "builder": "android-12l-x64-dbg-tests",'
+        '            "group": "chromium.android"'
+        '          }'
+        '        ]'
         '      }'
         '    }'
         '  ]'
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index 4f1e161..9953ce68 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -18667,6 +18667,9 @@
     name: "buildbucket/luci.chromium.reviver/android-launcher"
   }
   builders {
+    name: "buildbucket/luci.chromium.reviver/android-x64-launcher"
+  }
+  builders {
     name: "buildbucket/luci.chromium.reviver/fuchsia-coordinator"
   }
   builders {
diff --git a/infra/config/generated/luci/luci-scheduler.cfg b/infra/config/generated/luci/luci-scheduler.cfg
index af0df91..fcc8d8e 100644
--- a/infra/config/generated/luci/luci-scheduler.cfg
+++ b/infra/config/generated/luci/luci-scheduler.cfg
@@ -3896,6 +3896,16 @@
   }
 }
 job {
+  id: "android-x64-launcher"
+  realm: "reviver"
+  schedule: "0 2,5,8,11,14 * * *"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "reviver"
+    builder: "android-x64-launcher"
+  }
+}
+job {
   id: "android-x86-code-coverage"
   realm: "ci"
   schedule: "triggered"
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star b/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star
index 8327dd5..7fe85dd6 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.dawn.star
@@ -7,6 +7,7 @@
 load("//lib/builders.star", "os", "reclient")
 load("//lib/consoles.star", "consoles")
 load("//lib/try.star", "try_")
+load("//project.star", "settings")
 
 try_.defaults.set(
     executable = try_.DEFAULT_EXECUTABLE,
@@ -35,6 +36,9 @@
         "ci/Dawn Android arm DEPS Release (Pixel 4)",
     ],
     main_list_view = "try",
+    properties = {
+        "root_solution_revision": settings.ref,
+    },
     test_presentation = resultdb.test_presentation(
         grouping_keys = ["status", "v.test_suite", "v.gpu"],
     ),
@@ -64,6 +68,9 @@
         "ci/Dawn Linux x64 DEPS Release (NVIDIA)",
     ],
     main_list_view = "try",
+    properties = {
+        "root_solution_revision": settings.ref,
+    },
     test_presentation = resultdb.test_presentation(
         grouping_keys = ["status", "v.test_suite", "v.gpu"],
     ),
@@ -89,12 +96,14 @@
     branch_selector = branches.selector.MAC_BRANCHES,
     mirrors = [
         "ci/Dawn Mac x64 DEPS Builder",
-        # Not enough capacity on Mac AMD https://crbug.com/1380184.
-        # "ci/Dawn Mac x64 DEPS Release (AMD)",
+        "ci/Dawn Mac x64 DEPS Release (AMD)",
         "ci/Dawn Mac x64 DEPS Release (Intel)",
     ],
     os = os.MAC_ANY,
     main_list_view = "try",
+    properties = {
+        "root_solution_revision": settings.ref,
+    },
     test_presentation = resultdb.test_presentation(
         grouping_keys = ["status", "v.test_suite", "v.gpu"],
     ),
@@ -125,6 +134,9 @@
     ],
     os = os.WINDOWS_ANY,
     main_list_view = "try",
+    properties = {
+        "root_solution_revision": settings.ref,
+    },
     test_presentation = resultdb.test_presentation(
         grouping_keys = ["status", "v.test_suite", "v.gpu"],
     ),
@@ -155,6 +167,9 @@
     ],
     os = os.WINDOWS_ANY,
     main_list_view = "try",
+    properties = {
+        "root_solution_revision": settings.ref,
+    },
     test_presentation = resultdb.test_presentation(
         grouping_keys = ["status", "v.test_suite", "v.gpu"],
     ),
@@ -201,8 +216,7 @@
     name = "mac-dawn-rel",
     mirrors = [
         "ci/Dawn Mac x64 Builder",
-        # Not enough capacity on Mac AMD https://crbug.com/1380184.
-        # "ci/Dawn Mac x64 Release (AMD)",
+        "ci/Dawn Mac x64 Release (AMD)",
         "ci/Dawn Mac x64 Release (Intel)",
     ],
     os = os.MAC_ANY,
diff --git a/infra/config/subprojects/reviver/reviver.star b/infra/config/subprojects/reviver/reviver.star
index df1bf77..77d719ee 100644
--- a/infra/config/subprojects/reviver/reviver.star
+++ b/infra/config/subprojects/reviver/reviver.star
@@ -55,7 +55,6 @@
         "ci/android-nougat-x86-rel",
         "ci/android-pie-x86-rel",
         "ci/android-12-x64-rel",
-        "ci/android-12l-x64-dbg-tests",
     ],
 )
 
@@ -72,6 +71,28 @@
 )
 
 polymorphic.launcher(
+    name = "android-x64-launcher",
+    # To avoid peak hours, we run it at 2 AM, 5 AM, 8 AM, 11AM, 2 PM UTC.
+    schedule = "0 2,5,8,11,14 * * *",
+    pool = ci.DEFAULT_POOL,
+    cores = 8,
+    os = os.LINUX_DEFAULT,
+    runner = "reviver/runner",
+    target_builders = [
+        polymorphic.target_builder(
+            builder = "ci/Android x64 Builder (dbg)",
+            dimensions = dimensions.dimensions(
+                os = os.LINUX_DEFAULT,
+                cpu = cpu.X86_64,
+            ),
+            testers = [
+                "ci/android-12l-x64-dbg-tests",
+            ],
+        ),
+    ],
+)
+
+polymorphic.launcher(
     name = "linux-launcher",
     # To avoid peak hours, we run it at 5~11 UTC, 21~27 PST.
     schedule = "0 5-11/3 * * *",
diff --git a/ios/chrome/app/strings/resources/ios_strings_bn.xtb b/ios/chrome/app/strings/resources/ios_strings_bn.xtb
index f8de922..a6156a8 100644
--- a/ios/chrome/app/strings/resources/ios_strings_bn.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_bn.xtb
@@ -321,6 +321,7 @@
 <translation id="3131206671572504478">সব ব্লক করুন</translation>
 <translation id="313283613037595347">নতুন ছদ্মবেশী ট্যাব তৈরি করুন।</translation>
 <translation id="3146109040683991651">Chrome-কে ডিফল্ট ব্রাউজার হিসেবে সেট করুন</translation>
+<translation id="3152169319860972623">পাসওয়ার্ড চেকআপ আপনার সেভ করা পাসওয়ার্ড পর্যালোচনা করে এবং যেকোনও অনলাইন লঙ্ঘন সম্পর্কে আপনাকে সতর্ক করে। <ph name="BEGIN_LINK" />আরও জানুন<ph name="END_LINK" />।</translation>
 <translation id="3153862085237805241">কার্ড সেভ করুন</translation>
 <translation id="3157387275655328056">পড়ার তালিকায় যোগ করুন</translation>
 <translation id="3157684681743766797">সবগুলি চিহ্নিত করুন…</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_da.xtb b/ios/chrome/app/strings/resources/ios_strings_da.xtb
index 8d8c22d..e1f99b96 100644
--- a/ios/chrome/app/strings/resources/ios_strings_da.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_da.xtb
@@ -131,7 +131,7 @@
 <translation id="1815941218935345331">Adgangskode</translation>
 <translation id="1820259098641718022">Føjet til læseliste</translation>
 <translation id="1829392566394960110">{COUNT,plural, =0{Kompromitterede adgangskoder}=1{{COUNT} kompromitteret adgangskode}one{{COUNT} kompromitteret adgangskode}other{{COUNT} kompromitterede adgangskoder}}</translation>
-<translation id="1832848789136765277">Bekræft din identitet for at sikre, at du altid har adgang til dine synkroniserede data</translation>
+<translation id="1832848789136765277">Verificer din identitet for at sikre, at du altid har adgang til dine synkroniserede data</translation>
 <translation id="1870148520156231997">Vis adgangskode</translation>
 <translation id="1872096359983322073">Lommelygte</translation>
 <translation id="1891796056033961979">Dine gemte bogmærker, adgangskoder, indstillinger og meget mere er tilgængelige via denne skærm.</translation>
@@ -897,7 +897,7 @@
 <translation id="6822587385560699678">Når denne indstilling er aktiveret, gemmes adgangskoder på <ph name="ACCOUNT" />. Når indstillingen er deaktiveret, gemmes adgangskoder kun på denne enhed.</translation>
 <translation id="683022620450280906">Du kan bruge gemte adgangskoder på alle enheder. De er gemt i Googles Adgangskodeadministrator for <ph name="EMAIL" /></translation>
 <translation id="6831043979455480757">Oversæt</translation>
-<translation id="6842136130964845393">Bekræft din identitet for at sikre, at du altid har adgang til dine gemte adgangskoder</translation>
+<translation id="6842136130964845393">Verificer din identitet for at sikre, at du altid har adgang til dine gemte adgangskoder</translation>
 <translation id="6851516051005285358">Vis computerversion</translation>
 <translation id="6852222216891664518">Luk fastgjort fane</translation>
 <translation id="6858855187367714033">Scannet</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_fa.xtb b/ios/chrome/app/strings/resources/ios_strings_fa.xtb
index d63c4a61..f6ae7b0 100644
--- a/ios/chrome/app/strings/resources/ios_strings_fa.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_fa.xtb
@@ -353,6 +353,7 @@
 <translation id="3324193307694657476">آدرس ۲</translation>
 <translation id="3328459813621383194">انتقال برگه‌های غیرفعال</translation>
 <translation id="3328801116991980348">اطلاعات سایت</translation>
+<translation id="3344485292736684439">{count,plural, =1{نشانک در «{title}» در حساب شما ({email}) ذخیره شد}one{نشانک در «{title}» در حساب شما ({email}) ذخیره شد}other{نشانک‌ها در «{title}» در حساب شما ({email}) ذخیره شد}}</translation>
 <translation id="3371831930909698441">‏«ترجمه Google» دردسترس است. گزینه‌ها در نزدیک پایین صفحه نمایش در دسترس هستند.</translation>
 <translation id="3377063233124932127">اکنون نشانک‌ها، گذرواژه‌ها، و دیگر موارد ذخیره‌شده در بالا نمایش داده می‌شوند.</translation>
 <translation id="3393920035788932672">پنجره‌های بازشو مجاز است</translation>
@@ -1032,6 +1033,7 @@
 <translation id="7840771868269352570">موارد انتخاب‌شده برداشته خواهد شد.</translation>
 <translation id="7845466610722898">نمایش فهرست خواندن</translation>
 <translation id="784551991304901159">برای دیدن محتوا، «روشن کردن» را از منو انتخاب کنید</translation>
+<translation id="7846158885638438868">{count,plural, =1{در «{title}» نشانک‌گذاری شد}one{در «{title}» نشانک‌گذاری شد}other{در «{title}» نشانک‌گذاری شد}}</translation>
 <translation id="7853202427316060426">فعالیت</translation>
 <translation id="7856733331829174190">بارگیری نشد</translation>
 <translation id="785938070103630874">گذرواژه‌ها، روش‌های پرداخت، نشانی‌ها، و دیگر موارد ذخیره‌شده را باز کنید</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_kn.xtb b/ios/chrome/app/strings/resources/ios_strings_kn.xtb
index 6536b3a..1dd8c9a 100644
--- a/ios/chrome/app/strings/resources/ios_strings_kn.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_kn.xtb
@@ -321,6 +321,7 @@
 <translation id="3131206671572504478">ಎಲ್ಲವನ್ನೂ ನಿರ್ಬಂಧಿಸಿ</translation>
 <translation id="313283613037595347">ಹೊಸ ಅಜ್ಞಾತ ಟ್ಯಾಬ್ ರಚಿಸಿ</translation>
 <translation id="3146109040683991651">Chrome ಅನ್ನು ಡೀಫಾಲ್ಟ್ ಬ್ರೌಸರ್ ಆಗಿ ಸೆಟ್ ಮಾಡಿ</translation>
+<translation id="3152169319860972623">ಪಾಸ್‌ವರ್ಡ್ ಪರೀಕ್ಷೆಯು ನಿಮ್ಮ ಉಳಿಸಿದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸುತ್ತದೆ ಮತ್ತು ಯಾವುದೇ ಆನ್‌ಲೈನ್ ಉಲ್ಲಂಘನೆಗಳ ಕುರಿತು ನಿಮಗೆ ಎಚ್ಚರಿಕೆ ನೀಡುತ್ತದೆ. <ph name="BEGIN_LINK" />ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ.<ph name="END_LINK" /></translation>
 <translation id="3153862085237805241">ಕಾರ್ಡ್‌ ಅನ್ನು ಉಳಿಸಿ</translation>
 <translation id="3157387275655328056">ಓದುವ ಪಟ್ಟಿಗೆ ಸೇರಿಸಿ</translation>
 <translation id="3157684681743766797">ಎಲ್ಲವನ್ನೂ ಗುರುತಿಸಿ…</translation>
@@ -353,6 +354,7 @@
 <translation id="3324193307694657476">ವಿಳಾಸ 2</translation>
 <translation id="3328459813621383194">ನಿಷ್ಕ್ರಿಯ ಟ್ಯಾಬ್‌ಗಳನ್ನು ಸರಿಸಿ</translation>
 <translation id="3328801116991980348">ಸೈಟ್ ಮಾಹಿತಿ</translation>
+<translation id="3344485292736684439">{count,plural, =1{ಬುಕ್‌ಮಾರ್ಕ್ ಅನ್ನು ನಿಮ್ಮ ಖಾತೆ {email} ನಲ್ಲಿ "{title}" ಎಂಬಲ್ಲಿ ಉಳಿಸಲಾಗಿದೆ}one{ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳನ್ನು ನಿಮ್ಮ ಖಾತೆ {email} ನಲ್ಲಿ "{title}" ಎಂಬಲ್ಲಿ ಉಳಿಸಲಾಗಿದೆ}other{ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳನ್ನು ನಿಮ್ಮ ಖಾತೆ {email} ನಲ್ಲಿ "{title}" ಎಂಬಲ್ಲಿ ಉಳಿಸಲಾಗಿದೆ}}</translation>
 <translation id="3371831930909698441">ಅನುವಾದ ಲಭ್ಯವಿದೆ. ಪರದೆಯ ಕೆಳಭಾಗದ ಸಮೀಪದಲ್ಲಿ ಆಯ್ಕೆಗಳು ಲಭ್ಯವಿವೆ.</translation>
 <translation id="3377063233124932127">ಇದೀಗ ನೀವು ಉಳಿಸಿದ ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳು, ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಹಾಗೂ ಇನ್ನಷ್ಟು ವಿಷಯಗಳು ಮೇಲ್ಭಾಗದಲ್ಲಿ ಇರುತ್ತವೆ.</translation>
 <translation id="3393920035788932672">ಪಾಪ್-ಅಪ್‌ಗಳನ್ನು ಅನುಮತಿಸಲಾಗಿದೆ</translation>
@@ -1032,6 +1034,7 @@
 <translation id="7840771868269352570">ನೀವು ಆಯ್ಕೆ ಮಾಡಿದ ಐಟಂಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ</translation>
 <translation id="7845466610722898">ಓದುವ ಪಟ್ಟಿಯನ್ನು ತೋರಿಸಿ</translation>
 <translation id="784551991304901159">ವಿಷಯವನ್ನು ನೋಡಲು, ಮೆನುವಿನಿಂದ 'ಆನ್ ಮಾಡಿ' ಆಯ್ಕೆಮಾಡಿ</translation>
+<translation id="7846158885638438868">{count,plural, =1{"{title}" ನಲ್ಲಿ ಬುಕ್‌ಮಾರ್ಕ್ ಮಾಡಲಾಗಿದೆ}one{"{title}" ನಲ್ಲಿ ಬುಕ್‌ಮಾರ್ಕ್ ಮಾಡಲಾಗಿದೆ}other{"{title}" ನಲ್ಲಿ ಬುಕ್‌ಮಾರ್ಕ್ ಮಾಡಲಾಗಿದೆ}}</translation>
 <translation id="7853202427316060426">ಚಟುವಟಿಕೆ</translation>
 <translation id="7856733331829174190">ಡೌನ್‌ಲೋಡ್‌ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ</translation>
 <translation id="785938070103630874">ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, ಪಾವತಿ ವಿಧಾನಗಳು ಅಥವಾ ವಿಳಾಸ ಮತ್ತು ಇನ್ನಷ್ಟನ್ನು ತೆರೆಯಿರಿ</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_lt.xtb b/ios/chrome/app/strings/resources/ios_strings_lt.xtb
index 6e0dcab..828209c9 100644
--- a/ios/chrome/app/strings/resources/ios_strings_lt.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_lt.xtb
@@ -353,6 +353,7 @@
 <translation id="3324193307694657476">2 adreso eil.</translation>
 <translation id="3328459813621383194">Neaktyvių skirtukų perkėlimas</translation>
 <translation id="3328801116991980348">Svetainės informacija</translation>
+<translation id="3344485292736684439">{count,plural, =1{Žymė išsaugota skiltyje „{title}“ jūsų paskyroje, {email}}one{Žymės išsaugotos skiltyje „{title}“ jūsų paskyroje, {email}}few{Žymės išsaugotos skiltyje „{title}“ jūsų paskyroje, {email}}many{Žymės išsaugotos skiltyje „{title}“ jūsų paskyroje, {email}}other{Žymės išsaugotos skiltyje „{title}“ jūsų paskyroje, {email}}}</translation>
 <translation id="3371831930909698441">Pasiekiamas vertimas. Parinktys pasiekiamos netoli ekrano apačios.</translation>
 <translation id="3377063233124932127">Dabar išsaugotos žymės, slaptažodžiai ir kt. yra viršuje.</translation>
 <translation id="3393920035788932672">Iššok. l. leidžiami</translation>
@@ -1032,6 +1033,7 @@
 <translation id="7840771868269352570">Pasirinkti elementai bus pašalinti.</translation>
 <translation id="7845466610722898">Rodyti skaitymo sąrašą</translation>
 <translation id="784551991304901159">Jei norite peržiūrėti turinį, meniu pasirinkite „Įjungti“</translation>
+<translation id="7846158885638438868">{count,plural, =1{Žymė išsaugota skiltyje „{title}“}one{Žymės išsaugotos skiltyje „{title}“}few{Žymės išsaugotos skiltyje „{title}“}many{Žymės išsaugotos skiltyje „{title}“}other{Žymės išsaugotos skiltyje „{title}“}}</translation>
 <translation id="7853202427316060426">Veikla</translation>
 <translation id="7856733331829174190">Nepavyko atsisiųsti</translation>
 <translation id="785938070103630874">Atidarykite slaptažodžius, mokėjimo metodus arba adresą ir kt.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_lv.xtb b/ios/chrome/app/strings/resources/ios_strings_lv.xtb
index a718258e..5f2f0c70 100644
--- a/ios/chrome/app/strings/resources/ios_strings_lv.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_lv.xtb
@@ -353,6 +353,7 @@
 <translation id="3324193307694657476">2. adrese</translation>
 <translation id="3328459813621383194">Neaktīvo cilņu pārvietošana</translation>
 <translation id="3328801116991980348">Vietnes informācija</translation>
+<translation id="3344485292736684439">{count,plural, =1{Grāmatzīme ir saglabāta mapē “{title}” jūsu kontā ({email}).}zero{Grāmatzīmes ir saglabātas mapē “{title}” jūsu kontā ({email}).}one{Grāmatzīmes ir saglabātas mapē “{title}” jūsu kontā ({email}).}other{Grāmatzīmes ir saglabātas mapē “{title}” jūsu kontā ({email}).}}</translation>
 <translation id="3371831930909698441">Ir pieejams tulkojums. Opcijas, kas pieejamas ekrāna apakšējā daļā.</translation>
 <translation id="3377063233124932127">Tagad jūsu saglabātās grāmatzīmes, paroles un citi dati atrodas augšdaļā.</translation>
 <translation id="3393920035788932672">Uznir. logi atļauti</translation>
@@ -1032,6 +1033,7 @@
 <translation id="7840771868269352570">Jūsu atlasītie vienumi tiks noņemti.</translation>
 <translation id="7845466610722898">Rādīt lasīšanas sarakstu</translation>
 <translation id="784551991304901159">Lai skatītu saturu, izvēlnē atlasiet vienumu Ieslēgt</translation>
+<translation id="7846158885638438868">{count,plural, =1{Grāmatzīme ir saglabāta mapē “{title}”.}zero{Grāmatzīmes ir saglabātas mapē “{title}”.}one{Grāmatzīmes ir saglabātas mapē “{title}”.}other{Grāmatzīmes ir saglabātas mapē “{title}”.}}</translation>
 <translation id="7853202427316060426">Aktivitāte</translation>
 <translation id="7856733331829174190">Lejupielāde neizdevās</translation>
 <translation id="785938070103630874">Atveriet sadaļu Paroles, Maksājumu veidi vai Adreses un citi dati.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_ml.xtb b/ios/chrome/app/strings/resources/ios_strings_ml.xtb
index 112fc59..bf7945b 100644
--- a/ios/chrome/app/strings/resources/ios_strings_ml.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_ml.xtb
@@ -321,6 +321,7 @@
 <translation id="3131206671572504478">എല്ലാം ബ്ലോക്ക് ചെയ്യുക</translation>
 <translation id="313283613037595347">പുതിയ അദൃശ്യ ടാബ് സൃഷ്‌ടിക്കുക.</translation>
 <translation id="3146109040683991651">ഡിഫോൾട്ട് ബ്രൗസറായി Chrome സജ്ജീകരിക്കുക</translation>
+<translation id="3152169319860972623">പാസ്‌വേഡ് പരിശോധന നിങ്ങളുടെ സംരക്ഷിച്ച പാസ്‌വേഡുകൾ അവലോകനം ചെയ്യുകയും ഓൺലൈൻ ലംഘനങ്ങളുണ്ടെങ്കിൽ അവയെക്കുറിച്ച് മുന്നറിയിപ്പ് നൽകുകയും ചെയ്യുന്നു. <ph name="BEGIN_LINK" />കൂടുതലറിയുക.<ph name="END_LINK" /></translation>
 <translation id="3153862085237805241">കാർഡ് സംരക്ഷിക്കുക</translation>
 <translation id="3157387275655328056">വായന ലിസ്റ്റിൽ ചേർക്കുക</translation>
 <translation id="3157684681743766797">എല്ലാം അടയാളപ്പെടുത്തുക…</translation>
@@ -353,6 +354,7 @@
 <translation id="3324193307694657476">വിലാസം 2</translation>
 <translation id="3328459813621383194">നിഷ്ക്രിയമായ ടാബുകൾ നീക്കുക</translation>
 <translation id="3328801116991980348">സൈറ്റ് വിവരങ്ങള്‍</translation>
+<translation id="3344485292736684439">{count,plural, =1{{email} എന്ന നിങ്ങളുടെ അക്കൗണ്ടിലെ "{title}" എന്നതിലേക്ക് ബുക്ക്‌മാർക്ക് സംരക്ഷിച്ചു}other{{email} എന്ന നിങ്ങളുടെ അക്കൗണ്ടിലെ "{title}" എന്നതിലേക്ക് ബുക്ക്‌മാർക്കുകൾ സംരക്ഷിച്ചു}}</translation>
 <translation id="3371831930909698441">വിവർത്തനം ലഭ്യമാണ്. സ്‌ക്രീനിൻ്റെ ചുവടെ ഓപ്‌ഷനുകൾ ലഭ്യമാണ്.</translation>
 <translation id="3377063233124932127">നിങ്ങളുടെ സംരക്ഷിച്ച ബുക്ക്‌മാർക്കുകളും പാസ്‌വേഡുകളും മറ്റും ഇപ്പോൾ മുകളിൽ കാണാം.</translation>
 <translation id="3393920035788932672">പോപ്പ്-അപ്പുകൾ അനുവദിച്ചു</translation>
@@ -1032,6 +1034,7 @@
 <translation id="7840771868269352570">നിങ്ങൾ തിരഞ്ഞെടുത്ത ഇനങ്ങൾ നീക്കം ചെയ്യപ്പെടും.</translation>
 <translation id="7845466610722898">വായിക്കാനുള്ളവയുടെ ലിസ്‌റ്റ് കാണിക്കുക</translation>
 <translation id="784551991304901159">ഉള്ളടക്കം കാണാൻ, മെനുവിൽ നിന്ന് 'ഓണാക്കുക' തിരഞ്ഞെടുക്കുക</translation>
+<translation id="7846158885638438868">{count,plural, =1{"{title}" എന്നതിലേക്ക് ബുക്ക്‌മാർക്ക് ചെയ്‌തു}other{"{title}" എന്നതിലേക്ക് ബുക്ക്‌മാർക്ക് ചെയ്‌തു}}</translation>
 <translation id="7853202427316060426">പ്രവർത്തനം</translation>
 <translation id="7856733331829174190">ഡൗൺലോഡ് ചെയ്യാനായില്ല</translation>
 <translation id="785938070103630874">പാസ്‌വേഡുകൾ, പേയ്മെന്റ് രീതികൾ, വിലാസം എന്നിവയും മറ്റും തുറക്കുക</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_ne.xtb b/ios/chrome/app/strings/resources/ios_strings_ne.xtb
index 642f048..14638ed 100644
--- a/ios/chrome/app/strings/resources/ios_strings_ne.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_ne.xtb
@@ -353,6 +353,7 @@
 <translation id="3324193307694657476">ठेगाना 2</translation>
 <translation id="3328459813621383194">निष्क्रिय ट्याबहरू सार्नुहोस्</translation>
 <translation id="3328801116991980348">साइट जानकारी</translation>
+<translation id="3344485292736684439">{count,plural, =1{यो बुकमार्क तपाईंको खाता ({email}) मा भएको "{title}" मा सेभ गरियो}other{यी बुकमार्कहरू तपाईंको खाता ({email}) मा भएको "{title}" मा सेभ गरिए}}</translation>
 <translation id="3371831930909698441">अनुवाद उपलब्ध छ। विकल्पहरू स्क्रिनका पुछारतिर उपलब्ध छन्।</translation>
 <translation id="3377063233124932127">अब तपाईंले सेभ गर्नुभएका बुकमार्क तथा पासवर्डलगायतका कुराहरू सिरानमा देखिन्छन्।</translation>
 <translation id="3393920035788932672">पप-अपहरूलाई अनुमति दिइयो</translation>
@@ -1032,6 +1033,7 @@
 <translation id="7840771868269352570">तपाईंले चयन गर्नुभएका वस्तुहरू हटाइने छन्।</translation>
 <translation id="7845466610722898">पछि पढ्न सेभ गरिएका वेबपेजको सूची देखाइयोस्</translation>
 <translation id="784551991304901159">तपाईं सामग्री हेर्न चाहनुहुन्छ भने मेनुबाट "अन गर्नुहोस्" चयन गर्नुहोस्</translation>
+<translation id="7846158885638438868">{count,plural, =1{"{title}" मा बुकमार्क गरियो}other{"{title}" मा बुकमार्क गरियो}}</translation>
 <translation id="7853202427316060426">गतिविधि</translation>
 <translation id="7856733331829174190">डाउनलोड गर्न सकिएन</translation>
 <translation id="785938070103630874">"पासवर्डहरू", "भुक्तानी विधिहरू" वा "ठेगाना र अन्य जानकारी" खोल्नुहोस्</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_nl.xtb b/ios/chrome/app/strings/resources/ios_strings_nl.xtb
index 34e572c1..175c030c 100644
--- a/ios/chrome/app/strings/resources/ios_strings_nl.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_nl.xtb
@@ -353,6 +353,7 @@
 <translation id="3324193307694657476">Adres 2</translation>
 <translation id="3328459813621383194">Inactieve tabbladen verplaatsen</translation>
 <translation id="3328801116991980348">Site-informatie</translation>
+<translation id="3344485292736684439">{count,plural, =1{Bookmark opgeslagen in {title} in je account {email}}other{Bookmarks opgeslagen in {title} in je account {email}}}</translation>
 <translation id="3371831930909698441">Vertalen is beschikbaar. Opties beschikbaar onderaan het scherm.</translation>
 <translation id="3377063233124932127">Je opgeslagen bookmarks, wachtwoorden enz. staan nu bovenaan.</translation>
 <translation id="3393920035788932672">Pop-ups toegestaan</translation>
@@ -1032,6 +1033,7 @@
 <translation id="7840771868269352570">De geselecteerde items worden verwijderd.</translation>
 <translation id="7845466610722898">Leeslijst tonen</translation>
 <translation id="784551991304901159">Als je content wilt zien, selecteer je Aanzetten in het menu</translation>
+<translation id="7846158885638438868">{count,plural, =1{Gebookmarkt in {title}}other{Gebookmarkt in {title}}}</translation>
 <translation id="7853202427316060426">Activiteit</translation>
 <translation id="7856733331829174190">Kan niet downloaden</translation>
 <translation id="785938070103630874">Open Wachtwoorden, Betaalmethoden of Adres en meer</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_te.xtb b/ios/chrome/app/strings/resources/ios_strings_te.xtb
index 780e19ac..6d672883 100644
--- a/ios/chrome/app/strings/resources/ios_strings_te.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_te.xtb
@@ -353,6 +353,7 @@
 <translation id="3324193307694657476">అడ్రస్‌ 2</translation>
 <translation id="3328459813621383194">ఇన్‌యాక్టివ్ ట్యాబ్‌లను తరలించండి</translation>
 <translation id="3328801116991980348">సైట్ సమాచారం</translation>
+<translation id="3344485292736684439">{count,plural, =1{బుక్‌మార్క్ మీ {email} ఖాతాలోని "{title}"‌లో సేవ్ అయ్యింది}other{బుక్‌మార్క్‌లు మీ {email} ఖాతాలోని "{title}"‌లో సేవ్ అయ్యాయి}}</translation>
 <translation id="3371831930909698441">అనువాదం అందుబాటులో ఉంది. స్క్రీన్ దిగువ భాగానికి సమీపంలో ఎంపికలు అందుబాటులో ఉంటాయి.</translation>
 <translation id="3377063233124932127">ఇప్పుడు మీరు సేవ్ చేసిన మీ బుక్‌మార్క్‌లు, పాస్‌వర్డ్‌లు, ఇంకా మరిన్ని పేజీ ఎగువున కనిపిస్తాయి.</translation>
 <translation id="3393920035788932672">పాప్-అప్‌లు అనుమతించబడ్డాయి</translation>
@@ -1032,6 +1033,7 @@
 <translation id="7840771868269352570">మీరు ఎంచుకున్న అంశాలు తీసివేయబడతాయి.</translation>
 <translation id="7845466610722898">చదవాల్సిన లిస్ట్‌ను చూడండి</translation>
 <translation id="784551991304901159">కంటెంట్‌ను చూడటానికి, మెనూ నుండి 'ఆన్ చేయండి'ని ఎంచుకోండి</translation>
+<translation id="7846158885638438868">{count,plural, =1{"{title}"‌లో బుక్‌మార్క్ అయ్యింది}other{"{title}"‌లో బుక్‌మార్క్ అయ్యింది}}</translation>
 <translation id="7853202427316060426">కార్యాచరణ</translation>
 <translation id="7856733331829174190">డౌన్‌లోడ్ సాధ్యపడలేదు</translation>
 <translation id="785938070103630874">పాస్‌వర్డ్‌లు, పేమెంట్ ఆప్షన్‌లు, లేదా అడ్రస్‌, ఇంకా మరిన్నింటిని తెరవండి</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_zu.xtb b/ios/chrome/app/strings/resources/ios_strings_zu.xtb
index 8cc6392..51be6eb3 100644
--- a/ios/chrome/app/strings/resources/ios_strings_zu.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_zu.xtb
@@ -321,6 +321,7 @@
 <translation id="3131206671572504478">Vimbela konke</translation>
 <translation id="313283613037595347">Dala ithebhu ye-incognito entsha.</translation>
 <translation id="3146109040683991651">Setha i-Chrome Njengebhrawuza Ezenzekalelayo</translation>
+<translation id="3152169319860972623">Ukuhlolwa Kwephasiwedi kubuyekeza amaphasiwedi akho alondoloziwe futhi kukuxwayise nganoma yikuphi ukwephulwa kwe-inthanethi. <ph name="BEGIN_LINK" />Funda kabanzi.<ph name="END_LINK" /></translation>
 <translation id="3153862085237805241">Londoloza ikhadi</translation>
 <translation id="3157387275655328056">Engeza kuhlu lokufunda</translation>
 <translation id="3157684681743766797">Maka konke...</translation>
diff --git a/ios/chrome/browser/autofill/BUILD.gn b/ios/chrome/browser/autofill/BUILD.gn
index 7ae441e5..ced7d18 100644
--- a/ios/chrome/browser/autofill/BUILD.gn
+++ b/ios/chrome/browser/autofill/BUILD.gn
@@ -56,6 +56,7 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/history",
     "//ios/chrome/browser/paths",
+    "//ios/chrome/browser/prefs:pref_names",
     "//ios/chrome/browser/shared/ui/util:util_swift",
     "//ios/chrome/browser/shared/ui/util/image",
     "//ios/chrome/browser/signin",
diff --git a/ios/chrome/browser/autofill/bottom_sheet/BUILD.gn b/ios/chrome/browser/autofill/bottom_sheet/BUILD.gn
index 9a7c16a8..4f28477 100644
--- a/ios/chrome/browser/autofill/bottom_sheet/BUILD.gn
+++ b/ios/chrome/browser/autofill/bottom_sheet/BUILD.gn
@@ -18,6 +18,9 @@
     "//components/autofill/core/common",
     "//components/autofill/ios/form_util",
     "//components/password_manager/core/common:features",
+    "//components/prefs",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/prefs:pref_names",
     "//ios/chrome/browser/shared/public/commands",
     "//ios/web/public",
     "//ios/web/public:web_state_observer",
diff --git a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.mm b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.mm
index af2cc222..ae021cf9 100644
--- a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.mm
+++ b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.mm
@@ -4,10 +4,8 @@
 
 #import "ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.h"
 
-#import "base/feature_list.h"
 #import "base/values.h"
 #import "components/autofill/core/common/password_form_fill_data.h"
-#import "components/password_manager/core/common/password_manager_features.h"
 #import "ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -56,17 +54,14 @@
 void BottomSheetJavaScriptFeature::AttachListeners(
     const std::vector<autofill::FieldRendererId>& renderer_ids,
     web::WebFrame* frame) {
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kIOSPasswordBottomSheet)) {
-    base::Value::List renderer_id_list =
-        base::Value::List::with_capacity(renderer_ids.size());
-    for (auto renderer_id : renderer_ids) {
-      renderer_id_list.Append(static_cast<int>(renderer_id.value()));
-    }
-    std::vector<base::Value> parameters;
-    parameters.push_back(base::Value(std::move(renderer_id_list)));
-    CallJavaScriptFunction(frame, "bottomSheet.attachListeners", parameters);
+  base::Value::List renderer_id_list =
+      base::Value::List::with_capacity(renderer_ids.size());
+  for (auto renderer_id : renderer_ids) {
+    renderer_id_list.Append(static_cast<int>(renderer_id.value()));
   }
+  std::vector<base::Value> parameters;
+  parameters.push_back(base::Value(std::move(renderer_id_list)));
+  CallJavaScriptFunction(frame, "bottomSheet.attachListeners", parameters);
 }
 
 void BottomSheetJavaScriptFeature::DetachListenersAndRefocus(
diff --git a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h
index 62b462f4..c2fb1c34 100644
--- a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h
+++ b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h
@@ -6,19 +6,18 @@
 #define IOS_CHROME_BROWSER_AUTOFILL_BOTTOM_SHEET_BOTTOM_SHEET_TAB_HELPER_H_
 
 #import "components/autofill/core/common/unique_ids.h"
-#import "ios/web/public/web_state_observer.h"
 #import "ios/web/public/web_state_user_data.h"
 
 namespace web {
 class ScriptMessage;
+class WebFrame;
 }  // namespace web
 
 @class CommandDispatcher;
 @protocol PasswordBottomSheetCommands;
 
 class BottomSheetTabHelper
-    : public web::WebStateObserver,
-      public web::WebStateUserData<BottomSheetTabHelper> {
+    : public web::WebStateUserData<BottomSheetTabHelper> {
  public:
   BottomSheetTabHelper(const BottomSheetTabHelper&) = delete;
   BottomSheetTabHelper& operator=(const BottomSheetTabHelper&) = delete;
@@ -44,11 +43,15 @@
 
   explicit BottomSheetTabHelper(web::WebState* web_state);
 
-  // web::WebStateObserver implementation.
-  void WebStateDestroyed(web::WebState* web_state) override;
+  // Check whether the password bottom sheet has been dismissed too many times
+  // by the user.
+  bool HasReachedDismissLimit();
 
   id<PasswordBottomSheetCommands> handler_;
 
+  // The WebState with which this object is associated.
+  web::WebState* const web_state_;
+
   WEB_STATE_USER_DATA_KEY_DECL();
 };
 
diff --git a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.mm b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.mm
index 65f0ad94..f7f1f48 100644
--- a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.mm
+++ b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.mm
@@ -4,8 +4,13 @@
 
 #import "ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h"
 
+#import "base/feature_list.h"
 #import "components/autofill/ios/form_util/form_activity_params.h"
+#import "components/password_manager/core/common/password_manager_features.h"
+#import "components/prefs/pref_service.h"
 #import "ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.h"
+#import "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/prefs/pref_names.h"
 #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
 #import "ios/chrome/browser/shared/public/commands/password_bottom_sheet_commands.h"
 #import "ios/web/public/js_messaging/script_message.h"
@@ -14,11 +19,16 @@
 #error "This file requires ARC support."
 #endif
 
+namespace {
+// The maximum number of times the password bottom sheet can be dismissed before
+// it gets disabled.
+constexpr int kIosPasswordBottomSheetMaxDismissCount = 3;
+}  // namespace
+
 BottomSheetTabHelper::~BottomSheetTabHelper() = default;
 
-BottomSheetTabHelper::BottomSheetTabHelper(web::WebState* web_state) {
-  web_state->AddObserver(this);
-}
+BottomSheetTabHelper::BottomSheetTabHelper(web::WebState* web_state)
+    : web_state_(web_state) {}
 
 // Public methods
 
@@ -38,19 +48,32 @@
 void BottomSheetTabHelper::AttachListeners(
     const std::vector<autofill::FieldRendererId>& renderer_ids,
     web::WebFrame* frame) {
-  BottomSheetJavaScriptFeature::GetInstance()->AttachListeners(renderer_ids,
-                                                               frame);
+  // Verify that the password bottom sheet feature is enabled.
+  if (!base::FeatureList::IsEnabled(
+          password_manager::features::kIOSPasswordBottomSheet)) {
+    return;
+  }
+
+  // Verify that the password bottom sheet hasn't been dismissed too many times.
+  if (!HasReachedDismissLimit()) {
+    // Enable the password bottom sheet.
+    BottomSheetJavaScriptFeature::GetInstance()->AttachListeners(renderer_ids,
+                                                                 frame);
+  }
 }
 
 void BottomSheetTabHelper::DetachListenersAndRefocus(web::WebFrame* frame) {
   BottomSheetJavaScriptFeature::GetInstance()->DetachListenersAndRefocus(frame);
 }
 
-// WebStateObserver
+// Private methods
 
-void BottomSheetTabHelper::WebStateDestroyed(web::WebState* web_state) {
-  web_state->RemoveObserver(this);
-  handler_ = nil;
+bool BottomSheetTabHelper::HasReachedDismissLimit() {
+  PrefService* const pref_service =
+      ChromeBrowserState ::FromBrowserState(web_state_->GetBrowserState())
+          ->GetPrefs();
+  return pref_service->GetInteger(prefs::kIosPasswordBottomSheetDismissCount) >
+         kIosPasswordBottomSheetMaxDismissCount;
 }
 
 WEB_STATE_USER_DATA_KEY_IMPL(BottomSheetTabHelper)
diff --git a/ios/chrome/browser/autofill/form_suggestion_controller.mm b/ios/chrome/browser/autofill/form_suggestion_controller.mm
index 510fe7d..9423ac3 100644
--- a/ios/chrome/browser/autofill/form_suggestion_controller.mm
+++ b/ios/chrome/browser/autofill/form_suggestion_controller.mm
@@ -14,8 +14,11 @@
 #import "components/autofill/ios/browser/form_suggestion.h"
 #import "components/autofill/ios/browser/form_suggestion_provider.h"
 #import "components/autofill/ios/form_util/form_activity_params.h"
+#import "components/prefs/pref_service.h"
 #import "ios/chrome/browser/autofill/form_input_navigator.h"
 #import "ios/chrome/browser/autofill/form_input_suggestions_provider.h"
+#import "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/prefs/pref_names.h"
 #import "ios/web/common/url_scheme_util.h"
 #import "ios/web/public/js_messaging/web_frames_manager.h"
 #import "ios/web/public/ui/crw_web_view_proxy.h"
@@ -317,6 +320,10 @@
 }
 
 - (void)didSelectSuggestion:(FormSuggestion*)suggestion {
+  // If a suggestion was selected, reset the password bottom sheet dismiss count
+  // to 0.
+  [self resetPasswordBottomSheetDismissCount];
+
   if (!_suggestionState)
     return;
 
@@ -365,4 +372,18 @@
                    : autofill::PopupType::kUnspecified;
 }
 
+#pragma mark - Private
+
+// Resets the password bottom sheet dismiss count to 0.
+- (void)resetPasswordBottomSheetDismissCount {
+  ChromeBrowserState* browserState =
+      _webState
+          ? ChromeBrowserState::FromBrowserState(_webState->GetBrowserState())
+          : nullptr;
+  if (browserState) {
+    browserState->GetPrefs()->SetInteger(
+        prefs::kIosPasswordBottomSheetDismissCount, 0);
+  }
+}
+
 @end
diff --git a/ios/chrome/browser/default_browser/BUILD.gn b/ios/chrome/browser/default_browser/BUILD.gn
index 6959dec..461b03c 100644
--- a/ios/chrome/browser/default_browser/BUILD.gn
+++ b/ios/chrome/browser/default_browser/BUILD.gn
@@ -18,6 +18,7 @@
     "//components/sync/driver",
     "//ios/chrome/browser/application_context",
     "//ios/chrome/browser/feature_engagement",
+    "//ios/chrome/browser/ntp:features",
     "//ios/chrome/browser/settings/sync/utils:identity_error_util",
     "//ios/chrome/browser/shared/public/features",
   ]
diff --git a/ios/chrome/browser/default_browser/utils.mm b/ios/chrome/browser/default_browser/utils.mm
index 0df9faf..5e2f0ee 100644
--- a/ios/chrome/browser/default_browser/utils.mm
+++ b/ios/chrome/browser/default_browser/utils.mm
@@ -16,6 +16,7 @@
 #import "components/sync/driver/sync_service.h"
 #import "ios/chrome/browser/application_context/application_context.h"
 #import "ios/chrome/browser/feature_engagement/tracker_factory.h"
+#import "ios/chrome/browser/ntp/features.h"
 #import "ios/chrome/browser/settings/sync/utils/identity_error_util.h"
 #import "ios/chrome/browser/shared/public/features/features.h"
 
@@ -132,7 +133,8 @@
     base::Days(7);
 
 // Maximum time representing one user session.
-constexpr base::TimeDelta kMaximumTimeOneUserSession = base::Hours(6);
+const base::TimeDelta kMaximumTimeOneUserSession =
+    base::Seconds(GetFeedUnseenRefreshThresholdInSeconds());
 
 // Maximum time range between valid user URL pastes to notify the FET.
 constexpr base::TimeDelta kMaximumTimeBetweenValidURLPastes = base::Days(7);
diff --git a/ios/chrome/browser/flags/BUILD.gn b/ios/chrome/browser/flags/BUILD.gn
index a5121b6..da5340c 100644
--- a/ios/chrome/browser/flags/BUILD.gn
+++ b/ios/chrome/browser/flags/BUILD.gn
@@ -70,7 +70,6 @@
     "//ios/chrome/browser/promos_manager:features",
     "//ios/chrome/browser/screen_time:buildflags",
     "//ios/chrome/browser/shared/public/features",
-    "//ios/chrome/browser/snapshots:features",
     "//ios/chrome/browser/tabs:features",
     "//ios/chrome/browser/tabs/inactive_tabs:features",
     "//ios/chrome/browser/text_selection:text_selection_utils",
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index c64e343..bc04dd4 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -84,7 +84,6 @@
 #import "ios/chrome/browser/promos_manager/features.h"
 #import "ios/chrome/browser/screen_time/screen_time_buildflags.h"
 #import "ios/chrome/browser/shared/public/features/features.h"
-#import "ios/chrome/browser/snapshots/features.h"
 #import "ios/chrome/browser/tabs/features.h"
 #import "ios/chrome/browser/tabs/inactive_tabs/features.h"
 #import "ios/chrome/browser/text_selection/text_selection_util.h"
@@ -92,7 +91,6 @@
 #import "ios/chrome/browser/ui/autofill/features.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h"
 #import "ios/chrome/browser/ui/download/features.h"
-#import "ios/chrome/browser/ui/first_run/trending_queries_field_trial.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_feature.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_retention_field_trial_constants.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_ui_features.h"
@@ -349,19 +347,6 @@
      std::size(kStartSurfaceOneHourHideShortcutsReturnToRecentTab), nullptr},
 };
 
-const FeatureEntry::FeatureParam kModuleRefreshMinimizeSpacing[] = {
-    {kContentSuggestionsUIModuleRefreshMinimizeSpacingParam, "true"}};
-const FeatureEntry::FeatureParam kModuleRefreshNoHeaders[] = {
-    {kContentSuggestionsUIModuleRefreshMinimizeSpacingParam, "true"},
-    {kContentSuggestionsUIModuleRefreshRemoveHeadersParam, "true"}};
-
-const FeatureEntry::FeatureVariation kModuleRefreshVariations[] = {
-    {"Enabled with minimized spacing", kModuleRefreshMinimizeSpacing,
-     std::size(kModuleRefreshMinimizeSpacing), nullptr},
-    {"Enabled with no headers and minimized spacing", kModuleRefreshNoHeaders,
-     std::size(kModuleRefreshNoHeaders), nullptr},
-};
-
 #if BUILDFLAG(IOS_BACKGROUND_MODE_ENABLED)
 // Feed Background Refresh Feature Params.
 const FeatureEntry::FeatureParam kOneHourIntervalOneHourMaxAgeOnce[] = {
@@ -453,25 +438,6 @@
          std::size(kFeedAppCloseBackgroundRefresh), nullptr},
 };
 
-const FeatureEntry::FeatureParam kTrendingQueriesEnableAllUsers[] = {
-    {kTrendingQueriesHideShortcutsParam, "false"}};
-const FeatureEntry::FeatureParam kTrendingQueriesEnableAllUsersHideShortcuts[] =
-    {{kTrendingQueriesHideShortcutsParam, "true"}};
-const FeatureEntry::FeatureParam kTrendingQueriesEnableFeedDisabled[] = {
-    {kTrendingQueriesHideShortcutsParam, "false"},
-    {kTrendingQueriesDisabledFeedParam, "true"},
-};
-
-const FeatureEntry::FeatureVariation kTrendingQueriesModuleVariations[] = {
-    {"Enabled All Users", kTrendingQueriesEnableAllUsers,
-     std::size(kTrendingQueriesEnableAllUsers), nullptr},
-    {"Enabled All Users Hide Shortcuts",
-     kTrendingQueriesEnableAllUsersHideShortcuts,
-     std::size(kTrendingQueriesEnableAllUsersHideShortcuts), nullptr},
-    {"Enabled Disabled Feed", kTrendingQueriesEnableFeedDisabled,
-     std::size(kTrendingQueriesEnableFeedDisabled), nullptr},
-};
-
 const FeatureEntry::FeatureParam kDmTokenDeletionParam[] = {{"forced", "true"}};
 const FeatureEntry::FeatureVariation kDmTokenDeletionVariation[] = {
     {"(Forced)", kDmTokenDeletionParam, std::size(kDmTokenDeletionParam),
@@ -1121,14 +1087,6 @@
     {"content-suggestions-magic-stack", flag_descriptions::kMagicStackName,
      flag_descriptions::kMagicStackDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kMagicStack)},
-    {"content-suggestions-ui-module-refresh",
-     flag_descriptions::kContentSuggestionsUIModuleRefreshName,
-     flag_descriptions::kContentSuggestionsUIModuleRefreshDescription,
-     flags_ui::kOsIos,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(
-         kContentSuggestionsUIModuleRefresh,
-         kModuleRefreshVariations,
-         kContentSuggestionsUIModuleRefreshFlagOverrideFieldTrialName)},
     {"default-browser-intents-show-settings",
      flag_descriptions::kDefaultBrowserIntentsShowSettingsName,
      flag_descriptions::kDefaultBrowserIntentsShowSettingsDescription,
@@ -1163,12 +1121,6 @@
      flag_descriptions::kAdaptiveSuggestionsCountName,
      flag_descriptions::kAdaptiveSuggestionsCountDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(omnibox::kAdaptiveSuggestionsCount)},
-    {"trending-queries-module", flag_descriptions::kTrendingQueriesModuleName,
-     flag_descriptions::kTrendingQueriesModuleDescription, flags_ui::kOsIos,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(
-         kTrendingQueriesModule,
-         kTrendingQueriesModuleVariations,
-         kTrendingQueriesFlagOverrideFieldTrialName)},
     {"autofill-parse-iban-fields",
      flag_descriptions::kAutofillParseIBANFieldsName,
      flag_descriptions::kAutofillParseIBANFieldsDescription, flags_ui::kOsIos,
@@ -1519,9 +1471,6 @@
      flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(reading_list::switches::
                             kReadingListEnableSyncTransportModeUponSignIn)},
-    {"fix-pdf-snapshot", flag_descriptions::kPDFSnapshotName,
-     flag_descriptions::kPDFSnapshotDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(kPDFSnapshot)},
     {"omnibox-grouping-framework-zps",
      flag_descriptions::kOmniboxGroupingFrameworkForZPSName,
      flag_descriptions::kOmniboxGroupingFrameworkForZPSDescription,
@@ -1554,6 +1503,10 @@
     {"omnibox-tail-suggest", flag_descriptions::kOmniboxTailSuggestName,
      flag_descriptions::kOmniboxTailSuggestDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kOmniboxTailSuggest)},
+    {"feed-disable-hot-start-refresh-ios",
+     flag_descriptions::kFeedDisableHotStartRefreshName,
+     flag_descriptions::kFeedDisableHotStartRefreshDescription,
+     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kFeedDisableHotStartRefresh)},
 };
 
 bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index 1c41f9d..990f3b16 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -192,11 +192,6 @@
     "When enabled, one tapping or long pressing on an email address will "
     "trigger the email experience.";
 
-extern const char kPDFSnapshotName[] =
-    "Fix PDF snapshot by using a different API";
-extern const char kPDFSnapshotDescription[] =
-    "When enabled, the tab showing PDF should have the correct thumbnail.";
-
 extern const char kPhoneNumberName[] = "Phone number experience enable";
 extern const char kPhoneNumberDescription[] =
     "When enabled, one tapping or long pressing on a phone number will trigger "
@@ -233,12 +228,6 @@
 extern const char kLongPressSurroundingTextDescription[] =
     "When enabled, long pressing a text will analyze larger part of the text.";
 
-const char kContentSuggestionsUIModuleRefreshName[] =
-    "Content Suggestions UI Module Refresh";
-const char kContentSuggestionsUIModuleRefreshDescription[] =
-    "When enabled, the Content Suggestions will be redesigned to be contained "
-    "into distinct modules.";
-
 const char kCredentialProviderExtensionPromoName[] =
     "Enable the Credential Provider Extension promo.";
 const char kCredentialProviderExtensionPromoDescription[] =
@@ -462,6 +451,10 @@
     "Schedules a feed background refresh after some minimum period of time has "
     "passed after the last refresh.";
 
+const char kFeedDisableHotStartRefreshName[] = "Disable hot start feed refresh";
+const char kFeedDisableHotStartRefreshDescription[] =
+    "Disables all Discover-controlled foregrounding refreshes.";
+
 const char kFeedExperimentTaggingName[] = "Enable Feed experiment tagging";
 const char kFeedExperimentTaggingDescription[] =
     "Makes server experiments visible as client-side experiments.";
@@ -1006,10 +999,6 @@
     "When enabled, the toolbars and their fullscreen animations will be "
     "managed by the toolbar container coordinator rather than BVC.";
 
-extern const char kTrendingQueriesModuleName[] = "Show Trending Queries module";
-extern const char kTrendingQueriesModuleDescription[] =
-    "When enabled, the trending queries module will be shown in the NTP";
-
 const char kUseLensToSearchForImageName[] =
     "Use Google Lens to Search for images";
 const char kUseLensToSearchForImageDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index c484b44..23fff0e 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -163,10 +163,6 @@
 extern const char kEmailName[];
 extern const char kEmailDescription[];
 
-// Title and description for the flag to fix the PDF snapshot.
-extern const char kPDFSnapshotName[];
-extern const char kPDFSnapshotDescription[];
-
 // Title and description for the flag to enable phone numbers detection and
 // processing.
 extern const char kPhoneNumberName[];
@@ -194,11 +190,6 @@
 extern const char kMapsExperienceKitName[];
 extern const char kMapsExperienceKitDescription[];
 
-// Title and description for the flag that updates the Content Suggestions to a
-// new module design.
-extern const char kContentSuggestionsUIModuleRefreshName[];
-extern const char kContentSuggestionsUIModuleRefreshDescription[];
-
 // Title and description for the flag to enable the Credential
 // Provider Extension promo.
 extern const char kCredentialProviderExtensionPromoName[];
@@ -395,6 +386,11 @@
 extern const char kFeedBackgroundRefreshName[];
 extern const char kFeedBackgroundRefreshDescription[];
 
+// Title and description for the flag to disable Discover-controlled
+// foregrounding refresh.
+extern const char kFeedDisableHotStartRefreshName[];
+extern const char kFeedDisableHotStartRefreshDescription[];
+
 // Title and description for the flag to enable feed experiment tagging.
 extern const char kFeedExperimentTaggingName[];
 extern const char kFeedExperimentTaggingDescription[];
@@ -882,10 +878,6 @@
 extern const char kToolbarContainerName[];
 extern const char kToolbarContainerDescription[];
 
-// Title and Description for the flag to enable the trending queries module.
-extern const char kTrendingQueriesModuleName[];
-extern const char kTrendingQueriesModuleDescription[];
-
 // Title and description for the flag to enable using Lens to search for an
 // image from the long press context menu.
 extern const char kUseLensToSearchForImageName[];
diff --git a/ios/chrome/browser/ntp/features.h b/ios/chrome/browser/ntp/features.h
index 7cf5eee..2da56fe 100644
--- a/ios/chrome/browser/ntp/features.h
+++ b/ios/chrome/browser/ntp/features.h
@@ -53,6 +53,9 @@
 // Feature flag to enable the Set Up List.
 BASE_DECLARE_FEATURE(kIOSSetUpList);
 
+// Feature flag to disable Discover-controlled foregrounding refreshes.
+BASE_DECLARE_FEATURE(kFeedDisableHotStartRefresh);
+
 // Feature param under `kEnableFeedBackgroundRefresh` to also enable background
 // refresh for the Following feed.
 extern const char kEnableFollowingFeedBackgroundRefresh[];
@@ -235,4 +238,7 @@
 // Whether the Set Up List feature is enabled.
 bool IsIOSSetUpListEnabled();
 
+// Whether Discover-controlled foregrounding refreshes are disabled.
+bool IsFeedHotStartRefreshDisabled();
+
 #endif  // IOS_CHROME_BROWSER_NTP_FEATURES_H_
diff --git a/ios/chrome/browser/ntp/features.mm b/ios/chrome/browser/ntp/features.mm
index f041b47..1d2485f 100644
--- a/ios/chrome/browser/ntp/features.mm
+++ b/ios/chrome/browser/ntp/features.mm
@@ -80,6 +80,10 @@
 
 BASE_FEATURE(kIOSSetUpList, "IOSSetUpList", base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kFeedDisableHotStartRefresh,
+             "FeedDisableHotStartRefresh",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Key for NSUserDefaults containing a bool indicating whether the next run
 // should enable feed background refresh capability. This is used because
 // registering for background refreshes must happen early in app initialization
@@ -345,3 +349,7 @@
 bool IsIOSSetUpListEnabled() {
   return base::FeatureList::IsEnabled(kIOSSetUpList);
 }
+
+bool IsFeedHotStartRefreshDisabled() {
+  return base::FeatureList::IsEnabled(kFeedDisableHotStartRefresh);
+}
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm
index dd437d19..cb3fa09 100644
--- a/ios/chrome/browser/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -73,7 +73,6 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_mediator.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_path_cache.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h"
-#import "ios/chrome/browser/ui/first_run/trending_queries_field_trial.h"
 #import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_retention_field_trial.h"
 #import "ios/chrome/browser/ui/ntp/synced_segments_field_trial.h"
@@ -124,6 +123,9 @@
 // Deprecated 01/2023.
 const char* kTrialGroupMICeAndDefaultBrowserVersionPrefName =
     "fre_refactoring_mice_and_default_browser.trial_version";
+
+// Deprecated 04/2023.
+const char kTrialPrefName[] = "trending_queries.trial_version";
 }  // namespace
 
 void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
@@ -139,7 +141,6 @@
   sessions::SessionIdGenerator::RegisterPrefs(registry);
   update_client::RegisterPrefs(registry);
   variations::VariationsService::RegisterPrefs(registry);
-  trending_queries_field_trial::RegisterLocalStatePrefs(registry);
   new_tab_page_retention_field_trial::RegisterLocalStatePrefs(registry);
   synced_segments_field_trial::RegisterLocalStatePrefs(registry);
   component_updater::RegisterComponentUpdateServicePrefs(registry);
@@ -374,6 +375,10 @@
   // Register pref used to determine if the Price Tracking UI has been shown.
   registry->RegisterBooleanPref(prefs::kPriceNotificationsHasBeenShown, false);
 
+  // Register pref used to count the number of consecutive times the password
+  // bottom sheet has been dismissed.
+  registry->RegisterIntegerPref(prefs::kIosPasswordBottomSheetDismissCount, 0);
+
   // Register pref used to determine if Browser Lockdown Mode is enabled.
   registry->RegisterBooleanPref(prefs::kBrowserLockdownModeEnabled, false);
 
@@ -402,6 +407,11 @@
 
   // Added 01/2023
   prefs->ClearPref(kTrialGroupMICeAndDefaultBrowserVersionPrefName);
+
+  // Added 04/2023
+  if (prefs->FindPreference(kTrialPrefName)) {
+    prefs->ClearPref(kTrialPrefName);
+  }
 }
 
 // This method should be periodically pruned of year+ old migrations.
diff --git a/ios/chrome/browser/prefs/pref_names.cc b/ios/chrome/browser/prefs/pref_names.cc
index c68c9905d..063e886 100644
--- a/ios/chrome/browser/prefs/pref_names.cc
+++ b/ios/chrome/browser/prefs/pref_names.cc
@@ -129,6 +129,12 @@
 const char kIosDiscoverFeedLastUnseenRefreshTime[] =
     "ios.discover_feed.last_unseen_refresh_time";
 
+// The number of consecutive times the user dismissed the password bottom sheet.
+// This gets reset to 0 whenever the user selects a password from the bottom
+// sheet or from the keyboard accessory.
+const char kIosPasswordBottomSheetDismissCount[] =
+    "ios.password_bottom_sheet_dismiss_count";
+
 // The user's account info from before a device restore.
 const char kIosPreRestoreAccountInfo[] = "ios.pre_restore_account_info";
 
diff --git a/ios/chrome/browser/prefs/pref_names.h b/ios/chrome/browser/prefs/pref_names.h
index 1e7c30a8..3d5554dd 100644
--- a/ios/chrome/browser/prefs/pref_names.h
+++ b/ios/chrome/browser/prefs/pref_names.h
@@ -39,6 +39,7 @@
 extern const char kIosShareChromeLastShare[];
 extern const char kIosDiscoverFeedLastRefreshTime[];
 extern const char kIosDiscoverFeedLastUnseenRefreshTime[];
+extern const char kIosPasswordBottomSheetDismissCount[];
 extern const char kIosPreRestoreAccountInfo[];
 extern const char kIosPromosManagerActivePromos[];
 extern const char kIosPromosManagerImpressions[];
diff --git a/ios/chrome/browser/snapshots/BUILD.gn b/ios/chrome/browser/snapshots/BUILD.gn
index 8d3f3678..6ffdf91a 100644
--- a/ios/chrome/browser/snapshots/BUILD.gn
+++ b/ios/chrome/browser/snapshots/BUILD.gn
@@ -25,7 +25,6 @@
     "snapshots_util.mm",
   ]
   deps = [
-    ":features",
     "//base",
     "//base/ios",
     "//ios/chrome/browser/browser_state",
@@ -87,12 +86,3 @@
     "//ui/gfx",
   ]
 }
-
-source_set("features") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  sources = [
-    "features.h",
-    "features.mm",
-  ]
-  deps = [ "//base" ]
-}
diff --git a/ios/chrome/browser/snapshots/features.h b/ios/chrome/browser/snapshots/features.h
deleted file mode 100644
index f42b05c..0000000
--- a/ios/chrome/browser/snapshots/features.h
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_SNAPSHOTS_FEATURES_H_
-#define IOS_CHROME_BROWSER_SNAPSHOTS_FEATURES_H_
-
-#include "base/feature_list.h"
-
-// Fix the PDF snapshot issue (crbug.com/1425444).
-BASE_DECLARE_FEATURE(kPDFSnapshot);
-
-#endif  // IOS_CHROME_BROWSER_SNAPSHOTS_FEATURES_H_
diff --git a/ios/chrome/browser/snapshots/features.mm b/ios/chrome/browser/snapshots/features.mm
deleted file mode 100644
index 5cd0ede..0000000
--- a/ios/chrome/browser/snapshots/features.mm
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/snapshots/features.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-BASE_FEATURE(kPDFSnapshot, "FixPDFSnapshot", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/ios/chrome/browser/snapshots/snapshot_cache.mm b/ios/chrome/browser/snapshots/snapshot_cache.mm
index e0f5ec0c..7abb4c7 100644
--- a/ios/chrome/browser/snapshots/snapshot_cache.mm
+++ b/ios/chrome/browser/snapshots/snapshot_cache.mm
@@ -27,7 +27,6 @@
 #import "base/threading/scoped_blocking_call.h"
 #import "base/time/time.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
-#import "ios/chrome/browser/snapshots/features.h"
 #import "ios/chrome/browser/snapshots/snapshot_cache_observer.h"
 #import "ios/chrome/browser/snapshots/snapshot_lru_cache.h"
 #import "ios/chrome/browser/tabs/features.h"
@@ -181,7 +180,7 @@
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                 base::BlockingType::WILL_BLOCK);
   NSData* data = UIImageJPEGRepresentation(image, kJPEGImageQuality);
-  if (!data && base::FeatureList::IsEnabled(kPDFSnapshot)) {
+  if (!data) {
     // Use UIImagePNGRepresentation instead when ImageJPEGRepresentation returns
     // nil. It happens when the underlying CGImageRef contains data in an
     // unsupported bitmap format.
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
index f2d8077..d2f5c1c 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/content_suggestions/cells/BUILD.gn
@@ -5,8 +5,6 @@
 source_set("cells") {
   sources = [
     "content_suggestions_gesture_commands.h",
-    "content_suggestions_module_container.h",
-    "content_suggestions_module_container.mm",
     "content_suggestions_most_visited_action_item.h",
     "content_suggestions_most_visited_action_item.mm",
     "content_suggestions_most_visited_constants.h",
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cells_constants.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cells_constants.mm
index db0cdf5a..51a71851 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cells_constants.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cells_constants.mm
@@ -11,11 +11,7 @@
 #endif
 
 CGFloat ReturnToRecentTabHeight() {
-  if (ShouldMinimizeSpacingForModuleRefresh()) {
-    return 64;
-  } else {
-    return kReturnToRecentTabSize.height;
-  }
+  return kReturnToRecentTabSize.height;
 }
 
 const CGSize kReturnToRecentTabSize = {/*width=*/343, /*height=*/72};
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_module_container.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_module_container.h
deleted file mode 100644
index 86111f1..0000000
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_module_container.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MODULE_CONTAINER_H_
-#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MODULE_CONTAINER_H_
-
-#import <UIKit/UIKit.h>
-
-#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h"
-
-// Container View for a module in the Content Suggestions.
-@interface ContentSuggestionsModuleContainer : UIView
-
-// Initializes the view with a `contentView` content that is showing the Content
-// Suggestions `type`.
-- (instancetype)initWithContentView:(UIView*)contentView
-                         moduleType:(ContentSuggestionsModuleType)type;
-
-- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
-- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
-
-// If YES, the module will show a placeholder UI.
-@property(nonatomic, assign) BOOL isPlaceholder;
-
-// Returns the intrisic height for the entire module, including its content.
-- (CGFloat)calculateIntrinsicHeight;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MODULE_CONTAINER_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_module_container.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_module_container.mm
deleted file mode 100644
index ed523d0..0000000
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_module_container.mm
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_module_container.h"
-
-#import "ios/chrome/browser/shared/ui/util/image/image_util.h"
-#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cells_constants.h"
-#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_layout_util.h"
-#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h"
-#import "ios/chrome/common/ui/colors/semantic_color_names.h"
-#import "ios/chrome/common/ui/util/constraints_ui_util.h"
-#import "ios/chrome/grit/ios_strings.h"
-#import "ui/base/l10n/l10n_util_mac.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-// The horizontal inset of the contents to this container when there is a title.
-const float kContentHorizontalInset = 16.0f;
-
-// The vertical spacing between the title and the content of the module.
-const float kContentTitleVerticalSpacing = 12.0f;
-const float kContentTitleShortenedVerticalSpacing = 10.0f;
-
-// The top inset of the title label to this container.
-const float kTitleTopInset = 14.0f;
-const float kTitleShortenedTopInset = 11.0f;
-
-// The minimum width of the title label.
-const float kTitleMinimumWidth = 99.0f;
-
-// The minimum height of the title label.
-const float kTitleMinimumHeight = 11.0f;
-
-// The corner radius of the title placeholder view.
-const float kPlaceholderTitleCornerRadius = 2.0f;
-
-// The corner radius of this container.
-const float kCornerRadius = 16;
-
-// The shadow radius of this container.
-const float kShadowRadius = 5;
-
-// The shadow opacity of this container.
-const float kShadowOpacity = 0.06;
-
-// The vertical offset of the shadow.
-const float kShadowOffsetY = 3.0f;
-
-// Vertical space allocated to the Trending Queries module content.
-const float kTrendingQueriesContentHeight = 103;
-
-}  // namespace
-
-@interface ContentSuggestionsModuleContainer ()
-
-@property(nonatomic, assign) ContentSuggestionsModuleType type;
-
-// Title of the Module.
-@property(nonatomic, strong) UILabel* title;
-
-// The height constraint of this container view.
-@property(nonatomic, strong) NSLayoutConstraint* heightConstraint;
-
-@end
-
-@implementation ContentSuggestionsModuleContainer
-
-- (instancetype)initWithContentView:(UIView*)contentView
-                         moduleType:(ContentSuggestionsModuleType)type {
-  self = [super initWithFrame:CGRectZero];
-  if (self) {
-    _type = type;
-
-    self.layer.cornerRadius = kCornerRadius;
-    self.backgroundColor =
-        [UIColor colorNamed:kGroupedSecondaryBackgroundColor];
-
-    self.layer.shadowColor = [UIColor blackColor].CGColor;
-    self.layer.shadowRadius = kShadowRadius;
-    self.layer.shadowOpacity = kShadowOpacity;
-    self.layer.shadowOffset = CGSizeMake(0, kShadowOffsetY);
-    // Render shadow as bitmap to improve snapshot render layout performance.
-    self.layer.shouldRasterize = YES;
-    self.layer.rasterizationScale = UIScreen.mainScreen.scale;
-
-    contentView.translatesAutoresizingMaskIntoConstraints = NO;
-    [self addSubview:contentView];
-
-    NSString* titleString = [self titleString];
-    if ([titleString length] > 0) {
-      self.title = [[UILabel alloc] init];
-      self.title.text = [self titleString];
-      self.title.font =
-          [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
-      self.title.textColor = [UIColor colorNamed:kTextSecondaryColor];
-      self.title.accessibilityTraits |= UIAccessibilityTraitHeader;
-      self.title.accessibilityIdentifier = [self titleString];
-      self.title.translatesAutoresizingMaskIntoConstraints = NO;
-      [self addSubview:self.title];
-      [NSLayoutConstraint activateConstraints:@[
-        // Title constraints.
-        [self.title.leadingAnchor
-            constraintEqualToAnchor:self.leadingAnchor
-                           constant:kContentHorizontalInset],
-        [self.topAnchor constraintEqualToAnchor:self.title.topAnchor
-                                       constant:-[self titleTopInset]],
-        // Ensures placeholder for title is visible.
-        [self.title.widthAnchor
-            constraintGreaterThanOrEqualToConstant:kTitleMinimumWidth],
-        [self.title.heightAnchor
-            constraintGreaterThanOrEqualToConstant:kTitleMinimumHeight],
-        // contentView constraints.
-        [contentView.leadingAnchor
-            constraintEqualToAnchor:self.leadingAnchor
-                           constant:kContentHorizontalInset],
-        [contentView.trailingAnchor
-            constraintEqualToAnchor:self.trailingAnchor
-                           constant:-kContentHorizontalInset],
-        [contentView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
-        [contentView.topAnchor constraintEqualToAnchor:self.title.bottomAnchor
-                                              constant:[self titleSpacing]],
-      ]];
-    } else {
-      CGFloat horizontalInsets =
-          (ShouldRemoveHeadersForModuleRefresh() &&
-           self.type != ContentSuggestionsModuleTypeReturnToRecentTab)
-              ? kContentHorizontalInset
-              : 0;
-      [NSLayoutConstraint activateConstraints:@[
-        [contentView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor
-                                                  constant:horizontalInsets],
-        [contentView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor
-                                                   constant:-horizontalInsets],
-        [contentView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
-        [contentView.topAnchor constraintEqualToAnchor:self.topAnchor
-                                              constant:[self titleTopInset]],
-      ]];
-    }
-    // Height constraint must be flexible since on launch before the Feed
-    // CollectionView is used a native UICollectionView is the parent, and it
-    // can attempt to apply a large height constraint to the
-    // ContentSuggestionsViewController.
-    self.heightConstraint = [self.heightAnchor
-        constraintGreaterThanOrEqualToConstant:[self calculateIntrinsicHeight]];
-    self.heightConstraint.active = YES;
-  }
-  return self;
-}
-
-// Returns the title string for the module, empty string if there should be no
-// title.
-- (NSString*)titleString {
-  switch (self.type) {
-    case ContentSuggestionsModuleTypeShortcuts:
-      return ShouldRemoveHeadersForModuleRefresh()
-                 ? @""
-                 : l10n_util::GetNSString(
-                       IDS_IOS_CONTENT_SUGGESTIONS_SHORTCUTS_MODULE_TITLE);
-    case ContentSuggestionsModuleTypeMostVisited:
-      return ShouldRemoveHeadersForModuleRefresh()
-                 ? @""
-                 : l10n_util::GetNSString(
-                       IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_TITLE);
-    case ContentSuggestionsModuleTypeReturnToRecentTab:
-      return @"";
-    case ContentSuggestionsModuleTypeTrendingQueries:
-      return l10n_util::GetNSString(
-          IDS_IOS_CONTENT_SUGGESTIONS_TRENDING_QUERIES_MODULE_TITLE);
-  }
-}
-
-- (void)setIsPlaceholder:(BOOL)isPlaceholder {
-  if (_isPlaceholder == isPlaceholder) {
-    return;
-  }
-  if (isPlaceholder) {
-    self.title.text = @"";
-    self.title.backgroundColor = [UIColor colorNamed:kGrey100Color];
-    self.title.layer.cornerRadius = kPlaceholderTitleCornerRadius;
-    self.title.layer.masksToBounds = YES;
-  } else {
-    self.title.backgroundColor = [UIColor colorNamed:kBackgroundColor];
-    self.title.layer.masksToBounds = NO;
-    self.title.text = [self titleString];
-  }
-  _isPlaceholder = isPlaceholder;
-}
-
-- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
-  [super traitCollectionDidChange:previousTraitCollection];
-  if (previousTraitCollection.preferredContentSizeCategory !=
-      self.traitCollection.preferredContentSizeCategory) {
-    self.title.font =
-        [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
-    self.heightConstraint.constant = [self calculateIntrinsicHeight];
-  }
-}
-
-- (CGFloat)calculateIntrinsicHeight {
-  CGFloat contentHeight = 0;
-  switch (self.type) {
-    case ContentSuggestionsModuleTypeShortcuts:
-    case ContentSuggestionsModuleTypeMostVisited:
-      // Add 3px of addition spacing so that a 2-line caption has some bottom
-      // spacing.
-      // TODO(crbug.com/1361569): Only add spacing if at least one tile is
-      // multi-line.
-      contentHeight +=
-          MostVisitedCellSize(self.traitCollection.preferredContentSizeCategory)
-              .height +
-          3;
-      break;
-    case ContentSuggestionsModuleTypeReturnToRecentTab:
-      return ReturnToRecentTabHeight();
-    case ContentSuggestionsModuleTypeTrendingQueries:
-      contentHeight += kTrendingQueriesContentHeight;
-  }
-  if (!ShouldRemoveHeadersForModuleRefresh() ||
-      self.type == ContentSuggestionsModuleTypeTrendingQueries) {
-    contentHeight += ceilf(self.title.font.lineHeight);
-  }
-  return [self titleSpacing] + [self titleTopInset] + contentHeight;
-}
-
-// Returns the spacing between the module edge and title. Also used to return
-// the spacing between the contents and the module edge if
-// ShouldRemoveHeadersForModuleRefresh() is YES where there are no headers for
-// modules.
-- (CGFloat)titleTopInset {
-  if (self.type == ContentSuggestionsModuleTypeReturnToRecentTab) {
-    return 0;
-  }
-  if (ShouldRemoveHeadersForModuleRefresh() ||
-      ShouldMinimizeSpacingForModuleRefresh()) {
-    return kTitleShortenedTopInset;
-  }
-  return kTitleTopInset;
-}
-
-// Returns the spacing between the module and title and the content.
-- (CGFloat)titleSpacing {
-  // Order matters here since if there is no title shown, then there cannot be a
-  // need for spacing between the title and module contents.
-  if (ShouldRemoveHeadersForModuleRefresh() &&
-      self.type != ContentSuggestionsModuleTypeTrendingQueries) {
-    return 0;
-  }
-  if (ShouldMinimizeSpacingForModuleRefresh()) {
-    return kContentTitleShortenedVerticalSpacing;
-  }
-  return kContentTitleVerticalSpacing;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_view.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_view.mm
index 9dcc6362..ec77b5e 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_view.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_view.mm
@@ -28,12 +28,8 @@
 - (instancetype)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
   if (self) {
-    if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-      [self.layer setBorderColor:ntp_home::NTPBackgroundColor().CGColor];
-    } else {
-      [self.layer
-          setBorderColor:[UIColor colorNamed:kTertiaryBackgroundColor].CGColor];
-    }
+    [self.layer
+        setBorderColor:[UIColor colorNamed:kTertiaryBackgroundColor].CGColor];
     [self.layer setBorderWidth:kContentViewBorderWidth];
     self.layer.cornerRadius = kContentViewCornerRadius;
     self.layer.masksToBounds = YES;
@@ -120,12 +116,8 @@
   if (self.traitCollection.userInterfaceStyle !=
       previousTraitCollection.userInterfaceStyle) {
     // CGColors are static RGB, so the border color needs to be reset.
-    if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-      [self.layer setBorderColor:ntp_home::NTPBackgroundColor().CGColor];
-    } else {
-      [self.layer
-          setBorderColor:[UIColor colorNamed:kTertiaryBackgroundColor].CGColor];
-    }
+    [self.layer
+        setBorderColor:[UIColor colorNamed:kTertiaryBackgroundColor].CGColor];
   }
 }
 
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_view.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_view.mm
index 0ee45b7..2d21350 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_view.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_tile_view.mm
@@ -22,10 +22,6 @@
 const CGFloat kIconSize = 56;
 // Standard width of tiles.
 const CGFloat kPreferredMaxWidth = 74;
-// Non-standard width of tiles. (Used only when the Content Suggestions UI
-// Module Refresh feature is enabled.)
-const CGFloat kModulePreferredMaxWidth = 74;
-const CGFloat kModulePreferredMaxWidthWide = 83;
 
 }  // namespace
 
@@ -44,19 +40,7 @@
     _titleLabel.textColor = [UIColor colorNamed:kTextSecondaryColor];
     _titleLabel.font = [self titleLabelFont];
     _titleLabel.textAlignment = NSTextAlignmentCenter;
-
-    if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-      // Since modules are given more horizontal space on iPad, allow for more
-      // estimated width for the label to calculate content size.
-      CGFloat modulePreferredWidth = self.traitCollection.horizontalSizeClass ==
-                                             UIUserInterfaceSizeClassRegular
-                                         ? kModulePreferredMaxWidthWide
-                                         : kModulePreferredMaxWidth;
-
-      _titleLabel.preferredMaxLayoutWidth = modulePreferredWidth;
-    } else {
-      _titleLabel.preferredMaxLayoutWidth = kPreferredMaxWidth;
-    }
+    _titleLabel.preferredMaxLayoutWidth = kPreferredMaxWidth;
 
     _titleLabel.numberOfLines = kLabelNumLines;
     _imageContainerView = [[UIView alloc] init];
@@ -86,21 +70,10 @@
     AddSameCenterConstraints(_imageContainerView, backgroundView);
     UIView* containerView = backgroundView;
 
-    if (IsContentSuggestionsUIModuleRefreshEnabled() && isPlaceholder) {
-      ApplyVisualConstraintsWithMetrics(
-          @[ @"V:|[container]-(space)-[title]-(>=0)-|" ],
-          @{@"container" : containerView, @"title" : _titleLabel},
-          @{@"space" : @(kSpaceIconTitle)});
-      [NSLayoutConstraint activateConstraints:@[
-        [_titleLabel.widthAnchor constraintEqualToConstant:kIconSize],
-        [_titleLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
-      ]];
-    } else {
-      ApplyVisualConstraintsWithMetrics(
-          @[ @"V:|[container]-(space)-[title]|", @"H:|[title]|" ],
-          @{@"container" : containerView, @"title" : _titleLabel},
-          @{@"space" : @(kSpaceIconTitle)});
-    }
+    ApplyVisualConstraintsWithMetrics(
+        @[ @"V:|[container]-(space)-[title]|", @"H:|[title]|" ],
+        @{@"container" : containerView, @"title" : _titleLabel},
+        @{@"space" : @(kSpaceIconTitle)});
 
     _imageBackgroundView = backgroundView;
 
@@ -117,14 +90,10 @@
 
 // Returns the font size for the location label.
 - (UIFont*)titleLabelFont {
-  if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-    return [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1];
-  } else {
-    return PreferredFontForTextStyleWithMaxCategory(
-        UIFontTextStyleCaption1,
-        self.traitCollection.preferredContentSizeCategory,
-        UIContentSizeCategoryAccessibilityLarge);
-  }
+  return PreferredFontForTextStyleWithMaxCategory(
+      UIFontTextStyleCaption1,
+      self.traitCollection.preferredContentSizeCategory,
+      UIContentSizeCategoryAccessibilityLarge);
 }
 
 #pragma mark - UIView
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h
index 9362f01..a05f675 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h
@@ -17,9 +17,6 @@
 // Handles the actions tapping the "Return to Recent Tab" item that returns the
 // user to the last opened tab.
 - (void)openMostRecentTab;
-// Handles the actions following a tap on a trending query.
-- (void)loadSuggestedQuery:(QuerySuggestionConfig*)config;
-
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_consumer.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_consumer.h
index e1b8a28c..32dba17 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_consumer.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_consumer.h
@@ -37,10 +37,6 @@
 - (void)setShortcutTilesWithConfigs:
     (NSArray<ContentSuggestionsMostVisitedActionItem*>*)configs;
 
-// Indicates to the consumer the current Trending Queries to show with
-// `configs`.
-- (void)setTrendingQueriesWithConfigs:(NSArray<QuerySuggestionConfig*>*)configs;
-
 // Indicates to the consumer that the given `config` has updated data.
 - (void)updateShortcutTileConfig:
     (ContentSuggestionsMostVisitedActionItem*)config;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h
index 5489122..7a3867d6 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h
@@ -7,15 +7,6 @@
 
 #include "base/feature_list.h"
 
-// Store local state preference with whether the client has participated in
-// kModularHomeTrendingQueriesClientSideFieldTrialName experiment or not.
-extern const char kTrialPrefName[];
-
-// The current trial version of
-// kModularHomeTrendingQueriesClientSideFieldTrialName; should be updated when
-// the experiment is modified.
-extern const int kCurrentTrialVersion;
-
 // Feature to choose between the old Zine feed or the new Discover feed in the
 // Bling new tab page.
 // Use IsDiscoverFeedEnabled() instead of this constant directly.
@@ -25,39 +16,9 @@
 // Feature to use one NTP for all tabs in a Browser.
 BASE_DECLARE_FEATURE(kSingleNtp);
 
-// Feature to section the Content Suggestions into modules.
-BASE_DECLARE_FEATURE(kContentSuggestionsUIModuleRefresh);
-// Feature version of kContentSuggestionsUIModuleRefresh used for client-side
-// study.
-BASE_DECLARE_FEATURE(kContentSuggestionsUIModuleRefreshNewUser);
-
 // Feature for the Magic Stack.
 BASE_DECLARE_FEATURE(kMagicStack);
 
-// Name of the field trial for when kContentSuggestionsUIModuleRefresh is
-// enabled in about_flags.
-extern const char
-    kContentSuggestionsUIModuleRefreshFlagOverrideFieldTrialName[];
-
-// Feature params for kContentSuggestionsUIModuleRefresh.
-extern const char kContentSuggestionsUIModuleRefreshMinimizeSpacingParam[];
-extern const char kContentSuggestionsUIModuleRefreshRemoveHeadersParam[];
-
-// Feature to show the Trending Queries module.
-BASE_DECLARE_FEATURE(kTrendingQueriesModule);
-// Feature version of kTrendingQueriesModule used for client-side study.
-BASE_DECLARE_FEATURE(kTrendingQueriesModuleNewUser);
-
-// Feature params for kTrendingQueriesModule.
-extern const char kTrendingQueriesHideShortcutsParam[];
-extern const char kTrendingQueriesDisabledFeedParam[];
-
-// Name of the Modular Home + Trending Queries Client-side Field Trial.
-extern const char kModularHomeTrendingQueriesClientSideFieldTrialName[];
-
-// Name of the Trending Queries flag override field trial.
-extern const char kTrendingQueriesFlagOverrideFieldTrialName[];
-
 // A parameter to indicate whether the native UI is enabled for the discover
 // feed.
 // TODO(crbug.com/1385512): Remove this.
@@ -67,29 +28,7 @@
 // TODO(crbug.com/1385512): Remove this.
 bool IsDiscoverFeedEnabled();
 
-// Whether the Content Suggestions UI Module Refresh feature is enabled.
-bool IsContentSuggestionsUIModuleRefreshEnabled();
-
-// Whether some spacing should be removed for the Content Suggestions UI Module
-// Refresh feature.
-bool ShouldMinimizeSpacingForModuleRefresh();
-
-// Whether the module header should not be shown for the Content Suggestions UI
-// Module Refresh feature.
-bool ShouldRemoveHeadersForModuleRefresh();
-
 // Whether the Magic Stack should be shown.
 bool IsMagicStackEnabled();
 
-// Whether the Trending Queries module feature is enabled.
-bool IsTrendingQueriesModuleEnabled();
-
-// Whether the shorctus should be hidden while showing the Trending Queries
-// module.
-bool ShouldHideShortcutsForTrendingQueries();
-
-// Whether the Trending Queries module should only be shown to users who had the
-// feed disabled.
-bool ShouldOnlyShowTrendingQueriesForDisabledFeed();
-
 #endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_FEATURE_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.mm
index 0f4dc0f0..1bb4a51 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.mm
@@ -13,16 +13,6 @@
 #error "This file requires ARC support."
 #endif
 
-const char kTrialPrefName[] = "trending_queries.trial_version";
-
-// Update this if the experiment configuration is fundamentally changing. This
-// will mean clients in the study will fall out of the client-side FieldTrial
-// and be open to enabling the features based on the server-side config.
-// Otherwise, the existing groups should simply be marked (not renamed) as
-// postperiod, their params updated to default values, and new groups be created
-// for any followup experimentation.
-const int kCurrentTrialVersion = 3;
-
 // Feature disabled by default to keep showing old Zine feed.
 BASE_FEATURE(kDiscoverFeedInNtp,
              "DiscoverFeedInNtp",
@@ -32,41 +22,8 @@
 BASE_FEATURE(kSingleNtp, "SingleNTP", base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Feature disabled by default.
-BASE_FEATURE(kContentSuggestionsUIModuleRefresh,
-             "ContentSuggestionsUIModuleRefresh",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-BASE_FEATURE(kContentSuggestionsUIModuleRefreshNewUser,
-             "ContentSuggestionsUIModuleRefreshNewUser",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
-// Feature disabled by default.
 BASE_FEATURE(kMagicStack, "MagicStack", base::FEATURE_DISABLED_BY_DEFAULT);
 
-const char kContentSuggestionsUIModuleRefreshFlagOverrideFieldTrialName[] =
-    "ContentSuggestionsUIModuleRefreshFlagOverrideFieldTria";
-
-const char kContentSuggestionsUIModuleRefreshMinimizeSpacingParam[] =
-    "minimize_spacing";
-const char kContentSuggestionsUIModuleRefreshRemoveHeadersParam[] =
-    "remove_headers";
-
-// Feature disabled by default.
-BASE_FEATURE(kTrendingQueriesModule,
-             "TrendingQueriesModule",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-BASE_FEATURE(kTrendingQueriesModuleNewUser,
-             "TrendingQueriesModuleNewUser",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
-const char kTrendingQueriesHideShortcutsParam[] = "hide_shortcuts";
-const char kTrendingQueriesDisabledFeedParam[] = "disabled_feed_only";
-
-const char kModularHomeTrendingQueriesClientSideFieldTrialName[] =
-    "ModularHomeTrendingQueriesNewUsers";
-
-const char kTrendingQueriesFlagOverrideFieldTrialName[] =
-    "TrendingQueriesFlagOverride";
-
 // A parameter to indicate whether the native UI is enabled for the discover
 // feed.
 const char kDiscoverFeedIsNativeUIEnabled[] = "DiscoverFeedIsNativeUIEnabled";
@@ -75,121 +32,6 @@
   return base::FeatureList::IsEnabled(kDiscoverFeedInNtp);
 }
 
-// Returns true if the client is bucketed into an enabled experiment group of
-// the current active FieldTrial of
-// kModularHomeTrendingQueriesClientSideFieldTrialName.
-// This allows for the code to capture the state of the FieldTrial for new
-// clients that should be sticky and take precedence over the parallel studies
-// that may be coming from the server-side config meant for existing clients,
-// who then won't report being in those studies. If kCurrentTrialVersion gets
-// updates and a client has a previous version, then it will then be open to
-// enabling features based on the server-side config.
-bool IsClientInCurrentModularHomeTrendingQueryStudy() {
-  return GetApplicationContext()->GetLocalState()->GetInteger(kTrialPrefName) ==
-         kCurrentTrialVersion;
-}
-
-bool IsContentSuggestionsUIModuleRefreshEnabled() {
-  // If the feature has been overriden in chrome://flags, ensure the correct
-  // feature is checked (e.g. not the one used for the client-side FieldTrial).
-  if (base::FieldTrialList::TrialExists(
-          kContentSuggestionsUIModuleRefreshFlagOverrideFieldTrialName)) {
-    return base::FeatureList::IsEnabled(kContentSuggestionsUIModuleRefresh);
-  }
-  if (IsClientInCurrentModularHomeTrendingQueryStudy()) {
-    return base::FeatureList::IsEnabled(
-        kContentSuggestionsUIModuleRefreshNewUser);
-  }
-  return base::FeatureList::IsEnabled(kContentSuggestionsUIModuleRefresh);
-}
-
 bool IsMagicStackEnabled() {
   return base::FeatureList::IsEnabled(kMagicStack);
 }
-
-bool IsTrendingQueriesModuleEnabled() {
-  // If the feature has been overriden in chrome://flags, ensure the correct
-  // feature is checked (e.g. not the one used for the client-side FieldTrial).
-  if (base::FieldTrialList::TrialExists(
-          kTrendingQueriesFlagOverrideFieldTrialName)) {
-    return base::FeatureList::IsEnabled(kContentSuggestionsUIModuleRefresh) &&
-           base::FeatureList::IsEnabled(kTrendingQueriesModule);
-  }
-  // If client is registered in the client-side FieldTrial, check its unique
-  // base::Feature for enabled state.
-  if (IsClientInCurrentModularHomeTrendingQueryStudy()) {
-    return base::FeatureList::IsEnabled(
-               kContentSuggestionsUIModuleRefreshNewUser) &&
-           base::FeatureList::IsEnabled(kTrendingQueriesModuleNewUser);
-  }
-  return base::FeatureList::IsEnabled(kContentSuggestionsUIModuleRefresh) &&
-         base::FeatureList::IsEnabled(kTrendingQueriesModule);
-}
-
-bool ShouldMinimizeSpacingForModuleRefresh() {
-  // If the feature has been overriden in chrome://flags, ensure the correct
-  // feature is checked (e.g. not the one used for the client-side FieldTrial).
-  if (base::FieldTrialList::TrialExists(
-          kContentSuggestionsUIModuleRefreshFlagOverrideFieldTrialName)) {
-    return base::GetFieldTrialParamByFeatureAsBool(
-        kContentSuggestionsUIModuleRefresh,
-        kContentSuggestionsUIModuleRefreshMinimizeSpacingParam, false);
-  }
-  // If client is registered in the client-side FieldTrial, check its unique
-  // base::Feature for enabled state.
-  if (IsClientInCurrentModularHomeTrendingQueryStudy()) {
-    return base::GetFieldTrialParamByFeatureAsBool(
-        kContentSuggestionsUIModuleRefreshNewUser,
-        kContentSuggestionsUIModuleRefreshMinimizeSpacingParam, false);
-  }
-  return base::GetFieldTrialParamByFeatureAsBool(
-      kContentSuggestionsUIModuleRefresh,
-      kContentSuggestionsUIModuleRefreshMinimizeSpacingParam, false);
-}
-
-bool ShouldRemoveHeadersForModuleRefresh() {
-  // If the feature has been overriden in chrome://flags, ensure the correct
-  // feature is checked (e.g. not the one used for the client-side FieldTrial).
-  if (base::FieldTrialList::TrialExists(
-          kContentSuggestionsUIModuleRefreshFlagOverrideFieldTrialName)) {
-    return base::GetFieldTrialParamByFeatureAsBool(
-        kContentSuggestionsUIModuleRefresh,
-        kContentSuggestionsUIModuleRefreshRemoveHeadersParam, false);
-  }
-  // If client is registered in the client-side FieldTrial, check its unique
-  // base::Feature for enabled state.
-  if (IsClientInCurrentModularHomeTrendingQueryStudy()) {
-    return base::GetFieldTrialParamByFeatureAsBool(
-        kContentSuggestionsUIModuleRefreshNewUser,
-        kContentSuggestionsUIModuleRefreshRemoveHeadersParam, false);
-  }
-  return base::GetFieldTrialParamByFeatureAsBool(
-      kContentSuggestionsUIModuleRefresh,
-      kContentSuggestionsUIModuleRefreshRemoveHeadersParam, false);
-}
-
-bool ShouldHideShortcutsForTrendingQueries() {
-  // If the feature has been overriden in chrome://flags, ensure the correct
-  // feature is checked (e.g. not the one used for the client-side FieldTrial).
-  if (base::FieldTrialList::TrialExists(
-          kTrendingQueriesFlagOverrideFieldTrialName)) {
-    return base::GetFieldTrialParamByFeatureAsBool(
-        kTrendingQueriesModule, kTrendingQueriesHideShortcutsParam, false);
-  }
-  // If client is registered in the client-side FieldTrial, check its unique
-  // base::Feature for enabled state.
-  if (IsClientInCurrentModularHomeTrendingQueryStudy()) {
-    return base::GetFieldTrialParamByFeatureAsBool(
-        kTrendingQueriesModuleNewUser, kTrendingQueriesHideShortcutsParam,
-        false);
-  }
-  return base::GetFieldTrialParamByFeatureAsBool(
-      kTrendingQueriesModule, kTrendingQueriesHideShortcutsParam, false);
-}
-
-bool ShouldOnlyShowTrendingQueriesForDisabledFeed() {
-  // This param is not used in the client-side FieldTrial, so no need to make
-  // checks since chrome://flags and server-side config use same Feature name.
-  return base::GetFieldTrialParamByFeatureAsBool(
-      kTrendingQueriesModule, kTrendingQueriesDisabledFeedParam, false);
-}
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm
index a4d9504..67df2f7f 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm
@@ -174,9 +174,7 @@
       [[ToolbarButtonFactory alloc] initWithStyle:NORMAL];
   self.fakeToolbar = [[UIView alloc] init];
   self.fakeToolbar.backgroundColor =
-      IsContentSuggestionsUIModuleRefreshEnabled()
-          ? [UIColor clearColor]
-          : buttonFactory.toolbarConfiguration.backgroundColor;
+      buttonFactory.toolbarConfiguration.backgroundColor;
   [searchField insertSubview:self.fakeToolbar atIndex:0];
   self.fakeToolbar.translatesAutoresizingMaskIntoConstraints = NO;
 
@@ -186,9 +184,7 @@
   // Omnibox, used for animations.
   // TODO(crbug.com/936811): See if it is possible to share some initialization
   // code with the real Omnibox.
-  UIColor* color = IsContentSuggestionsUIModuleRefreshEnabled()
-                       ? [UIColor colorNamed:kGrey700Color]
-                       : [UIColor colorNamed:kTextfieldPlaceholderColor];
+  UIColor* color = [UIColor colorNamed:kTextfieldPlaceholderColor];
   OmniboxContainerView* omnibox =
       [[OmniboxContainerView alloc] initWithFrame:CGRectZero
                                         textColor:color
@@ -390,13 +386,6 @@
     percent = base::clamp<CGFloat>(
         animatingOffset / ntp_header::kAnimationDistance, 0, 1);
   }
-  if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-    // Update background color of fake toolbar if stuck to top of NTP so that it
-    // has a non-clear background. Otherwise, return to clear background.
-    self.fakeToolbar.backgroundColor =
-        percent == 1.0f ? [UIColor colorNamed:kBackgroundColor]
-                        : [UIColor clearColor];
-  }
   return percent;
 }
 
@@ -567,21 +556,8 @@
     _fakeLocationBar.userInteractionEnabled = NO;
     _fakeLocationBar.clipsToBounds = YES;
     _fakeLocationBar.backgroundColor =
-        IsContentSuggestionsUIModuleRefreshEnabled()
-            ? [UIColor clearColor]
-            : [UIColor colorNamed:kTextfieldBackgroundColor];
+        [UIColor colorNamed:kTextfieldBackgroundColor];
     _fakeLocationBar.translatesAutoresizingMaskIntoConstraints = NO;
-    if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-      GradientView* gradientView = [[GradientView alloc]
-          initWithTopColor:[UIColor
-                               colorNamed:@"fake_omnibox_top_gradient_color"]
-               bottomColor:
-                   [UIColor colorNamed:@"fake_omnibox_bottom_gradient_color"]];
-      gradientView.translatesAutoresizingMaskIntoConstraints = NO;
-      [_fakeLocationBar addSubview:gradientView];
-      AddSameConstraints(_fakeLocationBar, gradientView);
-    }
-
     _fakeLocationBarHighlightView = [[UIView alloc] init];
     _fakeLocationBarHighlightView.userInteractionEnabled = NO;
     _fakeLocationBarHighlightView.backgroundColor = UIColor.clearColor;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h
index 70665564..12fc429 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h
@@ -13,7 +13,6 @@
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_gesture_commands.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_consumer.h"
-#import "ios/chrome/browser/ui/content_suggestions/start_suggest_service_response_bridge.h"
 #import "ios/chrome/browser/ui/start_surface/start_surface_recent_tab_removal_observer_bridge.h"
 
 namespace favicon {
@@ -45,8 +44,7 @@
 @interface ContentSuggestionsMediator
     : NSObject <ContentSuggestionsCommands,
                 ContentSuggestionsGestureCommands,
-                StartSurfaceRecentTabObserving,
-                StartSuggestServiceResponseDelegating>
+                StartSurfaceRecentTabObserving>
 
 // Default initializer.
 - (instancetype)
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
index 52918433..f291731 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
@@ -93,9 +93,6 @@
   std::unique_ptr<ntp_tiles::MostVisitedSites> _mostVisitedSites;
   std::unique_ptr<ntp_tiles::MostVisitedSitesObserverBridge> _mostVisitedBridge;
   std::unique_ptr<ReadingListModelBridge> _readingListModelBridge;
-  std::unique_ptr<StartSuggestServiceResponseBridge>
-      _startSuggestServiceResponseBridge;
-  StartSuggestService* _startSuggestService;
 }
 
 // Whether the contents section should be hidden completely.
@@ -151,9 +148,6 @@
 // Browser reference.
 @property(nonatomic, assign) Browser* browser;
 
-@property(nonatomic, strong)
-    NSMutableArray<QuerySuggestionConfig*>* trendingQueries;
-
 @end
 
 @implementation ContentSuggestionsMediator
@@ -193,13 +187,6 @@
     _readingListModelBridge =
         std::make_unique<ReadingListModelBridge>(self, readingListModel);
     _browser = browser;
-
-    if (IsTrendingQueriesModuleEnabled()) {
-      _startSuggestService = StartSuggestServiceFactory::GetForBrowserState(
-          self.browser->GetBrowserState(), true);
-      _startSuggestServiceResponseBridge =
-          std::make_unique<StartSuggestServiceResponseBridge>(self);
-    }
   }
   return self;
 }
@@ -231,13 +218,9 @@
   if ([self.mostVisitedItems count] && ![self shouldHideMVTForTileAblation]) {
     [self.consumer setMostVisitedTilesWithConfigs:self.mostVisitedItems];
   }
-  if (!ShouldHideShortcutsForTrendingQueries() &&
-      ![self shouldHideShortcutsForTileAblation]) {
+  if (![self shouldHideShortcutsForTileAblation]) {
     [self.consumer setShortcutTilesWithConfigs:self.actionButtonItems];
   }
-  if (IsTrendingQueriesModuleEnabled()) {
-    [self fetchTrendingQueriesIfApplicable];
-  }
 }
 
 - (void)blockMostVisitedURL:(GURL)URL {
@@ -347,16 +330,6 @@
   UrlLoadingBrowserAgent::FromBrowser(self.browser)->Load(params);
 }
 
-- (void)loadSuggestedQuery:(QuerySuggestionConfig*)config {
-  [self.contentSuggestionsMetricsRecorder
-      recordTrendingQueryTappedAtIndex:config.index];
-  [self.NTPMetrics recordContentSuggestionsActionForType:
-                       IOSContentSuggestionsActionType::kTrendingQuery];
-  UrlLoadParams params = UrlLoadParams::InCurrentTab(config.URL);
-  params.web_params.transition_type = ui::PAGE_TRANSITION_LINK;
-  UrlLoadingBrowserAgent::FromBrowser(self.browser)->Load(params);
-}
-
 - (void)openMostRecentTab {
   [self.NTPMetrics recordContentSuggestionsActionForType:
                        IOSContentSuggestionsActionType::kReturnToRecentTab];
@@ -415,25 +388,6 @@
   [self showMostVisitedUndoForURL:item.URL];
 }
 
-#pragma mark - StartSuggestServiceDelegateBridge
-
-- (void)suggestionsReceived:(std::vector<QuerySuggestion>)suggestions {
-  self.trendingQueries = [NSMutableArray array];
-  int index = 0;
-  for (QuerySuggestion query : suggestions) {
-    if (index == kMaxTrendingQueries) {
-      break;
-    }
-    QuerySuggestionConfig* suggestion = [[QuerySuggestionConfig alloc] init];
-    suggestion.URL = query.destination_url;
-    suggestion.query = base::SysUTF16ToNSString(query.query);
-    suggestion.index = index;
-    index++;
-    [self.trendingQueries addObject:suggestion];
-  }
-  [self.consumer setTrendingQueriesWithConfigs:self.trendingQueries];
-}
-
 #pragma mark - StartSurfaceRecentTabObserving
 
 - (void)mostRecentTabWasRemoved:(web::WebState*)web_state {
@@ -575,40 +529,6 @@
   [self.dispatcher showSnackbarMessage:message];
 }
 
-- (void)fetchTrendingQueriesIfApplicable {
-  PrefService* pref_service =
-      ChromeBrowserState::FromBrowserState(self.browser->GetBrowserState())
-          ->GetPrefs();
-
-  // Feed is disabled in safe mode.
-  SceneState* sceneState =
-      SceneStateBrowserAgent::FromBrowser(self.browser)->GetSceneState();
-  BOOL isSafeMode = [sceneState.appState resumingFromSafeMode];
-
-  BOOL isFeedVisible =
-      (pref_service->GetBoolean(prefs::kArticlesForYouEnabled) &&
-       pref_service->GetBoolean(prefs::kNTPContentSuggestionsEnabled) &&
-       !IsFeedAblationEnabled()) &&
-      !isSafeMode &&
-      pref_service->GetBoolean(feed::prefs::kArticlesListVisible);
-  if (ShouldOnlyShowTrendingQueriesForDisabledFeed() && isFeedVisible) {
-    // Notify consumer with empty array so it knows to remove the module.
-    [self.consumer setTrendingQueriesWithConfigs:@[]];
-    return;
-  }
-
-  // Fetch Trending Queries
-  TemplateURLRef::SearchTermsArgs args;
-  args.request_source = RequestSource::NTP_MODULE;
-  BOOL isShowingStartSurface = NewTabPageTabHelper::FromWebState(self.webState)
-                                   ->ShouldShowStartSurface();
-  _startSuggestService->FetchSuggestions(
-      args,
-      base::BindOnce(&StartSuggestServiceResponseBridge::OnSuggestionsReceived,
-                     _startSuggestServiceResponseBridge->AsWeakPtr()),
-      isShowingStartSurface);
-}
-
 - (NSString*)constructReturnToRecentTabSubtitleWithPageTitle:
                  (NSString*)pageTitle
                                                   timeString:(NSString*)time {
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator_unittest.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator_unittest.mm
index a120b41..9239e74 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator_unittest.mm
@@ -265,46 +265,6 @@
   [mediator_ mostRecentTabWasRemoved:web_state];
 }
 
-// Tests that the mediator calls the consumer properly in response to a call
-// from TestStartSuggestServiceResponseBridge
-TEST_F(ContentSuggestionsMediatorTest,
-       TestStartSuggestServiceResponseDelegating) {
-  // Expect the consumer is called with something if no suggestions are
-  // returned.
-  OCMExpect([consumer_ setTrendingQueriesWithConfigs:[OCMArg any]]);
-  std::vector<QuerySuggestion> response_queries{
-      {u"query1", GURL("http://test-url.com/query1")},
-      {u"query2", GURL("http://test-url.com/query1")}};
-  [mediator_ suggestionsReceived:std::move(response_queries)];
-
-  // Expect the consumer is called with an empty array if no suggestions are
-  // returned.
-  OCMExpect([consumer_ setTrendingQueriesWithConfigs:@[]]);
-  [mediator_ suggestionsReceived:std::vector<QuerySuggestion>()];
-
-  int index = 1;
-  histogram_tester_->ExpectUniqueSample(
-      "IOS.ContentSuggestions.ActionOnNTP",
-      IOSContentSuggestionsActionType::kTrendingQuery, 0);
-  histogram_tester_->ExpectUniqueSample("IOS.TrendingQueries", index, 0);
-
-  // Test that the mediator loads the URL in the config passed into
-  // loadSuggestedQuery:.
-  GURL url = GURL("http://chromium.org");
-  QuerySuggestionConfig* config = [[QuerySuggestionConfig alloc] init];
-  config.index = index;
-  config.URL = url;
-  [mediator_ loadSuggestedQuery:config];
-  EXPECT_EQ(url, url_loader_->last_params.web_params.url);
-  EXPECT_TRUE(ui::PageTransitionCoreTypeIs(
-      ui::PAGE_TRANSITION_LINK,
-      url_loader_->last_params.web_params.transition_type));
-  histogram_tester_->ExpectUniqueSample(
-      "IOS.ContentSuggestions.ActionOnNTP",
-      IOSContentSuggestionsActionType::kTrendingQuery, 1);
-  histogram_tester_->ExpectUniqueSample("IOS.TrendingQueries", index, 1);
-}
-
 // Tests that the command is sent to the dispatcher when opening the What's new.
 TEST_F(ContentSuggestionsMediatorTest, TestOpenWhatsNew) {
   OCMExpect([dispatcher_ showWhatsNew]);
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
index cd2f8a8..a0076dd1 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -12,7 +12,6 @@
 #import "ios/chrome/browser/shared/public/features/features.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cells_constants.h"
-#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_module_container.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_tile_view.h"
@@ -47,34 +46,10 @@
 #endif
 
 namespace {
-// The width of the modules.
-const int kModuleWidthCompact = 343;
-const int kModuleWidthRegular = 432;
-
-// The spacing between the modules.
-const float kModuleVerticalSpacing = 16.0f;
-const float kModuleMinimizedVerticalSpacing = 14.0f;
-
-// The horizontal spacing between trending query views.
-const float kTrendingQueryViewHorizontalSpacing = 12.0f;
 
 // The bottom padding for the vertical stack view.
 const float kBottomStackViewPadding = 6.0f;
 
-// Returns the module width depending on the horizontal trait collection.
-CGFloat GetModuleWidthForHorizontalTraitCollection(
-    UITraitCollection* traitCollection) {
-  return traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular
-             ? kModuleWidthRegular
-             : kModuleWidthCompact;
-}
-
-// Returns the spacing between modules.
-CGFloat ModuleVerticalSpacing() {
-  return ShouldMinimizeSpacingForModuleRefresh()
-             ? kModuleMinimizedVerticalSpacing
-             : kModuleVerticalSpacing;
-}
 }  // namespace
 
 @interface ContentSuggestionsViewController () <
@@ -97,23 +72,14 @@
 // The Return To Recent Tab view.
 @property(nonatomic, strong)
     ContentSuggestionsReturnToRecentTabView* returnToRecentTabTile;
-// Module container of `returnToRecentTabTile`.
-@property(nonatomic, strong)
-    ContentSuggestionsModuleContainer* returnToRecentTabContainer;
 // StackView holding all of `mostVisitedViews`.
 @property(nonatomic, strong) UIStackView* mostVisitedStackView;
-// Module Container for the Most Visited Tiles.
-@property(nonatomic, strong)
-    ContentSuggestionsModuleContainer* mostVisitedModuleContainer;
 // Width Anchor of the Most Visited Tiles container.
 @property(nonatomic, strong)
     NSLayoutConstraint* mostVisitedContainerWidthAnchor;
 // List of all of the Most Visited views.
 @property(nonatomic, strong)
     NSMutableArray<ContentSuggestionsMostVisitedTileView*>* mostVisitedViews;
-// Module Container for the Shortcuts.
-@property(nonatomic, strong)
-    ContentSuggestionsModuleContainer* shortcutsModuleContainer;
 // Width Anchor of the Shortcuts container.
 @property(nonatomic, strong) NSLayoutConstraint* shortcutsContainerWidthAnchor;
 // StackView holding all of `shortcutsViews`.
@@ -121,22 +87,6 @@
 // List of all of the Shortcut views.
 @property(nonatomic, strong)
     NSMutableArray<ContentSuggestionsShortcutTileView*>* shortcutsViews;
-// Module Container for Trending Queries.
-@property(nonatomic, strong)
-    ContentSuggestionsModuleContainer* trendingQueriesModuleContainer;
-@property(nonatomic, strong) UIView* trendingQueriesContainingView;
-// Width Anchor of the Trending Queries module container.
-@property(nonatomic, strong)
-    NSLayoutConstraint* trendingQueriesContainerWidthAnchor;
-// List of all of the Trending Query views.
-@property(nonatomic, strong)
-    NSMutableArray<QuerySuggestionView*>* trendingQueryViews;
-// List of all UITapGestureRecognizers created for the Trending Queries.
-@property(nonatomic, strong)
-    NSMutableArray<UITapGestureRecognizer*>* trendingQueryTapRecognizers;
-// Set to YES when the trending queries fetch has been received.
-@property(nonatomic, assign) BOOL trendingQueriesReceived;
-
 @end
 
 @implementation ContentSuggestionsViewController
@@ -152,19 +102,11 @@
   self.dragDropHandler.dropDelegate = self;
   [self.view addInteraction:[[UIDropInteraction alloc]
                                 initWithDelegate:self.dragDropHandler]];
-
-  if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-    self.view.backgroundColor = [UIColor clearColor];
-  } else {
-    self.view.backgroundColor = ntp_home::NTPBackgroundColor();
-  }
+  self.view.backgroundColor = ntp_home::NTPBackgroundColor();
   self.view.accessibilityIdentifier = kContentSuggestionsCollectionIdentifier;
 
   self.verticalStackView = [[UIStackView alloc] init];
   self.verticalStackView.translatesAutoresizingMaskIntoConstraints = NO;
-  if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-    self.verticalStackView.spacing = ModuleVerticalSpacing();
-  }
   self.verticalStackView.axis = UILayoutConstraintAxisVertical;
   // A centered alignment will ensure the views are centered.
   self.verticalStackView.alignment = UIStackViewAlignmentCenter;
@@ -183,10 +125,6 @@
   // `IsContentSuggestionsUIModuleRefreshEnabled()` is NO, then we add
   // `kBottomStackViewPadding`
   CGFloat bottomSpacing = kBottomStackViewPadding;
-  if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-    bottomSpacing =
-        ShouldMinimizeSpacingForModuleRefresh() ? 0 : kModuleVerticalSpacing;
-  }
   [NSLayoutConstraint activateConstraints:@[
     [self.verticalStackView.leadingAnchor
         constraintEqualToAnchor:self.view.leadingAnchor],
@@ -203,19 +141,9 @@
       ContentSuggestionsTilesHorizontalSpacing(self.traitCollection);
   if (self.returnToRecentTabTile) {
     UIView* parentView = self.returnToRecentTabTile;
-    if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-      self.returnToRecentTabContainer = [[ContentSuggestionsModuleContainer
-          alloc]
-          initWithContentView:self.returnToRecentTabTile
-                   moduleType:ContentSuggestionsModuleTypeReturnToRecentTab];
-      parentView = self.returnToRecentTabContainer;
-      [self.verticalStackView
-          addArrangedSubview:self.returnToRecentTabContainer];
-    } else {
-      [self addUIElement:self.returnToRecentTabTile
-          withCustomBottomSpacing:content_suggestions::
-                                      kReturnToRecentTabSectionBottomMargin];
-    }
+    [self addUIElement:self.returnToRecentTabTile
+        withCustomBottomSpacing:content_suggestions::
+                                    kReturnToRecentTabSectionBottomMargin];
     CGFloat cardWidth = content_suggestions::SearchFieldWidth(
         self.view.bounds.size.width, self.traitCollection);
     [NSLayoutConstraint activateConstraints:@[
@@ -224,99 +152,32 @@
           constraintEqualToConstant:ReturnToRecentTabHeight()]
     ]];
   }
-  if (IsContentSuggestionsUIModuleRefreshEnabled() ||
-      [self.mostVisitedViews count] > 0) {
+  if ([self.mostVisitedViews count] > 0) {
     self.mostVisitedStackView = [[UIStackView alloc] init];
     self.mostVisitedStackView.axis = UILayoutConstraintAxisHorizontal;
     self.mostVisitedStackView.distribution = UIStackViewDistributionFillEqually;
     self.mostVisitedStackView.spacing = horizontalSpacing;
-
-    if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-      self.mostVisitedStackView.backgroundColor =
-          ntp_home::NTPBackgroundColor();
-      self.mostVisitedStackView.alignment = UIStackViewAlignmentTop;
-      self.mostVisitedModuleContainer =
-          [[ContentSuggestionsModuleContainer alloc]
-              initWithContentView:self.mostVisitedStackView
-                       moduleType:ContentSuggestionsModuleTypeMostVisited];
-      if (!self.mostVisitedViews) {
-        self.mostVisitedViews = [NSMutableArray array];
-        self.mostVisitedModuleContainer.isPlaceholder = YES;
-        // Add placeholder tiles if Most Visited Tiles are not ready yet.
-        for (int i = 0; i < 4; i++) {
-          ContentSuggestionsMostVisitedTileView* view =
-              [[ContentSuggestionsMostVisitedTileView alloc]
-                  initWithConfiguration:nil];
-          [self.mostVisitedViews addObject:view];
-        }
-      }
-      [self.verticalStackView
-          addArrangedSubview:self.mostVisitedModuleContainer];
-      CGFloat width =
-          GetModuleWidthForHorizontalTraitCollection(self.traitCollection);
-      self.mostVisitedContainerWidthAnchor =
-          [self.mostVisitedModuleContainer.widthAnchor
-              constraintEqualToConstant:width];
-      [NSLayoutConstraint
-          activateConstraints:@[ self.mostVisitedContainerWidthAnchor ]];
-    } else {
-      self.mostVisitedStackView.alignment = UIStackViewAlignmentTop;
-      [self addUIElement:self.mostVisitedStackView
-          withCustomBottomSpacing:kMostVisitedBottomMargin];
-      CGFloat width =
-          MostVisitedTilesContentHorizontalSpace(self.traitCollection);
-      CGFloat height =
-          MostVisitedCellSize(self.traitCollection.preferredContentSizeCategory)
-              .height;
-      [NSLayoutConstraint activateConstraints:@[
-        [self.mostVisitedStackView.widthAnchor constraintEqualToConstant:width],
-        [self.mostVisitedStackView.heightAnchor
-            constraintGreaterThanOrEqualToConstant:height]
-      ]];
-    }
+    self.mostVisitedStackView.alignment = UIStackViewAlignmentTop;
+    [self addUIElement:self.mostVisitedStackView
+        withCustomBottomSpacing:kMostVisitedBottomMargin];
+    CGFloat width =
+        MostVisitedTilesContentHorizontalSpace(self.traitCollection);
+    CGFloat height =
+        MostVisitedCellSize(self.traitCollection.preferredContentSizeCategory)
+            .height;
+    [NSLayoutConstraint activateConstraints:@[
+      [self.mostVisitedStackView.widthAnchor constraintEqualToConstant:width],
+      [self.mostVisitedStackView.heightAnchor
+          constraintGreaterThanOrEqualToConstant:height]
+    ]];
     [self populateMostVisitedModule];
   }
-  BOOL noTrendingQueriesToShow =
-      self.trendingQueriesReceived && [self.trendingQueryViews count] == 0;
-  if (IsTrendingQueriesModuleEnabled() && !noTrendingQueriesToShow) {
-    self.trendingQueriesContainingView = [[UIView alloc] init];
-    self.trendingQueriesModuleContainer =
-        [[ContentSuggestionsModuleContainer alloc]
-            initWithContentView:self.trendingQueriesContainingView
-                     moduleType:ContentSuggestionsModuleTypeTrendingQueries];
-    if (!self.trendingQueryViews) {
-      self.trendingQueriesModuleContainer.isPlaceholder = YES;
-      self.trendingQueryViews = [NSMutableArray array];
-      // Add placeholder tiles if Most Visited Tiles are not ready yet.
-      for (int i = 0; i < 4; i++) {
-        QuerySuggestionView* view =
-            [[QuerySuggestionView alloc] initWithConfiguration:nil];
-        view.translatesAutoresizingMaskIntoConstraints = NO;
-        [self.trendingQueryViews addObject:view];
-      }
-    }
-    [self.verticalStackView
-        addArrangedSubview:self.trendingQueriesModuleContainer];
-    self.trendingQueriesContainerWidthAnchor =
-        [self.trendingQueriesModuleContainer.widthAnchor
-            constraintEqualToConstant:
-                GetModuleWidthForHorizontalTraitCollection(
-                    self.traitCollection)];
-    [NSLayoutConstraint
-        activateConstraints:@[ self.trendingQueriesContainerWidthAnchor ]];
-    [self populateTrendingQueriesModule];
-  }
   if (self.shortcutsViews) {
     self.shortcutsStackView = [[UIStackView alloc] init];
     self.shortcutsStackView.axis = UILayoutConstraintAxisHorizontal;
     self.shortcutsStackView.distribution = UIStackViewDistributionFillEqually;
     self.shortcutsStackView.spacing = horizontalSpacing;
-    if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-      self.shortcutsStackView.alignment = UIStackViewAlignmentTop;
-      self.shortcutsStackView.backgroundColor = ntp_home::NTPBackgroundColor();
-    } else {
-      self.shortcutsStackView.alignment = UIStackViewAlignmentTop;
-    }
+    self.shortcutsStackView.alignment = UIStackViewAlignmentTop;
     NSUInteger index = 0;
     for (ContentSuggestionsShortcutTileView* view in self.shortcutsViews) {
       view.accessibilityIdentifier = [NSString
@@ -332,19 +193,6 @@
       index++;
     }
 
-    if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-      self.shortcutsModuleContainer = [[ContentSuggestionsModuleContainer alloc]
-          initWithContentView:self.shortcutsStackView
-                   moduleType:ContentSuggestionsModuleTypeShortcuts];
-      [self.verticalStackView addArrangedSubview:self.shortcutsModuleContainer];
-      CGFloat width =
-          GetModuleWidthForHorizontalTraitCollection(self.traitCollection);
-      self.shortcutsContainerWidthAnchor =
-          [self.shortcutsModuleContainer.widthAnchor
-              constraintEqualToConstant:width];
-      [NSLayoutConstraint
-          activateConstraints:@[ self.shortcutsContainerWidthAnchor ]];
-    } else {
       [self addUIElement:self.shortcutsStackView
           withCustomBottomSpacing:kMostVisitedBottomMargin];
       CGFloat width =
@@ -357,7 +205,6 @@
         [self.shortcutsStackView.heightAnchor
             constraintGreaterThanOrEqualToConstant:height]
       ]];
-    }
   }
 }
 
@@ -388,34 +235,12 @@
   self.urlLoadingBrowserAgent->Load(UrlLoadParams::InCurrentTab(URL));
 }
 
-#pragma mark - UITraitEnvironment
-
-- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
-  [super traitCollectionDidChange:previousTraitCollection];
-  if (IsContentSuggestionsUIModuleRefreshEnabled() &&
-      previousTraitCollection.horizontalSizeClass !=
-          self.traitCollection.horizontalSizeClass) {
-    self.shortcutsContainerWidthAnchor.constant =
-        GetModuleWidthForHorizontalTraitCollection(self.traitCollection);
-    self.mostVisitedContainerWidthAnchor.constant =
-        GetModuleWidthForHorizontalTraitCollection(self.traitCollection);
-    if (IsTrendingQueriesModuleEnabled()) {
-      self.trendingQueriesContainerWidthAnchor.constant =
-          GetModuleWidthForHorizontalTraitCollection(self.traitCollection);
-    }
-  }
-}
-
 #pragma mark - ContentSuggestionsConsumer
 
 - (void)showReturnToRecentTabTileWithConfig:
     (ContentSuggestionsReturnToRecentTabItem*)config {
   if (self.returnToRecentTabTile) {
     [self.returnToRecentTabTile removeFromSuperview];
-
-    if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-      [self.returnToRecentTabContainer removeFromSuperview];
-    }
   }
 
   self.returnToRecentTabTile = [[ContentSuggestionsReturnToRecentTabView alloc]
@@ -430,23 +255,12 @@
   // tile to the StackView, otherwise, add to the verticalStackView.
   if (self.isViewLoaded) {
     UIView* parentView = self.returnToRecentTabTile;
-    if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-      self.returnToRecentTabContainer = [[ContentSuggestionsModuleContainer
-          alloc]
-          initWithContentView:self.returnToRecentTabTile
-                   moduleType:ContentSuggestionsModuleTypeReturnToRecentTab];
-      parentView = self.returnToRecentTabContainer;
-      [self.verticalStackView
-          insertArrangedSubview:self.returnToRecentTabContainer
-                        atIndex:0];
-    } else {
-      [self.verticalStackView insertArrangedSubview:self.returnToRecentTabTile
-                                            atIndex:0];
-      [self.verticalStackView
-          setCustomSpacing:content_suggestions::
-                               kReturnToRecentTabSectionBottomMargin
-                 afterView:self.returnToRecentTabTile];
-    }
+    [self.verticalStackView insertArrangedSubview:self.returnToRecentTabTile
+                                          atIndex:0];
+    [self.verticalStackView
+        setCustomSpacing:content_suggestions::
+                             kReturnToRecentTabSectionBottomMargin
+               afterView:self.returnToRecentTabTile];
     CGFloat cardWidth = content_suggestions::SearchFieldWidth(
         self.view.bounds.size.width, self.traitCollection);
     [NSLayoutConstraint activateConstraints:@[
@@ -484,10 +298,6 @@
 - (void)hideReturnToRecentTabTile {
   [self.returnToRecentTabTile removeFromSuperview];
   self.returnToRecentTabTile = nil;
-  if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-    // Remove module container.
-    [self.returnToRecentTabContainer removeFromSuperview];
-  }
 }
 
 - (void)setMostVisitedTilesWithConfigs:
@@ -495,9 +305,6 @@
   if (!configs) {
     return;
   }
-  if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-    self.mostVisitedModuleContainer.isPlaceholder = NO;
-  }
   if ([self.mostVisitedViews count]) {
     for (ContentSuggestionsMostVisitedTileView* view in self.mostVisitedViews) {
       [view removeFromSuperview];
@@ -511,9 +318,6 @@
   if ([configs count] == 0) {
     // No Most Visited Tiles to show. Remove module.
     [self.mostVisitedStackView removeFromSuperview];
-    if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-      [self.mostVisitedModuleContainer removeFromSuperview];
-    }
     return;
   }
   NSInteger index = 0;
@@ -569,45 +373,6 @@
   }
 }
 
-- (void)setTrendingQueriesWithConfigs:
-    (NSArray<QuerySuggestionConfig*>*)configs {
-  DCHECK(IsTrendingQueriesModuleEnabled());
-  self.trendingQueriesReceived = YES;
-  if (!self.trendingQueriesContainingView) {
-    self.trendingQueriesContainingView = [[UIView alloc] init];
-  }
-  self.trendingQueriesModuleContainer.isPlaceholder = NO;
-
-  if ([self.trendingQueryViews count]) {
-    for (QuerySuggestionView* view in self.trendingQueryViews) {
-      [view removeFromSuperview];
-    }
-    [self.trendingQueryViews removeAllObjects];
-    [self.trendingQueryTapRecognizers removeAllObjects];
-  } else {
-    self.trendingQueryViews = [NSMutableArray array];
-  }
-
-  if ((int)[configs count] < kMaxTrendingQueries) {
-    // No Trending Queries to show. Remove module.
-    [self.trendingQueriesContainingView removeFromSuperview];
-    [self.trendingQueriesModuleContainer removeFromSuperview];
-    [self.audience moduleWasRemoved];
-    return;
-  }
-
-  for (QuerySuggestionConfig* config in configs) {
-    QuerySuggestionView* view =
-        [[QuerySuggestionView alloc] initWithConfiguration:config];
-    //      view.menuProvider = self.menuProvider;
-    view.accessibilityIdentifier =
-        [NSString stringWithFormat:@"%@", config.query];
-    view.translatesAutoresizingMaskIntoConstraints = NO;
-    [self.trendingQueryViews addObject:view];
-  }
-  [self populateTrendingQueriesModule];
-}
-
 - (void)updateMostVisitedTileConfig:(ContentSuggestionsMostVisitedItem*)config {
   for (ContentSuggestionsMostVisitedTileView* view in self.mostVisitedViews) {
     if (view.config == config) {
@@ -621,44 +386,19 @@
 
 - (CGFloat)contentSuggestionsHeight {
   CGFloat height = 0;
-  if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-    height += [self.mostVisitedModuleContainer calculateIntrinsicHeight] +
-              ModuleVerticalSpacing();
-  } else if ([self.mostVisitedViews count] > 0) {
+  if ([self.mostVisitedViews count] > 0) {
     height += MostVisitedCellSize(
                   UIApplication.sharedApplication.preferredContentSizeCategory)
                   .height +
               kMostVisitedBottomMargin;
   }
-  if (IsContentSuggestionsUIModuleRefreshEnabled() &&
-      IsTrendingQueriesModuleEnabled() &&
-      [self.trendingQueriesModuleContainer superview]) {
-    height += [self.trendingQueriesModuleContainer calculateIntrinsicHeight];
-    // Only skip bottom spacing if minimizing spacing and Trending Queries is
-    // the last module.
-    if (!ShouldMinimizeSpacingForModuleRefresh() ||
-        !ShouldHideShortcutsForTrendingQueries()) {
-      height += ModuleVerticalSpacing();
-    }
-  }
   if ([self.shortcutsViews count] > 0) {
-    if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-      height += [self.shortcutsModuleContainer calculateIntrinsicHeight];
-      if (!ShouldMinimizeSpacingForModuleRefresh()) {
-        height += ModuleVerticalSpacing();
-      }
-    } else {
-      height +=
-          MostVisitedCellSize(
-              UIApplication.sharedApplication.preferredContentSizeCategory)
-              .height;
-    }
+    height += MostVisitedCellSize(
+                  UIApplication.sharedApplication.preferredContentSizeCategory)
+                  .height;
   }
   if (self.returnToRecentTabTile) {
     height += ReturnToRecentTabHeight();
-    if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-      height += ModuleVerticalSpacing();
-    }
   }
   return height;
 }
@@ -719,11 +459,6 @@
       }
       [self.suggestionCommandHandler openMostRecentTab];
     }
-  } else if ([sender.view isKindOfClass:[QuerySuggestionView class]]) {
-    QuerySuggestionView* querySuggestionView =
-        static_cast<QuerySuggestionView*>(sender.view);
-    [self.suggestionCommandHandler
-        loadSuggestedQuery:querySuggestionView.config];
   }
 }
 
@@ -741,8 +476,7 @@
 - (void)populateMostVisitedModule {
   // If viewDidLoad has been called before the first valid Most Visited Tiles
   // are available, construct `mostVisitedStackView`.
-  if (!IsContentSuggestionsUIModuleRefreshEnabled() && self.verticalStackView &&
-      !self.mostVisitedStackView) {
+  if (self.verticalStackView && !self.mostVisitedStackView) {
     self.mostVisitedStackView = [[UIStackView alloc] init];
     self.mostVisitedStackView.axis = UILayoutConstraintAxisHorizontal;
     self.mostVisitedStackView.alignment = UIStackViewAlignmentTop;
@@ -780,56 +514,4 @@
   }
 }
 
-- (void)populateTrendingQueriesModule {
-  for (QuerySuggestionView* view in self.trendingQueryViews) {
-    UITapGestureRecognizer* tapRecognizer = [[UITapGestureRecognizer alloc]
-        initWithTarget:self
-                action:@selector(contentSuggestionsElementTapped:)];
-    [view addGestureRecognizer:tapRecognizer];
-    tapRecognizer.enabled = YES;
-    [self.trendingQueryTapRecognizers addObject:tapRecognizer];
-    [self.trendingQueriesContainingView addSubview:view];
-  }
-  QuerySuggestionView* query1 = self.trendingQueryViews[0];
-  [query1 addBottomSeparator];
-  QuerySuggestionView* query2 = self.trendingQueryViews[1];
-  [query2 addBottomSeparator];
-  QuerySuggestionView* query3 = self.trendingQueryViews[2];
-  QuerySuggestionView* query4 = self.trendingQueryViews[3];
-  [NSLayoutConstraint activateConstraints:@[
-    [query1.topAnchor
-        constraintEqualToAnchor:self.trendingQueriesContainingView.topAnchor],
-    [query1.leadingAnchor
-        constraintEqualToAnchor:self.trendingQueriesContainingView
-                                    .leadingAnchor],
-    [query2.leadingAnchor
-        constraintGreaterThanOrEqualToAnchor:query1.trailingAnchor
-                                    constant:
-                                        kTrendingQueryViewHorizontalSpacing],
-    [query2.topAnchor
-        constraintEqualToAnchor:self.trendingQueriesContainingView.topAnchor],
-    [query2.trailingAnchor
-        constraintEqualToAnchor:self.trendingQueriesContainingView
-                                    .trailingAnchor],
-    [query3.leadingAnchor
-        constraintEqualToAnchor:self.trendingQueriesContainingView
-                                    .leadingAnchor],
-    [query3.bottomAnchor
-        constraintEqualToAnchor:self.trendingQueriesContainingView
-                                    .bottomAnchor],
-    [query3.topAnchor constraintEqualToAnchor:query1.bottomAnchor],
-    [query4.leadingAnchor
-        constraintGreaterThanOrEqualToAnchor:query3.trailingAnchor
-                                    constant:
-                                        kTrendingQueryViewHorizontalSpacing],
-    [query4.bottomAnchor
-        constraintEqualToAnchor:self.trendingQueriesContainingView
-                                    .bottomAnchor],
-    [query4.trailingAnchor
-        constraintEqualToAnchor:self.trendingQueriesContainingView
-                                    .trailingAnchor],
-    [query4.topAnchor constraintEqualToAnchor:query3.topAnchor]
-  ]];
-}
-
 @end
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
index 2bb7c34..c26b303d 100644
--- a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
@@ -508,34 +508,6 @@
                  @"NTP scroll position not saved properly.");
 }
 
-// Tests that the trending queries module header is visible and all four
-// trending queries are interactable.
-// Re-enable this test if trending queries is re-launched as a stable LE.
-- (void)DISABLED_testTrendingQueries {
-  AppLaunchConfiguration config = self.appConfigurationForTestCase;
-  config.features_enabled.push_back(kTrendingQueriesModule);
-  config.variations_enabled = {3350760};
-  [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
-
-  [[EarlGrey
-      selectElementWithMatcher:
-          grey_accessibilityID([NSString
-              stringWithFormat:
-                  @"%@",
-                  l10n_util::GetNSString(
-                      IDS_IOS_CONTENT_SUGGESTIONS_TRENDING_QUERIES_MODULE_TITLE)])]
-      assertWithMatcher:grey_sufficientlyVisible()];
-  for (int index = 0; index < 4; index++) {
-    [[EarlGrey
-        selectElementWithMatcher:
-            grey_accessibilityID([NSString
-                stringWithFormat:@"%@%i",
-                                 kQuerySuggestionViewA11yIdentifierPrefix,
-                                 index])]
-        assertWithMatcher:grey_interactable()];
-  }
-}
-
 // Tests that the pull to refresh (iphone) or the refresh button (ipad) lands
 // the user on the top of the NTP even with a previously saved scroll position.
 - (void)testReload {
@@ -1280,7 +1252,6 @@
   // otherwise support the various possible experiment arms.
   AppLaunchConfiguration config = [self appConfigurationForTestCase];
   config.relaunch_policy = ForceRelaunchByCleanShutdown;
-  config.features_disabled.push_back(kTrendingQueriesModule);
   [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
 
   // Ensures that feed header is visible before enabling ablation.
@@ -1324,7 +1295,6 @@
   // TODO(crbug.com/1350826): Adapt the test with launch of trending queries.
   AppLaunchConfiguration config = [self appConfigurationForTestCase];
   config.relaunch_policy = ForceRelaunchByCleanShutdown;
-  config.features_disabled.push_back(kTrendingQueriesModule);
   // TODO(crbug.com/1403077): Reenable the discover feed sync promo feature
   config.features_disabled.push_back(kEnableDiscoverFeedTopSyncPromo);
   [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
diff --git a/ios/chrome/browser/ui/first_run/BUILD.gn b/ios/chrome/browser/ui/first_run/BUILD.gn
index d59054e3..cbe1679 100644
--- a/ios/chrome/browser/ui/first_run/BUILD.gn
+++ b/ios/chrome/browser/ui/first_run/BUILD.gn
@@ -7,8 +7,6 @@
   sources = [
     "ios_first_run_field_trials.cc",
     "ios_first_run_field_trials.h",
-    "trending_queries_field_trial.cc",
-    "trending_queries_field_trial.h",
   ]
   deps = [
     ":field_trial_ids",
@@ -172,36 +170,6 @@
   frameworks = [ "UIKit.framework" ]
 }
 
-source_set("unit_tests") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  testonly = true
-  sources = [ "trending_queries_field_trial_unittest.mm" ]
-  deps = [
-    ":field_trial",
-    ":field_trial_ids",
-    ":first_run",
-    ":utils",
-    "//base",
-    "//base/test:test_support",
-    "//components/metrics",
-    "//components/policy/core/common:common_constants",
-    "//components/prefs",
-    "//components/prefs:test_support",
-    "//ios/chrome/browser/browser_state:test_support",
-    "//ios/chrome/browser/main:test_support",
-    "//ios/chrome/browser/shared/public/features",
-    "//ios/chrome/browser/signin:fake_system_identity",
-    "//ios/chrome/browser/ui/authentication",
-    "//ios/chrome/browser/ui/content_suggestions:feature_flags",
-    "//ios/chrome/browser/ui/fancy_ui",
-    "//ios/chrome/browser/ui/start_surface:feature_flags",
-    "//ios/chrome/test:test_support",
-    "//ios/web/public/test",
-    "//testing/gtest",
-    "//third_party/ocmock",
-  ]
-}
-
 source_set("eg2_tests") {
   configs += [
     "//build/config/compiler:enable_arc",
diff --git a/ios/chrome/browser/ui/first_run/trending_queries_field_trial.cc b/ios/chrome/browser/ui/first_run/trending_queries_field_trial.cc
deleted file mode 100644
index 70c695c..0000000
--- a/ios/chrome/browser/ui/first_run/trending_queries_field_trial.cc
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/first_run/trending_queries_field_trial.h"
-
-#import "base/feature_list.h"
-#import "base/metrics/field_trial.h"
-#import "base/metrics/field_trial_params.h"
-#import "components/prefs/pref_registry_simple.h"
-#import "components/prefs/pref_service.h"
-#import "components/version_info/version_info.h"
-#import "ios/chrome/browser/first_run/first_run.h"
-#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h"
-#import "ios/chrome/browser/ui/first_run/ios_first_run_field_trials.h"
-#import "ios/chrome/browser/ui/start_surface/start_surface_features.h"
-#import "ios/chrome/common/channel_info.h"
-
-namespace {
-// The placeholder trial version that is stored for a client who has not been
-// enrolled in the experiment.
-const int kPlaceholderTrialVersion = -1;
-
-// Group names for the Trending Queries feature.
-const char kTrendingQueriesEnabledModuleEnabledGroup[] =
-    "TrendingQueriesEnabledModuleEnabled-V3";
-const char kTrendingQueriesEnabledMinimalSpacingModuleEnabledGroup[] =
-    "TrendingQueriesEnabledMinimalSpacingModuleEnabled-V3";
-const char
-    kTrendingQueriesEnabledMinimalSpacingRemoveHeaderModuleEnabledGroup[] =
-        "TrendingQueriesEnabledMinimalSpacingRemoveHeaderModuleEnabled-V3";
-const char kTrendingQueriesKeepShortcutsEnabledModuleEnabledGroup[] =
-    "TrendingQueriesKeepShortcutsEnabledModuleEnabled-V3";
-const char kTrendingQueriesControlGroup[] = "Control-V3";
-
-const char kTrendingQueriesDefaultGroup[] = "Default";
-
-// Returns a map of the group weights for each arm.
-std::map<variations::VariationID, int> GetGroupWeights() {
-  std::map<variations::VariationID, int> weight_by_id = {
-      {kTrendingQueriesEnabledModuleEnabledID, 0},
-      {kTrendingQueriesEnabledMinimalSpacingModuleEnabledID, 0},
-      {kTrendingQueriesEnabledMinimalSpacingRemoveHeaderModuleEnabledID, 0},
-      {kTrendingQueriesKeepShortcutsEnabledModuleEnabledID, 0},
-      {kTrendingQueriesControlID, 0}};
-  switch (GetChannel()) {
-    case version_info::Channel::UNKNOWN:
-    case version_info::Channel::CANARY:
-    case version_info::Channel::DEV:
-    case version_info::Channel::BETA:
-      weight_by_id[kTrendingQueriesEnabledModuleEnabledID] = 20;
-      weight_by_id[kTrendingQueriesEnabledMinimalSpacingModuleEnabledID] = 20;
-      weight_by_id
-          [kTrendingQueriesEnabledMinimalSpacingRemoveHeaderModuleEnabledID] =
-              20;
-      weight_by_id[kTrendingQueriesKeepShortcutsEnabledModuleEnabledID] = 20;
-      weight_by_id[kTrendingQueriesControlID] = 20;
-      break;
-    case version_info::Channel::STABLE:
-      weight_by_id[kTrendingQueriesEnabledModuleEnabledID] = 8;
-      weight_by_id[kTrendingQueriesEnabledMinimalSpacingModuleEnabledID] = 8;
-      weight_by_id
-          [kTrendingQueriesEnabledMinimalSpacingRemoveHeaderModuleEnabledID] =
-              8;
-      weight_by_id[kTrendingQueriesKeepShortcutsEnabledModuleEnabledID] = 8;
-      weight_by_id[kTrendingQueriesControlID] = 8;
-      break;
-  }
-  return weight_by_id;
-}
-
-// Configures `group_name` with variationID |group_id| of size `group_weight`
-// for TrialConfig `config` with the following parameters:
-// kTrendingQueriesModule. `should_minimize_spacing_for_modules`: string boolean
-// of whether to minimize spacing in kContentSuggestionsUIModuleRefresh.
-// `should_remove_headers_for_modules`: string boolean of whether the header
-// should not be shown in kContentSuggestionsUIModuleRefresh. See
-// content_suggestions_feature.h for more details about params.
-void ConfigureGroupForConfig(
-    FirstRunFieldTrialConfig& config,
-    const std::string& group_name,
-    const variations::VariationID group_id,
-    int group_weight,
-    const std::string& should_hide_shortcuts_for_trending_queries,
-    const std::string& should_minimize_spacing_for_modules,
-    const std::string& should_remove_headers_for_modules) {
-  config.AddGroup(group_name, group_id, group_weight);
-  base::FieldTrialParams params;
-  params[kTrendingQueriesHideShortcutsParam] =
-      should_hide_shortcuts_for_trending_queries;
-  params[kContentSuggestionsUIModuleRefreshMinimizeSpacingParam] =
-      should_minimize_spacing_for_modules;
-  params[kContentSuggestionsUIModuleRefreshRemoveHeadersParam] =
-      should_remove_headers_for_modules;
-  base::AssociateFieldTrialParams(
-      kModularHomeTrendingQueriesClientSideFieldTrialName, group_name, params);
-}
-
-}  // namespace
-
-namespace trending_queries_field_trial {
-
-// Creates the trial config, initializes the trial that puts clients into
-// different groups, and returns the version number of the current trial. There
-// are 6 groups other than the default group:
-// - Control
-// - Enabled for All users
-// - Enabled for All users and Hide Shortcuts
-// - Enabled for signed out users
-// - Enabled for users that had the feed disabled
-// - Disabled for All users and Hide Shortcuts (essentially only showing
-// Most Visited and pushing up the feed)
-void CreateTrendingQueriesTrial(
-    std::map<variations::VariationID, int> weight_by_id,
-    const base::FieldTrial::EntropyProvider& low_entropy_provider,
-    base::FeatureList* feature_list) {
-  FirstRunFieldTrialConfig config(
-      kModularHomeTrendingQueriesClientSideFieldTrialName);
-
-  // Control group.
-  config.AddGroup(kTrendingQueriesControlGroup, kTrendingQueriesControlID,
-                  weight_by_id[kTrendingQueriesControlID]);
-
-  // Experiment Groups
-  ConfigureGroupForConfig(config, kTrendingQueriesEnabledModuleEnabledGroup,
-                          kTrendingQueriesEnabledModuleEnabledID,
-                          weight_by_id[kTrendingQueriesEnabledModuleEnabledID],
-                          "true", "false", "false");
-
-  ConfigureGroupForConfig(
-      config, kTrendingQueriesEnabledMinimalSpacingModuleEnabledGroup,
-      kTrendingQueriesEnabledMinimalSpacingModuleEnabledID,
-      weight_by_id[kTrendingQueriesEnabledMinimalSpacingModuleEnabledID],
-      "true", "true", "false");
-
-  ConfigureGroupForConfig(
-      config,
-      kTrendingQueriesEnabledMinimalSpacingRemoveHeaderModuleEnabledGroup,
-      kTrendingQueriesEnabledMinimalSpacingRemoveHeaderModuleEnabledID,
-      weight_by_id
-          [kTrendingQueriesEnabledMinimalSpacingRemoveHeaderModuleEnabledID],
-      "true", "true", "true");
-
-  ConfigureGroupForConfig(
-      config, kTrendingQueriesKeepShortcutsEnabledModuleEnabledGroup,
-      kTrendingQueriesKeepShortcutsEnabledModuleEnabledID,
-      weight_by_id[kTrendingQueriesKeepShortcutsEnabledModuleEnabledID],
-      "false", "false", "false");
-
-  scoped_refptr<base::FieldTrial> trial = config.CreateOneTimeRandomizedTrial(
-      kTrendingQueriesDefaultGroup, low_entropy_provider);
-
-  // Finalize the group choice and activates the trial - similar to a variation
-  // config that's marked with `starts_active` true. This is required for
-  // studies that register variation ids, so they don't reveal extra information
-  // beyond the low-entropy source.
-  const std::string& group_name = trial->group_name();
-  if (group_name == kTrendingQueriesEnabledModuleEnabledGroup ||
-      group_name == kTrendingQueriesEnabledMinimalSpacingModuleEnabledGroup ||
-      group_name ==
-          kTrendingQueriesEnabledMinimalSpacingRemoveHeaderModuleEnabledGroup ||
-      group_name == kTrendingQueriesKeepShortcutsEnabledModuleEnabledGroup) {
-    feature_list->RegisterFieldTrialOverride(
-        kTrendingQueriesModuleNewUser.name,
-        base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
-    feature_list->RegisterFieldTrialOverride(
-        kContentSuggestionsUIModuleRefreshNewUser.name,
-        base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
-  } else if (group_name == kTrendingQueriesControlGroup) {
-    feature_list->RegisterFieldTrialOverride(
-        kTrendingQueriesModuleNewUser.name,
-        base::FeatureList::OVERRIDE_DISABLE_FEATURE, trial.get());
-    feature_list->RegisterFieldTrialOverride(
-        kContentSuggestionsUIModuleRefreshNewUser.name,
-        base::FeatureList::OVERRIDE_DISABLE_FEATURE, trial.get());
-  }
-}
-
-void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterIntegerPref(kTrialPrefName, kPlaceholderTrialVersion);
-}
-
-void Create(const base::FieldTrial::EntropyProvider& low_entropy_provider,
-            base::FeatureList* feature_list,
-            PrefService* local_state) {
-  // Don't create the trial if either feature is enabled in chrome://flags. This
-  // condition is to avoid having multiple registered trials overriding the same
-  // feature.
-  if (feature_list->IsFeatureOverridden(
-          kContentSuggestionsUIModuleRefreshNewUser.name) ||
-      feature_list->IsFeatureOverridden(kTrendingQueriesModuleNewUser.name)) {
-    return;
-  }
-
-  // If the client is already an existing client by the time this experiment
-  // began running, don't register (e.g. the client is not in a First Run
-  // experience and was never grouped client-side into this study when it went
-  // through First Run).
-  // If this is not First Run, but the client has the correct pref saved, that
-  // means the user was bucketed into the trial when it went through First Run.
-  // Thus, it is important to register the trial, so those clients can persist
-  // the behavior that was chosen on first run.
-  if (!FirstRun::IsChromeFirstRun() &&
-      local_state->GetInteger(kTrialPrefName) != kCurrentTrialVersion) {
-    return;
-  }
-
-  CreateTrendingQueriesTrial(GetGroupWeights(), low_entropy_provider,
-                             feature_list);
-  local_state->SetInteger(kTrialPrefName, kCurrentTrialVersion);
-}
-
-void CreateTrendingQueriesTrialForTesting(
-    std::map<variations::VariationID, int> weights_by_id,
-    const base::FieldTrial::EntropyProvider& low_entropy_provider,
-    base::FeatureList* feature_list) {
-  CreateTrendingQueriesTrial(weights_by_id, low_entropy_provider, feature_list);
-}
-
-}  // namespace trending_queries_field_trial
diff --git a/ios/chrome/browser/ui/first_run/trending_queries_field_trial.h b/ios/chrome/browser/ui/first_run/trending_queries_field_trial.h
deleted file mode 100644
index 10a0837..0000000
--- a/ios/chrome/browser/ui/first_run/trending_queries_field_trial.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_FIRST_RUN_TRENDING_QUERIES_FIELD_TRIAL_H_
-#define IOS_CHROME_BROWSER_UI_FIRST_RUN_TRENDING_QUERIES_FIELD_TRIAL_H_
-
-#include "base/metrics/field_trial.h"
-#include "components/variations/variations_associated_data.h"
-
-class PrefService;
-class PrefRegistrySimple;
-
-namespace {
-
-// Variation IDs for Trending Queries experiment arms.
-const variations::VariationID kTrendingQueriesEnabledModuleEnabledID = 4871319;
-const variations::VariationID
-    kTrendingQueriesEnabledMinimalSpacingModuleEnabledID = 4871320;
-const variations::VariationID
-    kTrendingQueriesEnabledMinimalSpacingRemoveHeaderModuleEnabledID = 4871321;
-const variations::VariationID
-    kTrendingQueriesKeepShortcutsEnabledModuleEnabledID = 4871322;
-const variations::VariationID kTrendingQueriesControlID = 4871323;
-
-}  // namespace
-
-namespace trending_queries_field_trial {
-
-// Creates a field trial to control the Trending Queries feature so that it is
-// shown on the NTP after first run.
-//
-// The trial group chosen on first run is persisted to local state prefs.
-void Create(const base::FieldTrial::EntropyProvider& low_entropy_provider,
-            base::FeatureList* feature_list,
-            PrefService* local_state);
-
-// Registers the local state pref used to manage grouping for this field trial.
-void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
-
-// Exposes CreateTrendingQueriesTrial() for testing FieldTrial set-up.
-void CreateTrendingQueriesTrialForTesting(
-    std::map<variations::VariationID, int> weights_by_id,
-    const base::FieldTrial::EntropyProvider& low_entropy_provider,
-    base::FeatureList* feature_list);
-
-}  // namespace trending_queries_field_trial
-
-#endif  // IOS_CHROME_BROWSER_UI_FIRST_RUN_TRENDING_QUERIES_FIELD_TRIAL_H_
diff --git a/ios/chrome/browser/ui/first_run/trending_queries_field_trial_unittest.mm b/ios/chrome/browser/ui/first_run/trending_queries_field_trial_unittest.mm
deleted file mode 100644
index ee7fc2eb..0000000
--- a/ios/chrome/browser/ui/first_run/trending_queries_field_trial_unittest.mm
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/first_run/trending_queries_field_trial.h"
-
-#import "base/feature_list.h"
-#import "base/metrics/field_trial.h"
-#import "base/metrics/field_trial_param_associator.h"
-#import "base/test/mock_entropy_provider.h"
-#import "base/test/scoped_feature_list.h"
-#import "components/variations/variations_associated_data.h"
-#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h"
-#import "ios/chrome/browser/ui/start_surface/start_surface_features.h"
-#import "testing/platform_test.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-// Tests for field trial creation for the Trending Queries feature.
-class TrendingQueriesFieldTrialTest : public PlatformTest {
- protected:
-  void SetUp() override {
-    weight_by_id_ = {
-        {kTrendingQueriesEnabledModuleEnabledID, 0},
-        {kTrendingQueriesEnabledMinimalSpacingModuleEnabledID, 0},
-        {kTrendingQueriesEnabledMinimalSpacingRemoveHeaderModuleEnabledID, 0},
-        {kTrendingQueriesKeepShortcutsEnabledModuleEnabledID, 0},
-        {kTrendingQueriesControlID, 0}};
-  }
-
-  void TearDown() override {
-    scoped_feature_list_.Reset();
-    base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
-  }
-
-  base::test::ScopedFeatureList scoped_feature_list_;
-  std::map<variations::VariationID, int> weight_by_id_;
-  base::MockEntropyProvider low_entropy_provider_;
-};
-
-// Tests default field trial group.
-TEST_F(TrendingQueriesFieldTrialTest, TestDefault) {
-  auto feature_list = std::make_unique<base::FeatureList>();
-  trending_queries_field_trial::CreateTrendingQueriesTrialForTesting(
-      weight_by_id_, low_entropy_provider_, feature_list.get());
-
-  // Substitute the existing feature list with the one with field trial
-  // configurations we are testing, and check assertions.
-  scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
-  ASSERT_TRUE(base::FieldTrialList::IsTrialActive(
-      kModularHomeTrendingQueriesClientSideFieldTrialName));
-  EXPECT_FALSE(base::FeatureList::IsEnabled(kTrendingQueriesModuleNewUser));
-  EXPECT_FALSE(
-      base::FeatureList::IsEnabled(kContentSuggestionsUIModuleRefreshNewUser));
-}
-
-// Tests control field trial.
-TEST_F(TrendingQueriesFieldTrialTest, TestControl) {
-  auto feature_list = std::make_unique<base::FeatureList>();
-  weight_by_id_[kTrendingQueriesControlID] = 100;
-  trending_queries_field_trial::CreateTrendingQueriesTrialForTesting(
-      weight_by_id_, low_entropy_provider_, feature_list.get());
-
-  // Substitute the existing feature list with the one with field trial
-  // configurations we are testing, and check assertions.
-  scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
-  ASSERT_TRUE(base::FieldTrialList::IsTrialActive(
-      kModularHomeTrendingQueriesClientSideFieldTrialName));
-  EXPECT_FALSE(base::FeatureList::IsEnabled(kTrendingQueriesModuleNewUser));
-  EXPECT_FALSE(
-      base::FeatureList::IsEnabled(kContentSuggestionsUIModuleRefreshNewUser));
-}
-
-// Tests kTrendingQueriesEnabledModuleEnabledID field trial.
-TEST_F(TrendingQueriesFieldTrialTest, TestTrendingQueriesEnabledModuleEnabled) {
-  auto feature_list = std::make_unique<base::FeatureList>();
-  weight_by_id_[kTrendingQueriesEnabledModuleEnabledID] = 100;
-  trending_queries_field_trial::CreateTrendingQueriesTrialForTesting(
-      weight_by_id_, low_entropy_provider_, feature_list.get());
-
-  // Substitute the existing feature list with the one with field trial
-  // configurations we are testing, and check assertions.
-  scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
-  ASSERT_TRUE(base::FieldTrialList::IsTrialActive(
-      kModularHomeTrendingQueriesClientSideFieldTrialName));
-  EXPECT_TRUE(base::FeatureList::IsEnabled(kTrendingQueriesModuleNewUser));
-  EXPECT_TRUE(
-      base::FeatureList::IsEnabled(kContentSuggestionsUIModuleRefreshNewUser));
-  EXPECT_TRUE(base::GetFieldTrialParamByFeatureAsBool(
-      kTrendingQueriesModuleNewUser, kTrendingQueriesHideShortcutsParam,
-      false));
-  EXPECT_FALSE(base::GetFieldTrialParamByFeatureAsBool(
-      kContentSuggestionsUIModuleRefreshNewUser,
-      kContentSuggestionsUIModuleRefreshMinimizeSpacingParam, true));
-  EXPECT_FALSE(base::GetFieldTrialParamByFeatureAsBool(
-      kContentSuggestionsUIModuleRefreshNewUser,
-      kContentSuggestionsUIModuleRefreshRemoveHeadersParam, true));
-}
-
-// Tests kTrendingQueriesEnabledMinimalSpacingModuleEnabledID field trial.
-TEST_F(TrendingQueriesFieldTrialTest,
-       TestTrendingQueriesEnabledMinimalSpacingModuleEnabled) {
-  auto feature_list = std::make_unique<base::FeatureList>();
-  weight_by_id_[kTrendingQueriesEnabledMinimalSpacingModuleEnabledID] = 100;
-  trending_queries_field_trial::CreateTrendingQueriesTrialForTesting(
-      weight_by_id_, low_entropy_provider_, feature_list.get());
-
-  // Substitute the existing feature list with the one with field trial
-  // configurations we are testing, and check assertions.
-  scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
-  ASSERT_TRUE(base::FieldTrialList::IsTrialActive(
-      kModularHomeTrendingQueriesClientSideFieldTrialName));
-  EXPECT_TRUE(base::FeatureList::IsEnabled(kTrendingQueriesModuleNewUser));
-  EXPECT_TRUE(
-      base::FeatureList::IsEnabled(kContentSuggestionsUIModuleRefreshNewUser));
-  EXPECT_TRUE(base::GetFieldTrialParamByFeatureAsBool(
-      kTrendingQueriesModuleNewUser, kTrendingQueriesHideShortcutsParam,
-      false));
-  EXPECT_TRUE(base::GetFieldTrialParamByFeatureAsBool(
-      kContentSuggestionsUIModuleRefreshNewUser,
-      kContentSuggestionsUIModuleRefreshMinimizeSpacingParam, false));
-  EXPECT_FALSE(base::GetFieldTrialParamByFeatureAsBool(
-      kContentSuggestionsUIModuleRefreshNewUser,
-      kContentSuggestionsUIModuleRefreshRemoveHeadersParam, true));
-}
-
-// Tests kTrendingQueriesEnabledMinimalSpacingRemoveHeaderModuleEnabledID field
-// trial.
-TEST_F(TrendingQueriesFieldTrialTest,
-       TestTrendingQueriesEnabledMinimalSpacingRemoveHeaderModuleEnabled) {
-  auto feature_list = std::make_unique<base::FeatureList>();
-  weight_by_id_
-      [kTrendingQueriesEnabledMinimalSpacingRemoveHeaderModuleEnabledID] = 100;
-  trending_queries_field_trial::CreateTrendingQueriesTrialForTesting(
-      weight_by_id_, low_entropy_provider_, feature_list.get());
-
-  // Substitute the existing feature list with the one with field trial
-  // configurations we are testing, and check assertions.
-  scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
-  ASSERT_TRUE(base::FieldTrialList::IsTrialActive(
-      kModularHomeTrendingQueriesClientSideFieldTrialName));
-  EXPECT_TRUE(base::FeatureList::IsEnabled(kTrendingQueriesModuleNewUser));
-  EXPECT_TRUE(
-      base::FeatureList::IsEnabled(kContentSuggestionsUIModuleRefreshNewUser));
-  EXPECT_TRUE(base::GetFieldTrialParamByFeatureAsBool(
-      kTrendingQueriesModuleNewUser, kTrendingQueriesHideShortcutsParam,
-      false));
-  EXPECT_TRUE(base::GetFieldTrialParamByFeatureAsBool(
-      kContentSuggestionsUIModuleRefreshNewUser,
-      kContentSuggestionsUIModuleRefreshMinimizeSpacingParam, false));
-  EXPECT_TRUE(base::GetFieldTrialParamByFeatureAsBool(
-      kContentSuggestionsUIModuleRefreshNewUser,
-      kContentSuggestionsUIModuleRefreshRemoveHeadersParam, false));
-}
-
-// Tests kTrendingQueriesKeepShortcutsEnabledModuleEnabledID field trial.
-TEST_F(TrendingQueriesFieldTrialTest,
-       TestTrendingQueriesKeepShortcutsEnabledModuleEnabled) {
-  auto feature_list = std::make_unique<base::FeatureList>();
-  weight_by_id_[kTrendingQueriesKeepShortcutsEnabledModuleEnabledID] = 100;
-  trending_queries_field_trial::CreateTrendingQueriesTrialForTesting(
-      weight_by_id_, low_entropy_provider_, feature_list.get());
-
-  // Substitute the existing feature list with the one with field trial
-  // configurations we are testing, and check assertions.
-  scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
-  ASSERT_TRUE(base::FieldTrialList::IsTrialActive(
-      kModularHomeTrendingQueriesClientSideFieldTrialName));
-  EXPECT_TRUE(base::FeatureList::IsEnabled(kTrendingQueriesModuleNewUser));
-  EXPECT_TRUE(
-      base::FeatureList::IsEnabled(kContentSuggestionsUIModuleRefreshNewUser));
-  EXPECT_FALSE(base::GetFieldTrialParamByFeatureAsBool(
-      kTrendingQueriesModuleNewUser, kTrendingQueriesHideShortcutsParam, true));
-  EXPECT_FALSE(base::GetFieldTrialParamByFeatureAsBool(
-      kContentSuggestionsUIModuleRefreshNewUser,
-      kContentSuggestionsUIModuleRefreshMinimizeSpacingParam, true));
-  EXPECT_FALSE(base::GetFieldTrialParamByFeatureAsBool(
-      kContentSuggestionsUIModuleRefreshNewUser,
-      kContentSuggestionsUIModuleRefreshRemoveHeadersParam, true));
-}
diff --git a/ios/chrome/browser/ui/integration_tests/BUILD.gn b/ios/chrome/browser/ui/integration_tests/BUILD.gn
index 5cc26030..b5d21e14 100644
--- a/ios/chrome/browser/ui/integration_tests/BUILD.gn
+++ b/ios/chrome/browser/ui/integration_tests/BUILD.gn
@@ -10,7 +10,6 @@
   testonly = true
   sources = [ "pdf_egtest.mm" ]
   deps = [
-    "//ios/chrome/browser/snapshots:features",
     "//ios/chrome/test/earl_grey:eg_test_support+eg2",
     "//ios/testing/earl_grey:eg_test_support+eg2",
     "//net:test_support",
diff --git a/ios/chrome/browser/ui/integration_tests/pdf_egtest.mm b/ios/chrome/browser/ui/integration_tests/pdf_egtest.mm
index 3ef28a91..916a9f2 100644
--- a/ios/chrome/browser/ui/integration_tests/pdf_egtest.mm
+++ b/ios/chrome/browser/ui/integration_tests/pdf_egtest.mm
@@ -6,8 +6,6 @@
 #import <XCTest/XCTest.h>
 
 #import "base/test/ios/wait_util.h"
-#import "base/test/scoped_feature_list.h"
-#import "ios/chrome/browser/snapshots/features.h"
 #import "ios/chrome/test/earl_grey/chrome_actions.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
@@ -32,12 +30,6 @@
 
 @implementation PDFTestCase
 
-- (AppLaunchConfiguration)appConfigurationForTestCase {
-  AppLaunchConfiguration config;
-  config.features_enabled.push_back(kPDFSnapshot);
-  return config;
-}
-
 // Regression test for crbug/981893. Repro steps: open a PDF in a new
 // tab, switch back and forth betweeen the new tab and the old one by
 // swiping in the toolbar. The regression is a crash.
diff --git a/ios/chrome/browser/ui/ntp/BUILD.gn b/ios/chrome/browser/ui/ntp/BUILD.gn
index 0df1d23e..9699b04e 100644
--- a/ios/chrome/browser/ui/ntp/BUILD.gn
+++ b/ios/chrome/browser/ui/ntp/BUILD.gn
@@ -87,6 +87,7 @@
     ":logo",
     ":ntp",
     ":ntp_internal",
+    "//components/feed/core/v2/public:common",
     "//components/feed/core/v2/public/ios:feed_ios_public",
     "//components/policy:policy_code_generate",
     "//components/pref_registry",
diff --git a/ios/chrome/browser/ui/ntp/feed_header_view_controller.mm b/ios/chrome/browser/ui/ntp/feed_header_view_controller.mm
index bda844d..108b2f8 100644
--- a/ios/chrome/browser/ui/ntp/feed_header_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/feed_header_view_controller.mm
@@ -131,12 +131,8 @@
 
   // Applies an opacity to the background. If ReduceTransparency is enabled,
   // then this replaces the blur effect.
-  // With ContentSuggestionsUIModuleRefresh enabled, the background color will
-  // be clear for continuity with the overall NTP gradient view.
-  self.view.backgroundColor = IsContentSuggestionsUIModuleRefreshEnabled()
-                                  ? [UIColor clearColor]
-                                  : [[UIColor colorNamed:kBackgroundColor]
-                                        colorWithAlphaComponent:0.95];
+  self.view.backgroundColor =
+      [[UIColor colorNamed:kBackgroundColor] colorWithAlphaComponent:0.95];
 
   self.container = [[UIView alloc] init];
 
@@ -157,15 +153,6 @@
   if (UIAccessibilityIsReduceTransparencyEnabled() ||
       ![self.feedControlDelegate isFollowingFeedAvailable] ||
       !self.blurBackgroundView) {
-    if (IsContentSuggestionsUIModuleRefreshEnabled() &&
-        UIAccessibilityIsReduceTransparencyEnabled()) {
-      // Give background a solid color since it is clear when not pinned to the
-      // top of the NTP.
-      self.view.backgroundColor = blurred
-                                      ? [[UIColor colorNamed:kBackgroundColor]
-                                            colorWithAlphaComponent:0.95]
-                                      : [UIColor clearColor];
-    }
     return;
   }
 
@@ -176,15 +163,8 @@
   // blurred.
   if (!animated) {
     self.blurBackgroundView.hidden = !blurred;
-    if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-      self.view.backgroundColor = blurred
-                                      ? [[UIColor colorNamed:kBackgroundColor]
-                                            colorWithAlphaComponent:0.1]
-                                      : [UIColor clearColor];
-    } else {
-      self.view.backgroundColor = [[UIColor colorNamed:kBackgroundColor]
-          colorWithAlphaComponent:(blurred ? 0.1 : 0.95)];
-    }
+    self.view.backgroundColor = [[UIColor colorNamed:kBackgroundColor]
+        colorWithAlphaComponent:(blurred ? 0.1 : 0.95)];
     return;
   }
   [UIView transitionWithView:self.blurBackgroundView
@@ -196,15 +176,8 @@
       completion:^(BOOL finished) {
         // Only reduce opacity after the animation is complete to avoid showing
         // content suggestions tiles momentarily.
-        if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-          self.view.backgroundColor =
-              blurred ? [[UIColor colorNamed:kBackgroundColor]
-                            colorWithAlphaComponent:0.1]
-                      : [UIColor clearColor];
-        } else {
-          self.view.backgroundColor = [[UIColor colorNamed:kBackgroundColor]
-              colorWithAlphaComponent:(blurred ? 0.1 : 0.95)];
-        }
+        self.view.backgroundColor = [[UIColor colorNamed:kBackgroundColor]
+            colorWithAlphaComponent:(blurred ? 0.1 : 0.95)];
       }];
 }
 
diff --git a/ios/chrome/browser/ui/ntp/feed_wrapper_view_controller.mm b/ios/chrome/browser/ui/ntp/feed_wrapper_view_controller.mm
index 20c5842..1488ef69 100644
--- a/ios/chrome/browser/ui/ntp/feed_wrapper_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/feed_wrapper_view_controller.mm
@@ -91,10 +91,7 @@
   [emptyCollectionView setShowsVerticalScrollIndicator:NO];
   [self.view addSubview:emptyCollectionView];
   self.contentCollectionView = emptyCollectionView;
-  self.contentCollectionView.backgroundColor =
-      IsContentSuggestionsUIModuleRefreshEnabled()
-          ? [UIColor clearColor]
-          : ntp_home::NTPBackgroundColor();
+  self.contentCollectionView.backgroundColor = ntp_home::NTPBackgroundColor();
   self.contentCollectionView.translatesAutoresizingMaskIntoConstraints = NO;
   AddSameConstraints(self.contentCollectionView, self.view);
 }
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h
index 74390198..8cdf48d71 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h
@@ -310,6 +310,9 @@
 // Discover feed.
 extern const char kFollowingIndexWhenSwitchingFeed[];
 
+// Histogram name for sign-in related UI triggered by Feed entry points.
+extern const char kFeedSignInUI[];
+
 #pragma mark - User Actions
 
 // User action names for the device orientation having changed.
@@ -391,6 +394,8 @@
 extern const char kFollowingFeedGroupByPublisher[];
 extern const char kFollowingFeedSortByLatest[];
 
+#pragma mark - User Actions for Feed Sign-in Promo
+
 // User actions triggered when a user clicks the buttons on the Feed sign-in
 // promo UI.
 extern const char kFeedSignInPromoUIContinueTapped[];
@@ -401,4 +406,11 @@
 extern const char kShowFeedSignInOnlyUIWithUserId[];
 extern const char kShowFeedSignInOnlyUIWithoutUserId[];
 
+// User actions triggered when a user taps on Feed personalization controls and
+// a corresponding sign-in related UI is shown. Ex. A sign in half sheet, a
+// sign-in only flow, or a disabled toast is shown.
+extern const char kShowSyncHalfSheetFromFeed[];
+extern const char kShowSignInOnlyFlowFromFeed[];
+extern const char kShowSignInDisableToastFromFeed[];
+
 #endif  // IOS_CHROME_BROWSER_UI_NTP_METRICS_FEED_METRICS_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm
index c00f54e..af8e0ab3 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm
@@ -96,6 +96,7 @@
     "ContentSuggestions.Feed.CardIndexOnSwitch";
 const char kFollowingIndexWhenSwitchingFeed[] =
     "ContentSuggestions.Feed.WebFeed.CardIndexOnSwitch";
+const char kFeedSignInUI[] = "ContentSuggestions.Feed.FeedSignInUI";
 
 #pragma mark - User Actions
 
@@ -193,3 +194,9 @@
     "ContentSuggestions.Feed.SignIn.ShowFeedSignInOnlyUIWithUserId";
 const char kShowFeedSignInOnlyUIWithoutUserId[] =
     "ContentSuggestions.Feed.SignIn.ShowFeedSignInOnlyUIWithoutUserId";
+const char kShowSyncHalfSheetFromFeed[] =
+    "ContentSuggestions.Feed.SignIn.ShowSyncHalfSheetFromFeed";
+const char kShowSignInOnlyFlowFromFeed[] =
+    "ContentSuggestions.Feed.SignIn.ShowSignInOnlyFlowFromFeed";
+const char kShowSignInDisableToastFromFeed[] =
+    "ContentSuggestions.Feed.SignIn.ShowSignInDisableToastFromFeed";
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.h b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.h
index 9189549..e51a0d9 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.h
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.h
@@ -8,6 +8,7 @@
 #import <UIKit/UIKit.h>
 
 #import "base/time/time.h"
+#import "components/feed/core/v2/public/common_enums.h"
 #import "ios/chrome/browser/discover_feed/feed_constants.h"
 #import "ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h"
 #import "ios/chrome/browser/ui/ntp/metrics/feed_refresh_state_tracker.h"
@@ -271,6 +272,8 @@
 // are able to follow a website.
 - (void)recordFollowRecommendationIPHShown;
 
+#pragma mark - Sign-in Promo
+
 // Record metrics for when a user tapped on "Continue" of the Sign-in promo
 // UI.
 - (void)recordSignInPromoUIContinueTapped;
@@ -283,6 +286,10 @@
 // identities.
 - (void)recordShowSignInOnlyUIWithUserId:(BOOL)hasUserId;
 
+// Record metrics for sign-in related UI from Discover feed personalization
+// controls.
+- (void)recordShowSignInRelatedUIWithType:(feed::FeedSignInUI)type;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_NTP_METRICS_FEED_METRICS_RECORDER_H_
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
index 43dde15..687a872d 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
@@ -10,7 +10,6 @@
 #import "base/metrics/user_metrics.h"
 #import "base/metrics/user_metrics_action.h"
 #import "base/time/time.h"
-#import "components/feed/core/v2/public/common_enums.h"
 #import "ios/chrome/browser/discover_feed/discover_feed_refresher.h"
 #import "ios/chrome/browser/ntp/features.h"
 #import "ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.h"
@@ -796,6 +795,22 @@
                 : base::UserMetricsAction(kShowFeedSignInOnlyUIWithoutUserId));
 }
 
+- (void)recordShowSignInRelatedUIWithType:(feed::FeedSignInUI)type {
+  base::UmaHistogramEnumeration(kFeedSignInUI, type);
+  switch (type) {
+    case feed::FeedSignInUI::kShowSyncHalfSheet:
+      base::RecordAction(base::UserMetricsAction(kShowSyncHalfSheetFromFeed));
+      break;
+    case feed::FeedSignInUI::kShowSignInOnlyFlow:
+      base::RecordAction(base::UserMetricsAction(kShowSignInOnlyFlowFromFeed));
+      break;
+    case feed::FeedSignInUI::kShowSignInDisableToast:
+      base::RecordAction(
+          base::UserMetricsAction(kShowSignInDisableToastFromFeed));
+      break;
+  }
+}
+
 #pragma mark - Private
 
 // Returns the UserSettingsOnStart value based on the user settings.
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
index 53dfb08..8d40f77 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
@@ -13,6 +13,7 @@
 #import "base/metrics/user_metrics.h"
 #import "base/metrics/user_metrics_action.h"
 #import "base/time/time.h"
+#import "components/feed/core/v2/public/common_enums.h"
 #import "components/feed/core/v2/public/ios/pref_names.h"
 #import "components/policy/policy_constants.h"
 #import "components/pref_registry/pref_registry_syncable.h"
@@ -1035,6 +1036,8 @@
     [handler showSignin:command baseViewController:self.NTPViewController];
     [self.feedMetricsRecorder
         recordShowSignInOnlyUIWithUserId:hasUserIdentities];
+    [self.feedMetricsRecorder recordShowSignInRelatedUIWithType:
+                                  feed::FeedSignInUI::kShowSignInOnlyFlow];
   } else if ([self isSignInAllowed] && [self isSyncAllowed]) {
     // Show a sign-in promo half sheet for feed BoC sign-in promo when the
     // condition of showing sign-in only flow is not fulfilled. This UI will
@@ -1046,19 +1049,19 @@
         initWithBaseViewController:self.NTPViewController
                            browser:self.browser];
     [self.feedSignInPromoCoordinator start];
+    [self.feedMetricsRecorder recordShowSignInRelatedUIWithType:
+                                  feed::FeedSignInUI::kShowSyncHalfSheet];
   } else {
     // Show a snackbar message if sign-in or sync is disabled and the above UI
     // shouldn't be shown.
-    // TODO(crbug.com/1382615): remove when able to hide the personalization
-    // control when sign-in or sync is disabled.
     [self showSignInDisableMessage];
+    [self.feedMetricsRecorder recordShowSignInRelatedUIWithType:
+                                  feed::FeedSignInUI::kShowSignInDisableToast];
   }
 }
 
 - (void)showSignInUI {
   // Show a snackbar message if sign-in or sync is disabled.
-  // TODO(crbug.com/1382615): remove when able to hide the  personalization
-  // control when sign-in or sync is disabled.
   if (![self isSignInAllowed] || ![self isSyncAllowed]) {
     [self showSignInDisableMessage];
     return;
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm
index c103c42..71286a2 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm
@@ -186,18 +186,7 @@
               action:@selector(handleSingleTapInView:)];
   singleTapRecognizer.delegate = self;
   [self.view addGestureRecognizer:singleTapRecognizer];
-
-  if (IsContentSuggestionsUIModuleRefreshEnabled()) {
-    GradientView* gradientView = [[GradientView alloc]
-        initWithTopColor:[UIColor colorNamed:kBackgroundColor]
-             bottomColor:
-                 [UIColor colorNamed:@"ntp_background_bottom_gradient_color"]];
-    gradientView.translatesAutoresizingMaskIntoConstraints = NO;
-    [self.view addSubview:gradientView];
-    AddSameConstraints(self.view, gradientView);
-  } else {
-    self.view.backgroundColor = ntp_home::NTPBackgroundColor();
-  }
+  self.view.backgroundColor = ntp_home::NTPBackgroundColor();
 
   [self registerNotifications];
 
diff --git a/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens@2x.png b/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens@2x.png
index eee05543..5eb4fe46 100644
--- a/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens@2x.png
+++ b/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens@3x.png b/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens@3x.png
index 05bcb4b..826b4be 100644
--- a/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens@3x.png
+++ b/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens_dark@2x.png b/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens_dark@2x.png
index 1011ad0..bc0d6cf 100644
--- a/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens_dark@2x.png
+++ b/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens_dark@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens_dark@3x.png b/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens_dark@3x.png
index abe12b2..b0cf281d 100644
--- a/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens_dark@3x.png
+++ b/ios/chrome/browser/ui/omnibox/keyboard_assist/resources/keyboard_accessory_lens.imageset/keyboard_accessory_lens_dark@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_ui_features.cc b/ios/chrome/browser/ui/omnibox/omnibox_ui_features.cc
index d198d1a..5e23f0b 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_ui_features.cc
+++ b/ios/chrome/browser/ui/omnibox/omnibox_ui_features.cc
@@ -24,9 +24,10 @@
              "OmniboxMultilineSearchSuggest",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Tail suggest is triggered server side.
 BASE_FEATURE(kOmniboxTailSuggest,
              "OmniboxTailSuggest",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 bool IsIpadPopoutOmniboxEnabled() {
   return base::FeatureList::IsEnabled(kEnablePopoutOmniboxIpad) &&
diff --git a/ios/chrome/browser/ui/omnibox/popup/autocomplete_match_formatter.mm b/ios/chrome/browser/ui/omnibox/popup/autocomplete_match_formatter.mm
index a4b9108..149fdd3 100644
--- a/ios/chrome/browser/ui/omnibox/popup/autocomplete_match_formatter.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/autocomplete_match_formatter.mm
@@ -198,11 +198,29 @@
     UIColor* suggestionTextColor = SuggestionTextColor();
     UIColor* dimColor = self.incognito ? DimColorIncognito() : DimColor();
 
-    return [self attributedStringWithString:text
-                            classifications:textClassifications
-                                  smallFont:NO
-                                      color:suggestionTextColor
-                                   dimColor:dimColor];
+    NSAttributedString* attributedText =
+        [self attributedStringWithString:text
+                         classifications:textClassifications
+                               smallFont:NO
+                                   color:suggestionTextColor
+                                dimColor:dimColor];
+
+    if (self.isTailSuggestion &&
+        base::FeatureList::IsEnabled(kOmniboxTailSuggest)) {
+      NSMutableAttributedString* mutableString =
+          [[NSMutableAttributedString alloc] init];
+      NSAttributedString* tailSuggestPrefix =
+          // TODO(crbug.com/1432987): Do we want to localize the ellipsis ?
+          [self attributedStringWithString:@"... "
+                           classifications:NULL
+                                 smallFont:NO
+                                     color:suggestionTextColor
+                                  dimColor:dimColor];
+      [mutableString appendAttributedString:tailSuggestPrefix];
+      [mutableString appendAttributedString:attributedText];
+      attributedText = mutableString;
+    }
+    return attributedText;
   }
 }
 
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
index 0f73517..289f2c89 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
@@ -376,7 +376,12 @@
   UITapGestureRecognizer* debugGestureRecognizer =
       [[UITapGestureRecognizer alloc] initWithTarget:self
                                               action:@selector(showDebugUI)];
+#if TARGET_OS_SIMULATOR
+  // One tap for easy trigger on simulator.
+  debugGestureRecognizer.numberOfTapsRequired = 1;
+#else
   debugGestureRecognizer.numberOfTapsRequired = 2;
+#endif
   debugGestureRecognizer.numberOfTouchesRequired = 2;
   [self.view addGestureRecognizer:debugGestureRecognizer];
 }
diff --git a/ios/chrome/browser/ui/passwords/bottom_sheet/BUILD.gn b/ios/chrome/browser/ui/passwords/bottom_sheet/BUILD.gn
index 7bda88e..7905e9f 100644
--- a/ios/chrome/browser/ui/passwords/bottom_sheet/BUILD.gn
+++ b/ios/chrome/browser/ui/passwords/bottom_sheet/BUILD.gn
@@ -17,12 +17,15 @@
   deps = [
     "//components/autofill/ios/browser",
     "//components/autofill/ios/form_util",
+    "//components/prefs",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/autofill",
     "//ios/chrome/browser/autofill/bottom_sheet",
+    "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/favicon",
     "//ios/chrome/browser/main:public",
     "//ios/chrome/browser/passwords:password_controller_delegate",
+    "//ios/chrome/browser/prefs:pref_names",
     "//ios/chrome/browser/shared/coordinator/chrome_coordinator",
     "//ios/chrome/browser/shared/ui/symbols",
     "//ios/chrome/browser/shared/ui/table_view",
diff --git a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_coordinator.mm b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_coordinator.mm
index 95ee598d..aa55685 100644
--- a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_coordinator.mm
+++ b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_coordinator.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_coordinator.h"
 
+#import "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h"
 #import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator.h"
@@ -39,6 +40,7 @@
         initWithWebStateList:browser->GetWebStateList()
                faviconLoader:IOSChromeFaviconLoaderFactory::GetForBrowserState(
                                  browser->GetBrowserState())
+                 prefService:browser->GetBrowserState()->GetPrefs()
                       params:params];
     self.viewController.delegate = self.mediator;
 
diff --git a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator.h b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator.h
index c651fe0..c7f59f99 100644
--- a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator.h
+++ b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator.h
@@ -12,6 +12,7 @@
 }  // namespace autofill
 
 class FaviconLoader;
+class PrefService;
 class WebStateList;
 
 @protocol PasswordSuggestionBottomSheetConsumer;
@@ -24,6 +25,7 @@
 
 - (instancetype)initWithWebStateList:(WebStateList*)webStateList
                        faviconLoader:(FaviconLoader*)faviconLoader
+                         prefService:(PrefService*)prefService
                               params:
                                   (const autofill::FormActivityParams&)params;
 
diff --git a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator.mm b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator.mm
index 3ad7aa37..c53c0df 100644
--- a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator.mm
+++ b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator.mm
@@ -7,9 +7,11 @@
 #import "base/memory/raw_ptr.h"
 #import "base/strings/sys_string_conversions.h"
 #import "components/autofill/ios/form_util/form_activity_params.h"
+#import "components/prefs/pref_service.h"
 #import "ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h"
 #import "ios/chrome/browser/autofill/form_input_suggestions_provider.h"
 #import "ios/chrome/browser/autofill/form_suggestion_tab_helper.h"
+#import "ios/chrome/browser/prefs/pref_names.h"
 #import "ios/chrome/browser/shared/ui/symbols/symbols.h"
 #import "ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_consumer.h"
 #import "ios/chrome/browser/web_state_list/active_web_state_observation_forwarder.h"
@@ -55,18 +57,23 @@
   // FaviconLoader is a keyed service that uses LargeIconService to retrieve
   // favicon images.
   raw_ptr<FaviconLoader> _faviconLoader;
+
+  // Preference service from the application context.
+  PrefService* _prefService;
 }
 
 @synthesize defaultGlobeIconAttributes = _defaultGlobeIconAttributes;
 
 - (instancetype)initWithWebStateList:(WebStateList*)webStateList
                        faviconLoader:(FaviconLoader*)faviconLoader
+                         prefService:(PrefService*)prefService
                               params:
                                   (const autofill::FormActivityParams&)params {
   if (self = [super init]) {
     _needsRefocus = true;
     _frameId = params.frame_id;
     _faviconLoader = faviconLoader;
+    _prefService = prefService;
 
     _webStateList = webStateList;
     web::WebState* activeWebState = _webStateList->GetActiveWebState();
@@ -101,6 +108,7 @@
 }
 
 - (void)disconnect {
+  _prefService = nullptr;
   _faviconLoader = nullptr;
   _webStateList = nullptr;
   _forwarder = nullptr;
@@ -130,6 +138,8 @@
 
 - (void)refocus {
   if (_needsRefocus && _webStateList) {
+    [self incrementDismissCount];
+
     web::WebState* activeWebState = _webStateList->GetActiveWebState();
     web::WebFrame* frame = web::GetWebFrameWithId(activeWebState, _frameId);
     BottomSheetTabHelper::FromWebState(activeWebState)
@@ -213,4 +223,14 @@
   return _defaultGlobeIconAttributes;
 }
 
+// Increments the dismiss count preference.
+- (void)incrementDismissCount {
+  if (_prefService) {
+    _prefService->SetInteger(
+        prefs::kIosPasswordBottomSheetDismissCount,
+        _prefService->GetInteger(prefs::kIosPasswordBottomSheetDismissCount) +
+            1);
+  }
+}
+
 @end
diff --git a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator_unittest.mm b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator_unittest.mm
index c30ac35..8910aeb 100644
--- a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_mediator_unittest.mm
@@ -198,6 +198,7 @@
         initWithWebStateList:&web_state_list_
                faviconLoader:IOSChromeFaviconLoaderFactory::GetForBrowserState(
                                  chrome_browser_state_.get())
+                 prefService:chrome_browser_state_->GetPrefs()
                       params:params_];
   }
 
diff --git a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm
index 57842502..207adbb 100644
--- a/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm
+++ b/ios/chrome/browser/ui/passwords/bottom_sheet/password_suggestion_bottom_sheet_view_controller.mm
@@ -315,11 +315,19 @@
 
   TableViewURLCell* URLCell = base::mac::ObjCCastStrict<TableViewURLCell>(cell);
 
+  // Set the cell identifier to the associated URL, which we use to fetch the
+  // favicon.
+  NSString* cellIdentifier = [self descriptionAtRow:indexPath.row];
+  URLCell.cellUniqueIdentifier = cellIdentifier;
+
   auto faviconLoadedBlock = ^(FaviconAttributes* attributes) {
-    // TODO(crbug.com/1422362): if the user scrolls quickly and the cell is
-    // reused, it is possible that the wrong favicon is displayed (as the
-    // favicon fetch is asynchronous).
-    [URLCell.faviconView configureWithAttributes:attributes];
+    // If the user scrolls quickly, the cell could be reused, so make sure the
+    // favicon still matches the URL used to fetch the favicon (as the favicon
+    // fetch is asynchronous).
+    if ([URLCell.cellUniqueIdentifier isEqualToString:cellIdentifier]) {
+      DCHECK(attributes);
+      [URLCell.faviconView configureWithAttributes:attributes];
+    }
   };
   [self.delegate loadFaviconAtIndexPath:indexPath
                     faviconBlockHandler:faviconLoadedBlock];
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm
index 3a8d6886..3663145 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm
@@ -4,11 +4,14 @@
 
 #import "ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.h"
 
+#import <set>
 #import <utility>
 #import <vector>
 
 #import "base/mac/foundation_util.h"
+#import "base/memory/raw_ptr.h"
 #import "base/memory/scoped_refptr.h"
+#import "base/notreached.h"
 #import "base/strings/sys_string_conversions.h"
 #import "components/password_manager/core/browser/ui/affiliated_group.h"
 #import "components/password_manager/core/browser/ui/credential_ui_entry.h"
@@ -17,6 +20,8 @@
 #import "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/credential_provider_promo/features.h"
 #import "ios/chrome/browser/main/browser.h"
+#import "ios/chrome/browser/main/browser_list.h"
+#import "ios/chrome/browser/main/browser_list_factory.h"
 #import "ios/chrome/browser/passwords/ios_chrome_password_check_manager.h"
 #import "ios/chrome/browser/passwords/ios_chrome_password_check_manager_factory.h"
 #import "ios/chrome/browser/passwords/password_tab_helper.h"
@@ -45,12 +50,70 @@
 #error "This file requires ARC support."
 #endif
 
+namespace {
+
+class PasswordManagerClientProviderImpl : public PasswordManagerClientProvider {
+ public:
+  explicit PasswordManagerClientProviderImpl(Browser* browser)
+      : browser_(browser) {}
+
+  ~PasswordManagerClientProviderImpl() override = default;
+
+  PasswordManagerClientProviderImpl(const PasswordManagerClientProviderImpl&) =
+      delete;
+  PasswordManagerClientProviderImpl& operator=(
+      const PasswordManagerClientProviderImpl&) = delete;
+
+  password_manager::PasswordManagerClient* GetAny() override {
+    web::WebState* active_tab_in_browser =
+        browser_->GetWebStateList()->GetActiveWebState();
+    if (active_tab_in_browser) {
+      return PasswordTabHelper::FromWebState(active_tab_in_browser)
+          ->GetPasswordManagerClient();
+    }
+
+    // PasswordDetailsCoordinator and other settings coordinators always receive
+    // a normal Browser, even if they are started from incognito. So if only
+    // incognito tabs are open, `active_tab_in_browser` is null, causing a crash
+    // (crbug.com/1431975).
+    // In that case, use an open tab in any Browser. It doesn't matter which
+    // one. This is a sad workaround for the fact that some PasswordManager
+    // layers depend on tabs unnecessarily.
+    BrowserList* browser_list =
+        BrowserListFactory::GetForBrowserState(browser_->GetBrowserState());
+    for (const std::set<Browser*>& browsers :
+         {browser_list->AllRegularBrowsers(),
+          browser_list->AllIncognitoBrowsers()}) {
+      for (Browser* other_browser : browsers) {
+        web::WebState* other_active_tab =
+            other_browser->GetWebStateList()->GetActiveWebState();
+        if (other_active_tab) {
+          return PasswordTabHelper::FromWebState(other_active_tab)
+              ->GetPasswordManagerClient();
+        }
+      }
+    }
+
+    // It's impossible to open PasswordDetailsCoordinator without an open tab.
+    NOTREACHED_NORETURN();
+  }
+
+ private:
+  const raw_ptr<Browser> browser_;
+};
+
+}  // namespace
+
 @interface PasswordDetailsCoordinator () <PasswordDetailsHandler> {
   password_manager::AffiliatedGroup _affiliatedGroup;
   password_manager::CredentialUIEntry _credential;
 
   // The context in which the password details are accessed.
   DetailsContext _context;
+
+  // See PasswordManagerClientProviderImpl docs.
+  std::unique_ptr<PasswordManagerClientProviderImpl>
+      _passwordManagerClientProvider;
 }
 
 // Main view controller for this coordinator.
@@ -135,23 +198,19 @@
   }
 
   ChromeBrowserState* browserState = self.browser->GetBrowserState();
-  web::WebState* webState =
-      self.browser->GetWebStateList()->GetActiveWebState();
-  DCHECK(webState) << "It is impossible to open password details UI when all "
-                      "tabs are closed.";
-  // It's safe to inject PasswordManagerClient, because `webState` (current tab)
-  // can't be closed while this UI is open.
+  _passwordManagerClientProvider =
+      std::make_unique<PasswordManagerClientProviderImpl>(self.browser);
   self.mediator = [[PasswordDetailsMediator alloc]
-          initWithPasswords:credentials
-                displayName:displayName
-       passwordCheckManager:IOSChromePasswordCheckManagerFactory::
-                                GetForBrowserState(browserState)
-                                    .get()
-                prefService:browserState->GetPrefs()
-                syncService:SyncServiceFactory::GetForBrowserState(browserState)
-                    context:_context
-      passwordManagerClient:PasswordTabHelper::FromWebState(webState)
-                                ->GetPasswordManagerClient()];
+                  initWithPasswords:credentials
+                        displayName:displayName
+               passwordCheckManager:IOSChromePasswordCheckManagerFactory::
+                                        GetForBrowserState(browserState)
+                                            .get()
+                        prefService:browserState->GetPrefs()
+                        syncService:SyncServiceFactory::GetForBrowserState(
+                                        browserState)
+                            context:_context
+      passwordManagerClientProvider:_passwordManagerClientProvider.get()];
   self.mediator.consumer = self.viewController;
   self.viewController.handler = self;
   self.viewController.delegate = self.mediator;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.h b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.h
index 2fd5629e..3eb1f19 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.h
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.h
@@ -25,6 +25,15 @@
 class IOSChromePasswordCheckManager;
 @protocol PasswordDetailsConsumer;
 
+// Provides PasswordManagerClient (per-tab object) on-demand, so there's no need
+// to worry about tabs being closed.
+class PasswordManagerClientProvider {
+ public:
+  virtual ~PasswordManagerClientProvider() = default;
+
+  virtual password_manager::PasswordManagerClient* GetAny() = 0;
+};
+
 // This mediator fetches and organises the credentials for its consumer.
 @interface PasswordDetailsMediator
     : NSObject <PasswordDetailsTableViewControllerDelegate>
@@ -40,8 +49,8 @@
                       prefService:(PrefService*)prefService
                       syncService:(syncer::SyncService*)syncService
                           context:(DetailsContext)context
-            passwordManagerClient:
-                (password_manager::PasswordManagerClient*)passwordManagerClient
+    passwordManagerClientProvider:
+        (PasswordManagerClientProvider*)passwordManagerClientProvider
     NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)init NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm
index 55e263c..45d124fb 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm
@@ -68,8 +68,8 @@
   // The context in which the password details are accessed.
   DetailsContext _context;
 
-  // Password manager client.
-  raw_ptr<password_manager::PasswordManagerClient> _passwordManagerClient;
+  // Password manager client provider.
+  raw_ptr<PasswordManagerClientProvider> _passwordManagerClientProvider;
 
   // The BrowserState pref service.
   raw_ptr<PrefService> _prefService;
@@ -91,18 +91,18 @@
 
 @implementation PasswordDetailsMediator
 
-- (instancetype)
-        initWithPasswords:
-            (const std::vector<password_manager::CredentialUIEntry>&)credentials
-              displayName:(NSString*)displayName
-     passwordCheckManager:(IOSChromePasswordCheckManager*)manager
-              prefService:(PrefService*)prefService
-              syncService:(syncer::SyncService*)syncService
-                  context:(DetailsContext)context
-    passwordManagerClient:
-        (password_manager::PasswordManagerClient*)passwordManagerClient {
+- (instancetype)initWithPasswords:
+                    (const std::vector<password_manager::CredentialUIEntry>&)
+                        credentials
+                      displayName:(NSString*)displayName
+             passwordCheckManager:(IOSChromePasswordCheckManager*)manager
+                      prefService:(PrefService*)prefService
+                      syncService:(syncer::SyncService*)syncService
+                          context:(DetailsContext)context
+    passwordManagerClientProvider:
+        (PasswordManagerClientProvider*)passwordManagerClientProvider {
   DCHECK(manager);
-  DCHECK(passwordManagerClient);
+  DCHECK(passwordManagerClientProvider);
   DCHECK(!credentials.empty());
 
   self = [super init];
@@ -116,7 +116,7 @@
   _passwordCheckObserver =
       std::make_unique<PasswordCheckObserverBridge>(self, manager);
   _context = context;
-  _passwordManagerClient = passwordManagerClient;
+  _passwordManagerClientProvider = passwordManagerClientProvider;
   _prefService = prefService;
   _syncService = syncService;
 
@@ -224,7 +224,7 @@
   MovePasswordsToAccountStore(
       _manager->GetSavedPasswordsPresenter()->GetCorrespondingPasswordForms(
           *it),
-      _passwordManagerClient,
+      _passwordManagerClientProvider->GetAny(),
       password_manager::metrics_util::MoveToAccountStoreTrigger::
           kExplicitlyTriggeredInSettings);
   [self providePasswordsToConsumer];
diff --git a/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm b/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm
index c4b3d58..4d087d0 100644
--- a/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm
+++ b/ios/chrome/browser/ui/settings/password/password_manager_egtest.mm
@@ -3204,6 +3204,61 @@
       assertWithMatcher:grey_notVisible()];
 }
 
+// Regression test for crbug.com/1431975. Similar to testMovePasswordToAccount
+// above but the only open tab is an incognito one.
+- (void)testMovePasswordToAccountWithOnlyIncognitoTabOpen {
+  GREYAssert(
+      [PasswordSettingsAppInterface saveExamplePassword:@"localPassword"
+                                               userName:@"username"
+                                                 origin:@"https://local.com"],
+      @"Stored form was not found in the PasswordStore results.");
+  [SigninEarlGreyUI signinWithFakeIdentity:[FakeSystemIdentity fakeIdentity1]
+                                enableSync:NO];
+
+  [ChromeEarlGrey openNewIncognitoTab];
+  [ChromeEarlGrey closeAllNormalTabs];
+
+  OpenPasswordManager();
+
+  // `passwordMatcher` includes grey_sufficientlyVisible() because there are
+  // other invisible cells when password details is closed later.
+  id<GREYMatcher> passwordMatcher =
+      grey_allOf([self groupingEnabled]
+                     ? ButtonWithAccessibilityID(@"local.com")
+                     : ButtonWithAccessibilityID(@"local.com, username"),
+                 grey_sufficientlyVisible(), nil);
+  id<GREYMatcher> localIconMatcher =
+      grey_allOf(grey_accessibilityID(kLocalOnlyPasswordIconId),
+                 grey_ancestor(passwordMatcher), nil);
+  [GetInteractionForListItem(localIconMatcher, kGREYDirectionDown)
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  [[EarlGrey selectElementWithMatcher:passwordMatcher]
+      performAction:grey_tap()];
+
+  [PasswordSettingsAppInterface setUpMockReauthenticationModule];
+  [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
+                                    ReauthenticationResult::kSuccess];
+
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kMovePasswordToAccountButtonId)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kMovePasswordToAccountButtonId)]
+      performAction:grey_tap()];
+
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kMovePasswordToAccountButtonId)]
+      assertWithMatcher:grey_notVisible()];
+
+  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
+      performAction:grey_tap()];
+
+  [GetInteractionForListItem(localIconMatcher, kGREYDirectionDown)
+      assertWithMatcher:grey_notVisible()];
+}
+
 @end
 
 // Rerun all the tests in this file but with kPasswordsGrouping disabled. This
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/BUILD.gn b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/BUILD.gn
index ee5d9d6..f99fa0f 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/BUILD.gn
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/BUILD.gn
@@ -22,11 +22,15 @@
     "//components/favicon/ios",
     "//components/prefs",
     "//components/prefs/ios",
+    "//components/sessions",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/application_context",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/main:public",
     "//ios/chrome/browser/prefs:pref_names",
+    "//ios/chrome/browser/sessions",
+    "//ios/chrome/browser/sessions:restoration_agent",
+    "//ios/chrome/browser/sessions:serialisation",
     "//ios/chrome/browser/shared/coordinator/alert",
     "//ios/chrome/browser/shared/coordinator/chrome_coordinator",
     "//ios/chrome/browser/shared/ui/symbols",
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.h
index 8f8a43c..8dac446 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.h
@@ -8,6 +8,7 @@
 #import "ios/chrome/browser/shared/coordinator/chrome_coordinator/chrome_coordinator.h"
 
 @class InactiveTabsCoordinator;
+@protocol GridCommands;
 @protocol TabContextMenuProvider;
 
 // Delegate for the coordinator.
@@ -26,19 +27,27 @@
 
 // Handles interaction with the inactive tabs view controller.
 //
-// This coordinator lifetime starts the first time the Inactive Tabs grid is
-// displayed, and stops only when the regular tab grid is stopped.
-// `start` creates the relevant objects (VC, mediator, etc.), but doesn't show
-// the VC. Call `show`/`hide` to display/hide the inactive tabs grid.
-// By keeping this coordinator alive, the VC can be re-shown as is (i.e. same
-// scroll position).
+// This coordinator lifetime starts when the regular tab grid is started, and
+// stops only when the regular tab grid is stopped. `start` creates the relevant
+// objects (VC, mediator, etc.), but doesn't show the VC. Call `show`/`hide` to
+// display/hide the inactive tabs grid. By having this coordinator alive, the
+// mediator can react to "Close All" signals, and the VC can be re-shown as is
+// (i.e. same scroll position).
 @interface InactiveTabsCoordinator : ChromeCoordinator
 
-// Delegate for dismissing the coordinator.
-@property(nonatomic, weak) id<InactiveTabsCoordinatorDelegate> delegate;
+// The GridCommands receiver handling "Close All"-related commands.
+@property(nonatomic, weak, readonly) id<GridCommands> gridCommandsHandler;
 
-// Provides the context menu for the tabs on the grid.
-@property(nonatomic, weak) id<TabContextMenuProvider> menuProvider;
+// Init the inactive tabs coordinator, all parameters should *not* be nil.
+- (instancetype)
+    initWithBaseViewController:(UIViewController*)viewController
+                       browser:(Browser*)browser
+                      delegate:(id<InactiveTabsCoordinatorDelegate>)delegate
+                  menuProvider:(id<TabContextMenuProvider>)menuProvider
+    NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)initWithBaseViewController:(UIViewController*)viewController
+                                   browser:(Browser*)browser NS_UNAVAILABLE;
 
 // Animates in the grid of inactive tabs.
 - (void)show;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.mm
index 0600a53..20f332a 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.mm
@@ -11,6 +11,8 @@
 #import "base/strings/sys_string_conversions.h"
 #import "ios/chrome/browser/application_context/application_context.h"
 #import "ios/chrome/browser/main/browser.h"
+#import "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h"
+#import "ios/chrome/browser/sessions/session_restoration_browser_agent.h"
 #import "ios/chrome/browser/shared/coordinator/alert/action_sheet_coordinator.h"
 #import "ios/chrome/browser/snapshots/snapshot_browser_agent.h"
 #import "ios/chrome/browser/tabs/inactive_tabs/features.h"
@@ -65,16 +67,38 @@
 
 @end
 
-@implementation InactiveTabsCoordinator
+@implementation InactiveTabsCoordinator {
+  // Delegate for dismissing the coordinator.
+  __weak id<InactiveTabsCoordinatorDelegate> _delegate;
+
+  // Provides the context menu for the tabs on the grid.
+  __weak id<TabContextMenuProvider> _menuProvider;
+}
+
+#pragma mark - Public
+
+- (instancetype)
+    initWithBaseViewController:(UIViewController*)viewController
+                       browser:(Browser*)browser
+                      delegate:(id<InactiveTabsCoordinatorDelegate>)delegate
+                  menuProvider:(id<TabContextMenuProvider>)menuProvider {
+  CHECK(IsInactiveTabsEnabled());
+  CHECK(menuProvider);
+  CHECK(delegate);
+  self = [super initWithBaseViewController:viewController browser:browser];
+  if (self) {
+    _delegate = delegate;
+    _menuProvider = menuProvider;
+  }
+  return self;
+}
+
+- (id<GridCommands>)gridCommandsHandler {
+  return self.mediator;
+}
 
 #pragma mark - ChromeCoordinator
 
-- (instancetype)initWithBaseViewController:(UIViewController*)viewController
-                                   browser:(Browser*)browser {
-  DCHECK(IsInactiveTabsEnabled());
-  return [super initWithBaseViewController:viewController browser:browser];
-}
-
 - (void)start {
   [super start];
 
@@ -84,16 +108,25 @@
   self.viewController.gridViewController.delegate = self;
 
   // Create the mediator.
-  SnapshotCache* snapshotCache =
-      SnapshotBrowserAgent::FromBrowser(self.browser)->snapshot_cache();
+  SessionRestorationBrowserAgent* sessionRestorationBrowserAgent =
+      SessionRestorationBrowserAgent::FromBrowser(self.browser);
+  SnapshotBrowserAgent* snapshotBrowserAgent =
+      SnapshotBrowserAgent::FromBrowser(self.browser);
+  sessions::TabRestoreService* tabRestoreService =
+      IOSChromeTabRestoreServiceFactory::GetForBrowserState(
+          self.browser->GetBrowserState());
+
   self.mediator = [[InactiveTabsMediator alloc]
-      initWithConsumer:self.viewController.gridViewController
-        commandHandler:self
-          webStateList:self.browser->GetWebStateList()
-           prefService:GetApplicationContext()->GetLocalState()
-         snapshotCache:snapshotCache];
+             initWithConsumer:self.viewController.gridViewController
+               commandHandler:self
+                 webStateList:self.browser->GetWebStateList()
+                  prefService:GetApplicationContext()->GetLocalState()
+      sessionRestorationAgent:sessionRestorationBrowserAgent
+                snapshotAgent:snapshotBrowserAgent
+            tabRestoreService:tabRestoreService];
+
   self.viewController.gridViewController.imageDataSource = self.mediator;
-  self.viewController.gridViewController.menuProvider = self.menuProvider;
+  self.viewController.gridViewController.menuProvider = _menuProvider;
 }
 
 - (void)show {
@@ -165,8 +198,8 @@
 
 - (void)gridViewController:(GridViewController*)gridViewController
        didSelectItemWithID:(NSString*)itemID {
-  [self.delegate inactiveTabsCoordinator:self didSelectItemWithID:itemID];
-  [self.delegate inactiveTabsCoordinatorDidFinish:self];
+  [_delegate inactiveTabsCoordinator:self didSelectItemWithID:itemID];
+  [_delegate inactiveTabsCoordinatorDidFinish:self];
 }
 
 - (void)gridViewController:(GridViewController*)gridViewController
@@ -248,7 +281,7 @@
 #pragma mark - InactiveTabsCommands
 
 - (void)inactiveTabsExplicitlyDisabledByUser {
-  [self.delegate inactiveTabsCoordinatorDidFinish:self];
+  [_delegate inactiveTabsCoordinatorDidFinish:self];
 }
 
 #pragma mark - InactiveTabsUserEducationCoordinatorDelegate
@@ -272,7 +305,7 @@
 
 - (void)inactiveTabsViewControllerDidTapBackButton:
     (InactiveTabsViewController*)inactiveTabsViewController {
-  [self.delegate inactiveTabsCoordinatorDidFinish:self];
+  [_delegate inactiveTabsCoordinatorDidFinish:self];
 }
 
 - (void)inactiveTabsViewController:
@@ -362,7 +395,7 @@
 
 // Called when the user confirmed wanting to close all inactive tabs.
 - (void)closeAllInactiveTabs {
-  [self.delegate inactiveTabsCoordinatorDidFinish:self];
+  [_delegate inactiveTabsCoordinatorDidFinish:self];
   [self.mediator closeAllItems];
 }
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.h
index c7338f64..ffe77067 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.h
@@ -7,38 +7,48 @@
 
 #import <Foundation/Foundation.h>
 
+#import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_commands.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_image_data_source.h"
 
 @protocol InactiveTabsCommands;
 @protocol InactiveTabsInfoConsumer;
 class PrefService;
-@class SnapshotCache;
+class SnapshotBrowserAgent;
+class SessionRestorationBrowserAgent;
 @protocol TabCollectionConsumer;
 class WebStateList;
 
+namespace sessions {
+class TabRestoreService;
+}  // namespace sessions
+
 // This mediator provides data to the Inactive Tabs grid and handles
 // interactions.
-@interface InactiveTabsMediator : NSObject <GridImageDataSource>
+@interface InactiveTabsMediator : NSObject <GridCommands, GridImageDataSource>
 
-// Initializer with `consumer` as the receiver of `webStateList` updates.
-- (instancetype)
-    initWithConsumer:
-        (id<TabCollectionConsumer, InactiveTabsInfoConsumer>)consumer
-      commandHandler:(id<InactiveTabsCommands>)commandHandler
-        webStateList:(WebStateList*)webStateList
-         prefService:(PrefService*)prefService
-       snapshotCache:(SnapshotCache*)snapshotCache NS_DESIGNATED_INITIALIZER;
+// Initializer with:
+// `consumer` as the receiver of `webStateList` updates.
+// `prefService` the preference service from the application context.
+// `sessionRestorationAgent` the session restoration browser agent from the
+// inactive browser. `snapshotAgent` the snapshot browser agent from the
+// inactive browser. `tabRestoreService` the service that holds the recently
+// closed tabs.
+- (instancetype)initWithConsumer:
+                    (id<TabCollectionConsumer, InactiveTabsInfoConsumer>)
+                        consumer
+                  commandHandler:(id<InactiveTabsCommands>)commandHandler
+                    webStateList:(WebStateList*)webStateList
+                     prefService:(PrefService*)prefService
+         sessionRestorationAgent:
+             (SessionRestorationBrowserAgent*)sessionRestorationAgent
+                   snapshotAgent:(SnapshotBrowserAgent*)snapshotAgent
+               tabRestoreService:(sessions::TabRestoreService*)tabRestoreService
+    NS_DESIGNATED_INITIALIZER;
 - (instancetype)init NS_UNAVAILABLE;
 
 // Returns the number of items pushed to the consumer.
 - (NSInteger)numberOfItems;
 
-// Tells the receiver to close the item with the `itemID` identifier.
-- (void)closeItemWithID:(NSString*)itemID;
-
-// Tells the receiver to close all items of the web state list.
-- (void)closeAllItems;
-
 // Disconnects the mediator.
 - (void)disconnect;
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.mm
index 86f04a3..b46768f8 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.mm
@@ -11,8 +11,11 @@
 #import "components/prefs/ios/pref_observer_bridge.h"
 #import "components/prefs/pref_change_registrar.h"
 #import "components/prefs/pref_service.h"
+#import "components/sessions/core/tab_restore_service.h"
 #import "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/prefs/pref_names.h"
+#import "ios/chrome/browser/sessions/session_restoration_browser_agent.h"
+#import "ios/chrome/browser/sessions/session_window_ios.h"
 #import "ios/chrome/browser/snapshots/snapshot_browser_agent.h"
 #import "ios/chrome/browser/snapshots/snapshot_cache.h"
 #import "ios/chrome/browser/snapshots/snapshot_cache_observer.h"
@@ -108,24 +111,43 @@
   PrefChangeRegistrar _prefChangeRegistrar;
   // The short-term cache for grid thumbnails.
   NSMutableDictionary<NSString*, UIImage*>* _appearanceCache;
+  // The saved session window just before close all tabs from regular tab grid
+  // is called.
+  SessionWindowIOS* _closedSessionWindow;
+  // The number of tabs in `_closedSessionWindow` that are synced by
+  // TabRestoreService.
+  int _syncedClosedTabsCount;
+  // Session restoration agent.
+  SessionRestorationBrowserAgent* _sessionRestorationAgent;
+  // Snapshot agent.
+  SnapshotBrowserAgent* _snapshotAgent;
+  // TabRestoreService holds the recently closed tabs.
+  sessions::TabRestoreService* _tabRestoreService;
 }
 
 @end
 
 @implementation InactiveTabsMediator
 
-- (instancetype)initWithConsumer:
-                    (id<TabCollectionConsumer, InactiveTabsInfoConsumer>)
-                        consumer
-                  commandHandler:(id<InactiveTabsCommands>)commandHandler
-                    webStateList:(WebStateList*)webStateList
-                     prefService:(PrefService*)prefService
-                   snapshotCache:(SnapshotCache*)snapshotCache {
-  DCHECK(IsInactiveTabsEnabled());
-  DCHECK(consumer);
-  DCHECK(commandHandler);
-  DCHECK(webStateList);
-  DCHECK(prefService);
+- (instancetype)
+           initWithConsumer:
+               (id<TabCollectionConsumer, InactiveTabsInfoConsumer>)consumer
+             commandHandler:(id<InactiveTabsCommands>)commandHandler
+               webStateList:(WebStateList*)webStateList
+                prefService:(PrefService*)prefService
+    sessionRestorationAgent:
+        (SessionRestorationBrowserAgent*)sessionRestorationAgent
+              snapshotAgent:(SnapshotBrowserAgent*)snapshotAgent
+          tabRestoreService:(sessions::TabRestoreService*)tabRestoreService {
+  CHECK(IsInactiveTabsEnabled());
+  CHECK(consumer);
+  CHECK(commandHandler);
+  CHECK(webStateList);
+  CHECK(prefService);
+  CHECK(sessionRestorationAgent);
+  CHECK(snapshotAgent);
+  CHECK(snapshotAgent->snapshot_cache());
+  CHECK(tabRestoreService);
   self = [super init];
   if (self) {
     _consumer = consumer;
@@ -163,10 +185,14 @@
         _prefService->GetInteger(prefs::kInactiveTabsTimeThreshold);
     [_consumer updateInactiveTabsDaysThreshold:daysThreshold];
 
-    _snapshotCache = snapshotCache;
+    _snapshotCache = snapshotAgent->snapshot_cache();
     [_snapshotCache addObserver:self];
 
     _appearanceCache = [[NSMutableDictionary alloc] init];
+
+    _sessionRestorationAgent = sessionRestorationAgent;
+    _snapshotAgent = snapshotAgent;
+    _tabRestoreService = tabRestoreService;
   }
   return self;
 }
@@ -179,22 +205,6 @@
   return _webStateList->count();
 }
 
-- (void)closeItemWithID:(NSString*)itemID {
-  // TODO(crbug.com/1418021): Add metrics when the user closes an inactive tab.
-  int index = GetTabIndex(_webStateList, WebStateSearchCriteria{
-                                             .identifier = itemID,
-                                         });
-  if (index != WebStateList::kInvalidIndex) {
-    _webStateList->CloseWebStateAt(index, WebStateList::CLOSE_USER_ACTION);
-  }
-}
-
-- (void)closeAllItems {
-  // TODO(crbug.com/1418021): Add metrics when the user closes all inactive
-  // tabs.
-  _webStateList->CloseAllWebStates(WebStateList::CLOSE_USER_ACTION);
-}
-
 - (void)disconnect {
   _consumer = nil;
   _scopedWebStateObservation.reset();
@@ -206,7 +216,11 @@
   _prefObserverBridge.reset();
   _prefService = nullptr;
   [_snapshotCache removeObserver:self];
-  _appearanceCache = nil;
+  _snapshotCache = nullptr;
+  _appearanceCache = nullptr;
+  _sessionRestorationAgent = nullptr;
+  [self discardSavedClosedItems];
+  _snapshotAgent = nullptr;
 }
 
 #pragma mark - CRWWebStateObserver
@@ -348,15 +362,15 @@
     didInsertWebState:(web::WebState*)webState
               atIndex:(int)index
            activating:(BOOL)activating {
-  // Insertions are only supported for iPad multiwindow support when changing
-  // the user settings for Inactive Tabs (i.e. when picking a longer inactivity
-  // threshold).
-  DCHECK_EQ(ui::GetDeviceFormFactor(), ui::DEVICE_FORM_FACTOR_TABLET);
   DCHECK_EQ(_webStateList, webStateList);
   if (_webStateList->IsBatchInProgress()) {
     // Updates are handled in the batch operation observer methods.
     return;
   }
+  // Insertions are only supported for iPad multiwindow support when changing
+  // the user settings for Inactive Tabs (i.e. when picking a longer inactivity
+  // threshold).
+  DCHECK_EQ(ui::GetDeviceFormFactor(), ui::DEVICE_FORM_FACTOR_TABLET);
 
   TabSwitcherItem* item =
       [[WebStateTabSwitcherItem alloc] initWithWebState:webState];
@@ -369,14 +383,14 @@
      didMoveWebState:(web::WebState*)webState
            fromIndex:(int)fromIndex
              toIndex:(int)toIndex {
-  NOTREACHED();
+  NOTREACHED_NORETURN();
 }
 
 - (void)webStateList:(WebStateList*)webStateList
     didReplaceWebState:(web::WebState*)oldWebState
           withWebState:(web::WebState*)newWebState
                atIndex:(int)index {
-  NOTREACHED();
+  NOTREACHED_NORETURN();
 }
 
 - (void)webStateList:(WebStateList*)webStateList
@@ -418,7 +432,7 @@
 - (void)webStateList:(WebStateList*)webStateList
     didChangePinnedStateForWebState:(web::WebState*)webState
                             atIndex:(int)index {
-  NOTREACHED();
+  NOTREACHED_NORETURN();
 }
 
 - (void)webStateListWillBeginBatchOperation:(WebStateList*)webStateList {
@@ -439,4 +453,139 @@
   _webStateList = nullptr;
 }
 
+#pragma mark - GridCommands
+
+- (void)addNewItem {
+  NOTREACHED_NORETURN();
+}
+
+- (void)insertNewItemAtIndex:(NSUInteger)index {
+  NOTREACHED_NORETURN();
+}
+
+- (BOOL)isItemWithIDSelected:(NSString*)itemID {
+  NOTREACHED_NORETURN();
+}
+
+- (void)moveItemWithID:(NSString*)itemID toIndex:(NSUInteger)index {
+  NOTREACHED_NORETURN();
+}
+
+- (void)closeItemsWithIDs:(NSArray<NSString*>*)itemIDs {
+  NOTREACHED_NORETURN();
+}
+
+- (void)closeAllItems {
+  // TODO(crbug.com/1418021): Add metrics when the user closes all inactive
+  // tabs.
+  _webStateList->CloseAllWebStates(WebStateList::CLOSE_USER_ACTION);
+  _snapshotAgent->RemoveAllSnapshots();
+}
+
+- (void)saveAndCloseAllItems {
+  if (_webStateList->empty()) {
+    return;
+  }
+  // TODO(crbug.com/1418021): Add metrics when the user closes all inactive
+  // tabs from regular tab grid.
+  _closedSessionWindow = SerializeWebStateList(_webStateList);
+  int oldSize = _tabRestoreService ? _tabRestoreService->entries().size() : 0;
+  _webStateList->CloseAllWebStates(WebStateList::CLOSE_USER_ACTION);
+  _syncedClosedTabsCount =
+      _tabRestoreService ? _tabRestoreService->entries().size() - oldSize : 0;
+}
+
+- (void)undoCloseAllItems {
+  if (!_closedSessionWindow) {
+    return;
+  }
+  // TODO(crbug.com/1418021): Add metrics when the user restores all inactive
+  // tabs from regular tab grid.
+  _sessionRestorationAgent->RestoreSessionWindow(
+      _closedSessionWindow, SessionRestorationScope::kRegularOnly);
+
+  _closedSessionWindow = nil;
+  [self removeEntriesFromTabRestoreService];
+  _syncedClosedTabsCount = 0;
+}
+
+- (void)discardSavedClosedItems {
+  if (!_closedSessionWindow) {
+    return;
+  }
+  _syncedClosedTabsCount = 0;
+  _closedSessionWindow = nil;
+  _snapshotAgent->RemoveAllSnapshots();
+}
+
+- (void)
+    showCloseItemsConfirmationActionSheetWithItems:(NSArray<NSString*>*)items
+                                            anchor:
+                                                (UIBarButtonItem*)buttonAnchor {
+  NOTREACHED_NORETURN();
+}
+
+- (void)shareItems:(NSArray<NSString*>*)items
+            anchor:(UIBarButtonItem*)buttonAnchor {
+  NOTREACHED_NORETURN();
+}
+
+- (NSArray<UIMenuElement*>*)addToButtonMenuElementsForItems:
+    (NSArray<NSString*>*)items {
+  NOTREACHED_NORETURN();
+}
+
+- (void)searchItemsWithText:(NSString*)searchText {
+  NOTREACHED_NORETURN();
+}
+
+- (void)resetToAllItems {
+  NOTREACHED_NORETURN();
+}
+
+- (void)fetchSearchHistoryResultsCountForText:(NSString*)searchText
+                                   completion:(void (^)(size_t))completion {
+  NOTREACHED_NORETURN();
+}
+
+#pragma mark - TabCollectionCommands
+
+- (void)selectItemWithID:(NSString*)itemID {
+  NOTREACHED_NORETURN();
+}
+
+- (void)closeItemWithID:(NSString*)itemID {
+  // TODO(crbug.com/1418021): Add metrics when the user closes an inactive tab.
+  int index = GetTabIndex(_webStateList, WebStateSearchCriteria{
+                                             .identifier = itemID,
+                                         });
+  if (index != WebStateList::kInvalidIndex) {
+    _webStateList->CloseWebStateAt(index, WebStateList::CLOSE_USER_ACTION);
+  }
+}
+
+- (void)setPinState:(BOOL)pinState forItemWithIdentifier:(NSString*)identifier {
+  NOTREACHED_NORETURN();
+}
+
+#pragma mark - Private
+
+// Removes `_syncedClosedTabsCount` most recent entries from the
+// TabRestoreService.
+- (void)removeEntriesFromTabRestoreService {
+  if (!_tabRestoreService) {
+    return;
+  }
+  std::vector<SessionID> identifiers;
+  auto iter = _tabRestoreService->entries().begin();
+  auto end = _tabRestoreService->entries().end();
+  for (int i = 0; i < _syncedClosedTabsCount && iter != end; i++) {
+    identifiers.push_back(iter->get()->id);
+    iter++;
+  }
+  for (const SessionID sessionID : identifiers) {
+    _tabRestoreService->RemoveTabEntryById(sessionID);
+  }
+}
+
 @end
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
index f9c48ab..141c57f 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
@@ -72,6 +72,7 @@
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_commands.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_button_mediator.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.h"
+#import "ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/pinned_tabs/pinned_tabs_mediator.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_context_menu/tab_context_menu_helper.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_context_menu/tab_item.h"
@@ -807,6 +808,18 @@
   self.baseViewController.incognitoTabsContextMenuProvider =
       self.incognitoTabContextMenuHelper;
 
+  if (IsInactiveTabsEnabled()) {
+    self.inactiveTabsCoordinator = [[InactiveTabsCoordinator alloc]
+        initWithBaseViewController:self.baseViewController
+                           browser:_inactiveBrowser
+                          delegate:self
+                      menuProvider:self.regularTabContextMenuHelper];
+    [self.inactiveTabsCoordinator start];
+
+    baseViewController.inactiveTabsDelegate =
+        self.inactiveTabsCoordinator.gridCommandsHandler;
+  }
+
   // TODO(crbug.com/845192) : Remove RecentTabsTableViewController dependency on
   // ChromeBrowserState so that we don't need to expose the view controller.
   baseViewController.remoteTabsViewController.browser = self.regularBrowser;
@@ -1119,17 +1132,6 @@
 
 - (void)showInactiveTabs {
   DCHECK(IsInactiveTabsEnabled());
-
-  if (!self.inactiveTabsCoordinator) {
-    self.inactiveTabsCoordinator = [[InactiveTabsCoordinator alloc]
-        initWithBaseViewController:self.baseViewController
-                           browser:_inactiveBrowser];
-    self.inactiveTabsCoordinator.delegate = self;
-    self.inactiveTabsCoordinator.menuProvider =
-        self.regularTabContextMenuHelper;
-    [self.inactiveTabsCoordinator start];
-  }
-
   [self.inactiveTabsCoordinator show];
 }
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.h
index 9378ac8a..537735b 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.h
@@ -130,6 +130,7 @@
 
 // Delegates send updates from the UI layer to the model layer.
 @property(nonatomic, weak) id<GridCommands> regularTabsDelegate;
+@property(nonatomic, weak) id<GridCommands> inactiveTabsDelegate;
 @property(nonatomic, weak) id<GridCommands> incognitoTabsDelegate;
 @property(nonatomic, weak) id<TabCollectionCommands> pinnedTabsDelegate;
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
index 3974dd1..bd693a6 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
@@ -563,6 +563,7 @@
     self.tabGridMode = TabGridModeNormal;
   }
   [self.regularTabsDelegate discardSavedClosedItems];
+  [self.inactiveTabsDelegate discardSavedClosedItems];
   // When the view disappears, the toolbar alpha should be set to 0; either as
   // part of the animation, or directly with -hideToolbars.
   if (animated && self.transitionCoordinator) {
@@ -2808,13 +2809,23 @@
 }
 
 - (void)undoCloseAllItemsForRegularTabs {
+  // This was saved as a stack: first save the inactive tabs, then the active
+  // tabs. So undo in the reverse order: first undo the active tabs, then the
+  // inactive tabs.
   [self.regularTabsDelegate undoCloseAllItems];
+  [self.inactiveTabsDelegate undoCloseAllItems];
+
   self.undoCloseAllAvailable = NO;
   [self configureCloseAllButtonForCurrentPageAndUndoAvailability];
 }
 
 - (void)saveAndCloseAllItemsForRegularTabs {
+  // This was saved as a stack: first save the inactive tabs, then the active
+  // tabs. So undo in the reverse order: first undo the active tabs, then the
+  // inactive tabs.
+  [self.inactiveTabsDelegate saveAndCloseAllItems];
   [self.regularTabsDelegate saveAndCloseAllItems];
+
   self.undoCloseAllAvailable = YES;
   [self configureCloseAllButtonForCurrentPageAndUndoAvailability];
 }
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index f05cee4..5fddcdd 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -313,7 +313,6 @@
     "//ios/chrome/browser/ui/dialogs:unit_tests",
     "//ios/chrome/browser/ui/dialogs:unit_tests_internal",
     "//ios/chrome/browser/ui/download:unit_tests",
-    "//ios/chrome/browser/ui/first_run:unit_tests",
     "//ios/chrome/browser/ui/first_run/tos:unit_tests",
     "//ios/chrome/browser/ui/fullscreen:unit_tests",
     "//ios/chrome/browser/ui/gestures:unit_tests",
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index 5dc34b3a..c42c9dd 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-716d700d01a9f0a0a3a9609f5328a44c7dde8a12
\ No newline at end of file
+6e59a137532eab23645a15a66e00b6226d3f945d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index 231439537..85c8df4 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-2a07cc0b9800d36f28350c25d4482297ed92953d
\ No newline at end of file
+558abe135da2ebe67422d2cd5034ab4fd00684c6
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index e69355e..c5d17fe 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-a1bf8dec14f9a2a1ad0afa80be776070c42b63a6
\ No newline at end of file
+d53c39854fdbd39e9ce00528e424201e290e34ac
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 804761d..ed34376f 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-acab7fecdb7fd1a246723e4a5b4c24aee59f646b
\ No newline at end of file
+0e41795bf4ba564817fe484251e0a84217182d7c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index 5164277..7d3bd25 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-d1a496a316098992b7601c13dd72f09f105e95a6
\ No newline at end of file
+c886c01fcd6cff6fd73cf8aa51bf32812a47ca05
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index a09dd8d8..88279096 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-a51839e0fb1a064f8ad738e0086cb9f0ec5df282
\ No newline at end of file
+7d6eddd6735cd29c029e0747dffb94599de7d7d6
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index 5272a3b..9eb96ba 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-75c34dce3970fb04f0f83f8fb64700bae29bf8f5
\ No newline at end of file
+73bcc7600ce5a6c737d0d9c37eab3ccd481206ec
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index 4eecda421..dc94986b 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-bdf6003b9c45dcdcdfc9cf2ec953b0d39eb4cbcb
\ No newline at end of file
+ff32b5764fa89f81729cc184f6eafb51d891c870
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index c93d9308..46f0e67 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-edb58a90996b2d3daf9f1fc6c014cd02cf72ddb1
\ No newline at end of file
+dc319d9629a929ea9895713cb81f18d9ce03e4fc
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index 0b6963b..98b17a9 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-cdb38d001eb2debee45aa000d10101c1d45531ad
\ No newline at end of file
+52790fe0c0b94d9534c2f30afcafe25da9d293c6
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index c84a05f..9c450ac0 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-a20d2fef73eb02ce0877112993992e48bdddb4e2
\ No newline at end of file
+b69dae0668899de48d191559bc340ab184b1fc47
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index 693f4b0..0a347b7 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-661f0fa802268cf15a0b8904116cb6b7ff1da8e3
\ No newline at end of file
+2ddc7fbc86e7799138953aa2d0ec92b26124c973
\ No newline at end of file
diff --git a/ios/web/content/js_messaging/content_web_frame.h b/ios/web/content/js_messaging/content_web_frame.h
index 1e3024b..95ec3e9 100644
--- a/ios/web/content/js_messaging/content_web_frame.h
+++ b/ios/web/content/js_messaging/content_web_frame.h
@@ -10,7 +10,6 @@
 
 #import "base/cancelable_callback.h"
 #import "base/values.h"
-#import "content/public/browser/global_routing_id.h"
 #import "ios/web/js_messaging/web_frame_internal.h"
 #import "ios/web/public/js_messaging/web_frame.h"
 #import "ios/web/public/web_state_observer.h"
@@ -30,7 +29,7 @@
                         public WebStateObserver {
  public:
   ContentWebFrame(const std::string& web_frame_id,
-                  const content::GlobalRenderFrameHostId& content_id,
+                  content::RenderFrameHost* render_frame_id,
                   ContentWebState* content_web_state);
 
   ContentWebFrame(const ContentWebFrame&) = delete;
@@ -80,19 +79,15 @@
   // Detaches the receiver from the associated  WebState.
   void DetachFromWebState();
 
-  // Returns the RenderFrameHost corresponding to this WebFrame.
-  content::RenderFrameHost* GetRenderFrameHost() const;
-
   // The web frame identifier which uniquely identifies this frame across the
   // application's lifetime.
   std::string web_frame_id_;
 
-  // The content frame identifier which uniquely identifies this frame across
-  // the application's lifetime.
-  content::GlobalRenderFrameHostId content_id_;
-
   // The web state corresponding to the WebContents for this frame.
   raw_ptr<ContentWebState> content_web_state_;
+
+  // The RenderFrameHost corresponding to this frame.
+  raw_ptr<content::RenderFrameHost> render_frame_host_;
 };
 
 }  // namespace web
diff --git a/ios/web/content/js_messaging/content_web_frame.mm b/ios/web/content/js_messaging/content_web_frame.mm
index 7f840be..9a9e355 100644
--- a/ios/web/content/js_messaging/content_web_frame.mm
+++ b/ios/web/content/js_messaging/content_web_frame.mm
@@ -13,13 +13,12 @@
 
 namespace web {
 
-ContentWebFrame::ContentWebFrame(
-    const std::string& web_frame_id,
-    const content::GlobalRenderFrameHostId& content_id,
-    ContentWebState* content_web_state)
+ContentWebFrame::ContentWebFrame(const std::string& web_frame_id,
+                                 content::RenderFrameHost* render_frame_host,
+                                 ContentWebState* content_web_state)
     : web_frame_id_(web_frame_id),
-      content_id_(content_id),
-      content_web_state_(content_web_state) {
+      content_web_state_(content_web_state),
+      render_frame_host_(render_frame_host) {
   content_web_state->AddObserver(this);
 }
 
@@ -35,18 +34,14 @@
   return web_frame_id_;
 }
 
-content::RenderFrameHost* ContentWebFrame::GetRenderFrameHost() const {
-  return content::RenderFrameHost::FromID(content_id_);
-}
-
 bool ContentWebFrame::IsMainFrame() const {
-  return GetRenderFrameHost()->IsInPrimaryMainFrame();
+  return render_frame_host_->IsInPrimaryMainFrame();
 }
 
 GURL ContentWebFrame::GetSecurityOrigin() const {
   // TODO(crbug.com/1423501):  Once GetSecurityOrigin is changed to return an
   // Origin instead of a URL, this should use GetLastCommittedOrigin().
-  return GetRenderFrameHost()->GetLastCommittedURL();
+  return render_frame_host_->GetLastCommittedURL();
 }
 
 BrowserState* ContentWebFrame::GetBrowserState() {
diff --git a/ios/web/content/js_messaging/content_web_frames_manager.mm b/ios/web/content/js_messaging/content_web_frames_manager.mm
index ab4861b..d88fb9e7 100644
--- a/ios/web/content/js_messaging/content_web_frames_manager.mm
+++ b/ios/web/content/js_messaging/content_web_frames_manager.mm
@@ -66,7 +66,7 @@
   // received from the frame, since features expect this.
   std::string web_frame_id = ios::device_util::GetRandomId();
   auto web_frame = std::make_unique<ContentWebFrame>(
-      web_frame_id, render_frame_host->GetGlobalId(), content_web_state_);
+      web_frame_id, render_frame_host, content_web_state_);
   WebFrame* new_frame = web_frame.get();
   web_frames_[web_frame_id] = std::move(web_frame);
   content_to_web_id_map_[render_frame_host->GetGlobalId()] = web_frame_id;
diff --git a/media/audio/clockless_audio_sink.cc b/media/audio/clockless_audio_sink.cc
index d0d1311f..0f5e861d 100644
--- a/media/audio/clockless_audio_sink.cc
+++ b/media/audio/clockless_audio_sink.cc
@@ -14,7 +14,6 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/threading/simple_thread.h"
 #include "media/base/audio_glitch_info.h"
-#include "media/base/audio_hash.h"
 
 namespace media {
 
@@ -48,9 +47,9 @@
     return playback_time_;
   }
 
-  std::string GetAudioHash() {
+  const AudioHash& GetAudioHash() const {
     DCHECK(audio_hash_);
-    return audio_hash_->ToString();
+    return *audio_hash_;
   }
 
  private:
@@ -164,8 +163,8 @@
   hashing_ = true;
 }
 
-std::string ClocklessAudioSink::GetAudioHashForTesting() {
-  return thread_ && hashing_ ? thread_->GetAudioHash() : std::string();
+const AudioHash& ClocklessAudioSink::GetAudioHashForTesting() const {
+  return thread_->GetAudioHash();
 }
 
 void ClocklessAudioSink::SetIsOptimizedForHardwareParametersForTesting(
diff --git a/media/audio/clockless_audio_sink.h b/media/audio/clockless_audio_sink.h
index c865cff..7a35a69a 100644
--- a/media/audio/clockless_audio_sink.h
+++ b/media/audio/clockless_audio_sink.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/time/time.h"
+#include "media/base/audio_hash.h"
 #include "media/base/audio_renderer_sink.h"
 
 namespace media {
@@ -45,7 +46,7 @@
   void StartAudioHashForTesting();
 
   // Returns the hash of all audio frames seen since construction.
-  std::string GetAudioHashForTesting();
+  const AudioHash& GetAudioHashForTesting() const;
 
   void SetIsOptimizedForHardwareParametersForTesting(bool value);
 
diff --git a/media/audio/null_audio_sink.cc b/media/audio/null_audio_sink.cc
index bd5a1ce..359f070 100644
--- a/media/audio/null_audio_sink.cc
+++ b/media/audio/null_audio_sink.cc
@@ -127,8 +127,8 @@
   audio_hash_ = std::make_unique<AudioHash>();
 }
 
-std::string NullAudioSink::GetAudioHashForTesting() {
-  return audio_hash_ ? audio_hash_->ToString() : std::string();
+const AudioHash& NullAudioSink::GetAudioHashForTesting() const {
+  return *audio_hash_;
 }
 
 }  // namespace media
diff --git a/media/audio/null_audio_sink.h b/media/audio/null_audio_sink.h
index 7aec9ffa..d44c8a7 100644
--- a/media/audio/null_audio_sink.h
+++ b/media/audio/null_audio_sink.h
@@ -47,7 +47,7 @@
   void StartAudioHashForTesting();
 
   // Returns the hash of all audio frames seen since construction.
-  std::string GetAudioHashForTesting();
+  const AudioHash& GetAudioHashForTesting() const;
 
  protected:
   ~NullAudioSink() override;
diff --git a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
index 89db035..ba3b6499 100644
--- a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
@@ -713,8 +713,7 @@
      * @return the key request.
      */
     private MediaDrm.KeyRequest getKeyRequest(SessionId sessionId, byte[] data, String mime,
-            int keyType, HashMap<String, String> optionalParameters)
-            throws android.media.NotProvisionedException {
+            int keyType, HashMap<String, String> optionalParameters) {
         assert mMediaDrm != null;
         assert mMediaCryptoSession != null;
         assert !mProvisioningPending;
@@ -730,6 +729,12 @@
                     keyType == MediaDrm.KEY_TYPE_RELEASE ? sessionId.keySetId() : sessionId.drmId();
             assert scopeId != null;
             request = mMediaDrm.getKeyRequest(scopeId, data, mime, keyType, optionalParameters);
+        } catch (android.media.NotProvisionedException e) {
+            Log.e(TAG,
+                    "The origin needs re-provision. Unprovision the origin so that the next "
+                            + "MediaDrmBridge creation can trigger the provision flow.",
+                    e);
+            unprovision();
         } catch (java.lang.IllegalStateException e) {
             // We've seen both MediaDrmStateException and MediaDrmResetException happening.
             // Since both are IllegalStateExceptions, so they will be handled here.
@@ -785,40 +790,38 @@
         assert mMediaCryptoSession != null;
         assert !mProvisioningPending;
 
-        boolean newSessionOpened = false;
-        SessionId sessionId = null;
+        byte[] drmId = null;
         try {
-            byte[] drmId = openSession();
-            if (drmId == null) {
-                onPromiseRejected(promiseId, "Open session failed.");
-                return;
-            }
-            newSessionOpened = true;
-            assert keyType == MediaDrm.KEY_TYPE_STREAMING || keyType == MediaDrm.KEY_TYPE_OFFLINE;
-            sessionId = (keyType == MediaDrm.KEY_TYPE_OFFLINE)
-                    ? SessionId.createPersistentSessionId(drmId)
-                    : SessionId.createTemporarySessionId(drmId);
-
-            MediaDrm.KeyRequest request =
-                    getKeyRequest(sessionId, initData, mime, keyType, optionalParameters);
-            if (request == null) {
-                closeSessionNoException(sessionId);
-                onPromiseRejected(promiseId, "Generate request failed.");
-                return;
-            }
-
-            // Success!
-            Log.d(TAG, "createSession(): Session (%s) created.", sessionId.toHexString());
-            onPromiseResolvedWithSession(promiseId, sessionId);
-            onSessionMessage(sessionId, request);
-            mSessionManager.put(sessionId, mime, keyType);
+            drmId = openSession();
         } catch (android.media.NotProvisionedException e) {
             Log.e(TAG, "Device not provisioned", e);
-            if (newSessionOpened) {
-                closeSessionNoException(sessionId);
-            }
             onPromiseRejected(promiseId, "Device not provisioned during createSession().");
+            return;
         }
+
+        if (drmId == null) {
+            onPromiseRejected(promiseId, "Open session failed.");
+            return;
+        }
+
+        assert keyType == MediaDrm.KEY_TYPE_STREAMING || keyType == MediaDrm.KEY_TYPE_OFFLINE;
+        SessionId sessionId = (keyType == MediaDrm.KEY_TYPE_OFFLINE)
+                ? SessionId.createPersistentSessionId(drmId)
+                : SessionId.createTemporarySessionId(drmId);
+
+        MediaDrm.KeyRequest request =
+                getKeyRequest(sessionId, initData, mime, keyType, optionalParameters);
+        if (request == null) {
+            closeSessionNoException(sessionId);
+            onPromiseRejected(promiseId, "Generate request failed.");
+            return;
+        }
+
+        // Success!
+        Log.d(TAG, "createSession(): Session (%s) created.", sessionId.toHexString());
+        onPromiseResolvedWithSession(promiseId, sessionId);
+        onSessionMessage(sessionId, request);
+        mSessionManager.put(sessionId, mime, keyType);
     }
 
     /**
@@ -959,8 +962,8 @@
 
             return;
         } catch (android.media.NotProvisionedException e) {
-            // TODO(xhwang): Should we handle this?
             Log.e(TAG, "failed to provide key response", e);
+            unprovision();
         } catch (android.media.DeniedByServerException e) {
             Log.e(TAG, "failed to provide key response", e);
         } catch (java.lang.IllegalStateException e) {
@@ -1116,28 +1119,23 @@
     }
 
     private void doRemoveSession(SessionId sessionId, String mimeType, long promiseId) {
-        try {
-            // Get key release request.
-            MediaDrm.KeyRequest request =
-                    getKeyRequest(sessionId, null, mimeType, MediaDrm.KEY_TYPE_RELEASE, null);
+        // Get key release request.
+        MediaDrm.KeyRequest request =
+                getKeyRequest(sessionId, null, mimeType, MediaDrm.KEY_TYPE_RELEASE, null);
 
-            if (request == null) {
-                onPromiseRejected(promiseId, "Fail to generate key release request");
-                return;
-            }
-
-            // According to EME spec:
-            // https://www.w3.org/TR/encrypted-media/#dom-mediakeysession-remove
-            // 5.5 ... run the Queue a "message" Event ...
-            // 5.6 Resolve promise
-            // Since event is queued, JS will receive event after promise is
-            // resolved. So resolve the promise before firing the event here.
-            onPromiseResolved(promiseId);
-            onSessionMessage(sessionId, request);
-        } catch (android.media.NotProvisionedException e) {
-            Log.e(TAG, "removeSession called on unprovisioned device");
-            onPromiseRejected(promiseId, "Unknown failure");
+        if (request == null) {
+            onPromiseRejected(promiseId, "Fail to generate key release request");
+            return;
         }
+
+        // According to EME spec:
+        // https://www.w3.org/TR/encrypted-media/#dom-mediakeysession-remove
+        // 5.5 ... run the Queue a "message" Event ...
+        // 5.6 Resolve promise
+        // Since event is queued, JS will receive event after promise is
+        // resolved. So resolve the promise before firing the event here.
+        onPromiseResolved(promiseId);
+        onSessionMessage(sessionId, request);
     }
 
     /**
@@ -1404,13 +1402,8 @@
             switch (event) {
                 case MediaDrm.EVENT_KEY_REQUIRED:
                     Log.d(TAG, "MediaDrm.EVENT_KEY_REQUIRED");
-                    try {
-                        request = getKeyRequest(sessionId, data, sessionInfo.mimeType(),
-                                sessionInfo.keyType(), null);
-                    } catch (android.media.NotProvisionedException e) {
-                        Log.e(TAG, "Device not provisioned", e);
-                        return;
-                    }
+                    request = getKeyRequest(
+                            sessionId, data, sessionInfo.mimeType(), sessionInfo.keyType(), null);
                     if (request != null) {
                         onSessionMessage(sessionId, request);
                     } else {
@@ -1424,15 +1417,8 @@
                 // (b/271451225) This event is generated during ClearKey implementation in Android.
                 case MediaDrm.EVENT_VENDOR_DEFINED:
                     Log.d(TAG, "MediaDrm.EVENT_VENDOR_DEFINED");
-                    try {
-                        request = getKeyRequest(sessionId, data, sessionInfo.mimeType(),
-                                sessionInfo.keyType(), null);
-                    } catch (android.media.NotProvisionedException e) {
-                        // Device does not need to be provisioned for Clear Key, shouldn't hit this
-                        // error.
-                        Log.e(TAG, "Device not provisioned", e);
-                        return;
-                    }
+                    request = getKeyRequest(
+                            sessionId, data, sessionInfo.mimeType(), sessionInfo.keyType(), null);
                     if (request != null) {
                         onSessionMessage(sessionId, request);
                     } else {
diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc
index 23953b6..5d24cd13 100644
--- a/media/cdm/aes_decryptor_unittest.cc
+++ b/media/cdm/aes_decryptor_unittest.cc
@@ -205,7 +205,7 @@
     const std::vector<SubsampleEntry>& subsample_entries) {
   DCHECK(!data.empty());
   DCHECK(!iv.empty());
-  scoped_refptr<DecoderBuffer> encrypted_buffer(new DecoderBuffer(data.size()));
+  auto encrypted_buffer = base::MakeRefCounted<DecoderBuffer>(data.size());
   memcpy(encrypted_buffer->writable_data(), data.data(), data.size());
   std::string key_id_string(key_id.begin(), key_id.end());
   std::string iv_string(iv.begin(), iv.end());
@@ -217,7 +217,7 @@
 scoped_refptr<DecoderBuffer> CreateClearBuffer(
     const std::vector<uint8_t>& data) {
   DCHECK(!data.empty());
-  scoped_refptr<DecoderBuffer> encrypted_buffer(new DecoderBuffer(data.size()));
+  auto encrypted_buffer = base::MakeRefCounted<DecoderBuffer>(data.size());
   memcpy(encrypted_buffer->writable_data(), data.data(), data.size());
   return encrypted_buffer;
 }
diff --git a/media/cdm/default_cdm_factory.cc b/media/cdm/default_cdm_factory.cc
index ace2bf9d..0b34481 100644
--- a/media/cdm/default_cdm_factory.cc
+++ b/media/cdm/default_cdm_factory.cc
@@ -45,9 +45,9 @@
     return;
   }
 
-  scoped_refptr<ContentDecryptionModule> cdm(
-      new AesDecryptor(session_message_cb, session_closed_cb,
-                       session_keys_change_cb, session_expiration_update_cb));
+  auto cdm = base::MakeRefCounted<AesDecryptor>(
+      session_message_cb, session_closed_cb, session_keys_change_cb,
+      session_expiration_update_cb);
   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
       FROM_HERE, base::BindOnce(std::move(cdm_created_cb), cdm, ""));
 }
diff --git a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
index 795dcaa..4d6306c 100644
--- a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
+++ b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
@@ -309,7 +309,7 @@
 ClearKeyCdm::ClearKeyCdm(HostInterface* host, const std::string& key_system)
     : host_interface_version_(HostInterface::kVersion),
       cdm_host_proxy_(std::make_unique<CdmHostProxyImpl<HostInterface>>(host)),
-      cdm_(new ClearKeyPersistentSessionCdm(
+      cdm_(base::MakeRefCounted<ClearKeyPersistentSessionCdm>(
           cdm_host_proxy_.get(),
           base::BindRepeating(&ClearKeyCdm::OnSessionMessage,
                               base::Unretained(this)),
diff --git a/media/cdm/library_cdm/mock_library_cdm.cc b/media/cdm/library_cdm/mock_library_cdm.cc
index df90fd6..f46dbd4 100644
--- a/media/cdm/library_cdm/mock_library_cdm.cc
+++ b/media/cdm/library_cdm/mock_library_cdm.cc
@@ -25,7 +25,8 @@
 template <typename HostInterface>
 MockLibraryCdm::MockLibraryCdm(HostInterface* host,
                                const std::string& key_system)
-    : cdm_host_proxy_(new CdmHostProxyImpl<HostInterface>(host)) {}
+    : cdm_host_proxy_(std::make_unique<CdmHostProxyImpl<HostInterface>>(host)) {
+}
 
 MockLibraryCdm::~MockLibraryCdm() {
   DCHECK(g_mock_library_cdm);
diff --git a/media/filters/android/media_codec_audio_decoder.cc b/media/filters/android/media_codec_audio_decoder.cc
index dc309d33..5d98dce 100644
--- a/media/filters/android/media_codec_audio_decoder.cc
+++ b/media/filters/android/media_codec_audio_decoder.cc
@@ -36,7 +36,7 @@
       channel_layout_(CHANNEL_LAYOUT_NONE),
       sample_rate_(0),
       media_crypto_context_(nullptr),
-      pool_(new AudioBufferMemoryPool()) {
+      pool_(base::MakeRefCounted<AudioBufferMemoryPool>()) {
   DVLOG(1) << __func__;
 }
 
@@ -199,6 +199,11 @@
   DecodeCB bound_decode_cb =
       base::BindPostTaskToCurrentDefault(std::move(decode_cb));
 
+  if (!DecoderBuffer::DoSubsamplesMatch(*buffer)) {
+    std::move(bound_decode_cb).Run(DecoderStatus::Codes::kFailed);
+    return;
+  }
+
   if (!buffer->end_of_stream() && buffer->timestamp() == kNoTimestamp) {
     DVLOG(2) << __func__ << " " << buffer->AsHumanReadableString()
              << ": no timestamp, skipping this buffer";
diff --git a/media/filters/android/video_frame_extractor.cc b/media/filters/android/video_frame_extractor.cc
index 0997aba..27433d3 100644
--- a/media/filters/android/video_frame_extractor.cc
+++ b/media/filters/android/video_frame_extractor.cc
@@ -93,18 +93,20 @@
   switch (video_stream_->codecpar->codec_id) {
     case AV_CODEC_ID_H264:
       video_config_.SetExtraData(std::vector<uint8_t>());
-      bitstream_converter_.reset(
-          new FFmpegH264ToAnnexBBitstreamConverter(video_stream_->codecpar));
+      bitstream_converter_ =
+          std::make_unique<FFmpegH264ToAnnexBBitstreamConverter>(
+              video_stream_->codecpar);
       break;
 #if BUILDFLAG(ENABLE_PLATFORM_HEVC)
     case AV_CODEC_ID_HEVC:
-      bitstream_converter_.reset(
-          new FFmpegH265ToAnnexBBitstreamConverter(video_stream_->codecpar));
+      bitstream_converter_ =
+          std::make_unique<FFmpegH265ToAnnexBBitstreamConverter>(
+              video_stream_->codecpar);
       break;
 #endif
     case AV_CODEC_ID_AAC:
-      bitstream_converter_.reset(
-          new FFmpegAACBitstreamConverter(video_stream_->codecpar));
+      bitstream_converter_ = std::make_unique<FFmpegAACBitstreamConverter>(
+          video_stream_->codecpar);
       break;
     default:
       break;
diff --git a/media/filters/audio_decoder_unittest.cc b/media/filters/audio_decoder_unittest.cc
index ca8a2cf..4546a54e 100644
--- a/media/filters/audio_decoder_unittest.cc
+++ b/media/filters/audio_decoder_unittest.cc
@@ -579,15 +579,9 @@
     {AudioCodec::kOpus,
      "sfx-opus.ogg",
      {{
-#if defined(OPUS_FIXED_POINT)
          {0, 13500, "-2.70,-1.41,-0.78,-1.27,-2.56,-3.73,"},
          {13500, 20000, "5.48,5.93,6.05,5.83,5.54,5.46,"},
          {33500, 20000, "-3.44,-3.34,-3.57,-4.11,-4.74,-5.13,"},
-#else
-         {0, 13500, "-2.70,-1.41,-0.78,-1.27,-2.56,-3.73,"},
-         {13500, 20000, "5.48,5.93,6.04,5.83,5.54,5.45,"},
-         {33500, 20000, "-3.45,-3.35,-3.57,-4.12,-4.74,-5.14,"},
-#endif
      }},
      -312,
      48000,
@@ -682,6 +676,12 @@
   }
 }
 
+TEST_P(AudioDecoderTest, DecodeMismatchedSubsamples) {
+  ASSERT_NO_FATAL_FAILURE(Initialize());
+  DecodeBuffer(CreateMismatchedBufferForTest());
+  EXPECT_TRUE(!last_decode_status().is_ok());
+}
+
 TEST_P(AudioDecoderTest, Decode) {
   ASSERT_NO_FATAL_FAILURE(Initialize());
   Decode();
@@ -695,7 +695,7 @@
 
 TEST_P(AudioDecoderTest, NoTimestamp) {
   ASSERT_NO_FATAL_FAILURE(Initialize());
-  scoped_refptr<DecoderBuffer> buffer(new DecoderBuffer(0));
+  auto buffer = base::MakeRefCounted<DecoderBuffer>(0);
   buffer->set_timestamp(kNoTimestamp);
   DecodeBuffer(std::move(buffer));
   EXPECT_THAT(last_decode_status(), IsDecodeErrorStatus());
diff --git a/media/filters/audio_renderer_algorithm_unittest.cc b/media/filters/audio_renderer_algorithm_unittest.cc
index b26fd87..650a655 100644
--- a/media/filters/audio_renderer_algorithm_unittest.cc
+++ b/media/filters/audio_renderer_algorithm_unittest.cc
@@ -620,7 +620,7 @@
   std::unique_ptr<AudioBus> a = AudioBus::Create(kChannels, kFrames);
   std::unique_ptr<AudioBus> b = AudioBus::Create(kChannels, kFrames);
 
-  std::unique_ptr<float[]> dot_prod(new float[kChannels]);
+  auto dot_prod = std::make_unique<float[]>(kChannels);
 
   FillWithSquarePulseTrain(kHalfPulseWidth, 0, 0, a.get());
   FillWithSquarePulseTrain(kHalfPulseWidth, 1, 1, a.get());
@@ -651,7 +651,7 @@
   const int kFramesPerBlock = 3;
   const int kNumBlocks = kFrames - (kFramesPerBlock - 1);
   std::unique_ptr<AudioBus> a = AudioBus::Create(kChannels, kFrames);
-  std::unique_ptr<float[]> energies(new float[kChannels * kNumBlocks]);
+  auto energies = std::make_unique<float[]>(kChannels * kNumBlocks);
   float* ch_left = a->channel(0);
   float* ch_right = a->channel(1);
 
@@ -713,7 +713,7 @@
   ch = target->channel(1);
   memcpy(ch, target_1, sizeof(float) * kFramePerBlock);
 
-  std::unique_ptr<float[]> energy_target(new float[kChannels]);
+  auto energy_target = std::make_unique<float[]>(kChannels);
 
   internal::MultiChannelDotProduct(target.get(), 0, target.get(), 0,
                                    kFramePerBlock, energy_target.get());
@@ -722,8 +722,8 @@
   ASSERT_EQ(2.01f, energy_target[1]);
 
   const int kNumCandidBlocks = kFramesInSearchRegion - (kFramePerBlock - 1);
-  std::unique_ptr<float[]> energy_candid_blocks(
-      new float[kNumCandidBlocks * kChannels]);
+  auto energy_candid_blocks =
+      std::make_unique<float[]>(kNumCandidBlocks * kChannels);
 
   internal::MultiChannelMovingBlockEnergies(
       search_region.get(), kFramePerBlock, energy_candid_blocks.get());
diff --git a/media/filters/audio_timestamp_validator_unittest.cc b/media/filters/audio_timestamp_validator_unittest.cc
index cd7b594..862ed551 100644
--- a/media/filters/audio_timestamp_validator_unittest.cc
+++ b/media/filters/audio_timestamp_validator_unittest.cc
@@ -81,7 +81,7 @@
 
   for (int i = 0; i < 100; ++i) {
     // Each buffer's timestamp is kBufferDuration from the previous buffer.
-    scoped_refptr<DecoderBuffer> encoded_buffer = new DecoderBuffer(0);
+    auto encoded_buffer = base::MakeRefCounted<DecoderBuffer>(0);
 
     // Ping-pong between two random offsets to prevent validator from
     // stabilizing timestamp pattern.
@@ -126,7 +126,7 @@
 
   for (int i = 0; i < 100; ++i) {
     // Each buffer's timestamp is kBufferDuration from the previous buffer.
-    scoped_refptr<DecoderBuffer> encoded_buffer = new DecoderBuffer(0);
+    auto encoded_buffer = base::MakeRefCounted<DecoderBuffer>(0);
     encoded_buffer->set_timestamp(i * kBufferDuration);
 
     if (i == 0) {
@@ -172,7 +172,7 @@
     if (i == 50)
       EXPECT_MEDIA_LOG(HasSubstr("timestamp gap detected"));
 
-    scoped_refptr<DecoderBuffer> encoded_buffer = new DecoderBuffer(0);
+    auto encoded_buffer = base::MakeRefCounted<DecoderBuffer>(0);
     encoded_buffer->set_timestamp(i * kBufferDuration + offset);
 
     if (i == 0) {
@@ -219,7 +219,7 @@
     if (i >= output_delay_ + 2)
       offset = i * base::Milliseconds(1);
 
-    scoped_refptr<DecoderBuffer> encoded_buffer = new DecoderBuffer(0);
+    auto encoded_buffer = base::MakeRefCounted<DecoderBuffer>(0);
     encoded_buffer->set_timestamp((i * kBufferDuration) + offset);
 
     // Expect gap warnings to start when drift hits 50 milliseconds. Warnings
diff --git a/media/filters/audio_video_metadata_extractor_unittest.cc b/media/filters/audio_video_metadata_extractor_unittest.cc
index 42df821..94d54644 100644
--- a/media/filters/audio_video_metadata_extractor_unittest.cc
+++ b/media/filters/audio_video_metadata_extractor_unittest.cc
@@ -26,8 +26,7 @@
   FileDataSource source;
   EXPECT_TRUE(source.Initialize(GetTestDataFilePath(filename)));
 
-  std::unique_ptr<AudioVideoMetadataExtractor> extractor(
-      new AudioVideoMetadataExtractor);
+  auto extractor = std::make_unique<AudioVideoMetadataExtractor>();
   bool extracted = extractor->Extract(&source, extract_attached_images);
   EXPECT_EQ(expected_result, extracted);
 
diff --git a/media/filters/blocking_url_protocol_unittest.cc b/media/filters/blocking_url_protocol_unittest.cc
index 7040507..058b6a2 100644
--- a/media/filters/blocking_url_protocol_unittest.cc
+++ b/media/filters/blocking_url_protocol_unittest.cc
@@ -21,7 +21,7 @@
 class BlockingUrlProtocolTest : public testing::Test {
  public:
   BlockingUrlProtocolTest()
-      : url_protocol_(new BlockingUrlProtocol(
+      : url_protocol_(std::make_unique<BlockingUrlProtocol>(
             &data_source_,
             base::BindRepeating(&BlockingUrlProtocolTest::OnDataSourceError,
                                 base::Unretained(this)))) {
diff --git a/media/filters/dav1d_video_decoder_unittest.cc b/media/filters/dav1d_video_decoder_unittest.cc
index b5d1bf1c..ccf707b 100644
--- a/media/filters/dav1d_video_decoder_unittest.cc
+++ b/media/filters/dav1d_video_decoder_unittest.cc
@@ -39,7 +39,7 @@
 class Dav1dVideoDecoderTest : public testing::Test {
  public:
   Dav1dVideoDecoderTest()
-      : decoder_(new Dav1dVideoDecoder(&media_log_)),
+      : decoder_(std::make_unique<Dav1dVideoDecoder>(&media_log_)),
         i_frame_buffer_(ReadTestDataFile("av1-I-frame-320x240")) {}
 
   Dav1dVideoDecoderTest(const Dav1dVideoDecoderTest&) = delete;
diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc
index e212dc9..926d869 100644
--- a/media/filters/decrypting_audio_decoder_unittest.cc
+++ b/media/filters/decrypting_audio_decoder_unittest.cc
@@ -46,7 +46,8 @@
 // Create a fake non-empty encrypted buffer.
 static scoped_refptr<DecoderBuffer> CreateFakeEncryptedBuffer() {
   const int buffer_size = 16;  // Need a non-empty buffer;
-  scoped_refptr<DecoderBuffer> buffer(new DecoderBuffer(buffer_size));
+  scoped_refptr<DecoderBuffer> buffer(
+      base::MakeRefCounted<DecoderBuffer>(buffer_size));
   buffer->set_decrypt_config(DecryptConfig::CreateCencConfig(
       std::string(reinterpret_cast<const char*>(kFakeKeyId),
                   std::size(kFakeKeyId)),
@@ -58,11 +59,11 @@
 class DecryptingAudioDecoderTest : public testing::Test {
  public:
   DecryptingAudioDecoderTest()
-      : decoder_(new DecryptingAudioDecoder(
+      : decoder_(std::make_unique<DecryptingAudioDecoder>(
             task_environment_.GetMainThreadTaskRunner(),
             &media_log_)),
-        cdm_context_(new StrictMock<MockCdmContext>()),
-        decryptor_(new StrictMock<MockDecryptor>()),
+        cdm_context_(std::make_unique<StrictMock<MockCdmContext>>()),
+        decryptor_(std::make_unique<StrictMock<MockDecryptor>>()),
         num_decrypt_and_decode_calls_(0),
         num_frames_in_decryptor_(0),
         encrypted_buffer_(CreateFakeEncryptedBuffer()),
diff --git a/media/filters/decrypting_demuxer_stream_unittest.cc b/media/filters/decrypting_demuxer_stream_unittest.cc
index fbae031..39a83a6 100644
--- a/media/filters/decrypting_demuxer_stream_unittest.cc
+++ b/media/filters/decrypting_demuxer_stream_unittest.cc
@@ -45,7 +45,7 @@
 // true, the buffer is not encrypted (signaled by an empty IV).
 static scoped_refptr<DecoderBuffer> CreateFakeEncryptedStreamBuffer(
     bool is_clear) {
-  scoped_refptr<DecoderBuffer> buffer(new DecoderBuffer(kFakeBufferSize));
+  auto buffer = base::MakeRefCounted<DecoderBuffer>(kFakeBufferSize);
   std::string iv = is_clear
                        ? std::string()
                        : std::string(reinterpret_cast<const char*>(kFakeIv),
@@ -73,22 +73,23 @@
 class DecryptingDemuxerStreamTest : public testing::Test {
  public:
   DecryptingDemuxerStreamTest()
-      : demuxer_stream_(new DecryptingDemuxerStream(
+      : demuxer_stream_(std::make_unique<DecryptingDemuxerStream>(
             task_environment_.GetMainThreadTaskRunner(),
             &media_log_,
             base::BindRepeating(&DecryptingDemuxerStreamTest::OnWaiting,
                                 base::Unretained(this)))),
-        cdm_context_(new StrictMock<MockCdmContext>()),
-        decryptor_(new StrictMock<MockDecryptor>()),
+        cdm_context_(std::make_unique<StrictMock<MockCdmContext>>()),
+        decryptor_(std::make_unique<StrictMock<MockDecryptor>>()),
         is_initialized_(false),
-        input_audio_stream_(
-            new StrictMock<MockDemuxerStream>(DemuxerStream::AUDIO)),
-        input_video_stream_(
-            new StrictMock<MockDemuxerStream>(DemuxerStream::VIDEO)),
-        clear_buffer_(new DecoderBuffer(kFakeBufferSize)),
+        input_audio_stream_(std::make_unique<StrictMock<MockDemuxerStream>>(
+            DemuxerStream::AUDIO)),
+        input_video_stream_(std::make_unique<StrictMock<MockDemuxerStream>>(
+            DemuxerStream::VIDEO)),
+        clear_buffer_(base::MakeRefCounted<DecoderBuffer>(kFakeBufferSize)),
         clear_encrypted_stream_buffer_(CreateFakeEncryptedStreamBuffer(true)),
         encrypted_buffer_(CreateFakeEncryptedStreamBuffer(false)),
-        decrypted_buffer_(new DecoderBuffer(kFakeBufferSize)) {}
+        decrypted_buffer_(
+            base::MakeRefCounted<DecoderBuffer>(kFakeBufferSize)) {}
 
   DecryptingDemuxerStreamTest(const DecryptingDemuxerStreamTest&) = delete;
   DecryptingDemuxerStreamTest& operator=(const DecryptingDemuxerStreamTest&) =
diff --git a/media/filters/decrypting_video_decoder_unittest.cc b/media/filters/decrypting_video_decoder_unittest.cc
index 0d51690..ff894fa0 100644
--- a/media/filters/decrypting_video_decoder_unittest.cc
+++ b/media/filters/decrypting_video_decoder_unittest.cc
@@ -41,7 +41,7 @@
 // Create a fake non-empty encrypted buffer.
 static scoped_refptr<DecoderBuffer> CreateFakeEncryptedBuffer() {
   const int buffer_size = 16;  // Need a non-empty buffer;
-  scoped_refptr<DecoderBuffer> buffer(new DecoderBuffer(buffer_size));
+  auto buffer = base::MakeRefCounted<DecoderBuffer>(buffer_size);
   buffer->set_decrypt_config(DecryptConfig::CreateCencConfig(
       std::string(reinterpret_cast<const char*>(kFakeKeyId),
                   std::size(kFakeKeyId)),
@@ -53,11 +53,11 @@
 class DecryptingVideoDecoderTest : public testing::Test {
  public:
   DecryptingVideoDecoderTest()
-      : decoder_(new DecryptingVideoDecoder(
+      : decoder_(std::make_unique<DecryptingVideoDecoder>(
             task_environment_.GetMainThreadTaskRunner(),
             &media_log_)),
-        cdm_context_(new StrictMock<MockCdmContext>()),
-        decryptor_(new StrictMock<MockDecryptor>()),
+        cdm_context_(std::make_unique<StrictMock<MockCdmContext>>()),
+        decryptor_(std::make_unique<StrictMock<MockDecryptor>>()),
         num_decrypt_and_decode_calls_(0),
         num_frames_in_decryptor_(0),
         encrypted_buffer_(CreateFakeEncryptedBuffer()),
diff --git a/media/filters/fake_video_decoder_unittest.cc b/media/filters/fake_video_decoder_unittest.cc
index f561d7b..38901bc 100644
--- a/media/filters/fake_video_decoder_unittest.cc
+++ b/media/filters/fake_video_decoder_unittest.cc
@@ -35,7 +35,7 @@
       public testing::WithParamInterface<FakeVideoDecoderTestParams> {
  public:
   FakeVideoDecoderTest()
-      : decoder_(new FakeVideoDecoder(
+      : decoder_(std::make_unique<FakeVideoDecoder>(
             0xFACCE,
             GetParam().decoding_delay,
             GetParam().max_decode_requests,
diff --git a/media/filters/ffmpeg_audio_decoder.cc b/media/filters/ffmpeg_audio_decoder.cc
index 887bee2..b28a6b18 100644
--- a/media/filters/ffmpeg_audio_decoder.cc
+++ b/media/filters/ffmpeg_audio_decoder.cc
@@ -56,7 +56,7 @@
       state_(DecoderState::kUninitialized),
       av_sample_format_(0),
       media_log_(media_log),
-      pool_(new AudioBufferMemoryPool()) {
+      pool_(base::MakeRefCounted<AudioBufferMemoryPool>()) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
@@ -119,6 +119,11 @@
   DecodeCB decode_cb_bound =
       base::BindPostTaskToCurrentDefault(std::move(decode_cb));
 
+  if (!DecoderBuffer::DoSubsamplesMatch(*buffer)) {
+    std::move(decode_cb_bound).Run(DecoderStatus::Codes::kFailed);
+    return;
+  }
+
   if (state_ == DecoderState::kError) {
     std::move(decode_cb_bound).Run(DecoderStatus::Codes::kFailed);
     return;
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index daa2187..d5ab57b 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -778,8 +778,9 @@
       break;
 #if BUILDFLAG(ENABLE_PLATFORM_HEVC)
     case AV_CODEC_ID_HEVC:
-      bitstream_converter_.reset(
-          new FFmpegH265ToAnnexBBitstreamConverter(stream_->codecpar));
+      bitstream_converter_ =
+          std::make_unique<FFmpegH265ToAnnexBBitstreamConverter>(
+              stream_->codecpar);
       break;
 #endif
     case AV_CODEC_ID_AAC:
diff --git a/media/filters/ffmpeg_glue_unittest.cc b/media/filters/ffmpeg_glue_unittest.cc
index 99bfc1d8..b712378f 100644
--- a/media/filters/ffmpeg_glue_unittest.cc
+++ b/media/filters/ffmpeg_glue_unittest.cc
@@ -46,8 +46,7 @@
 
 class FFmpegGlueTest : public ::testing::Test {
  public:
-  FFmpegGlueTest()
-      : protocol_(new StrictMock<MockProtocol>()) {
+  FFmpegGlueTest() : protocol_(std::make_unique<StrictMock<MockProtocol>>()) {
     // IsStreaming() is called when opening.
     EXPECT_CALL(*protocol_.get(), IsStreaming()).WillOnce(Return(true));
     glue_ = std::make_unique<FFmpegGlue>(protocol_.get());
diff --git a/media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.cc b/media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.cc
index 7b65ccc4..c1228755 100644
--- a/media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.cc
+++ b/media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.cc
@@ -38,7 +38,7 @@
       return false;
     }
 
-    avc_config.reset(new mp4::AVCDecoderConfigurationRecord());
+    avc_config = std::make_unique<mp4::AVCDecoderConfigurationRecord>();
 
     if (!converter_.ParseConfiguration(stream_codec_parameters_->extradata,
                                        stream_codec_parameters_->extradata_size,
diff --git a/media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.cc b/media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.cc
index 480e57ef..8de8c46 100644
--- a/media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.cc
+++ b/media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.cc
@@ -36,7 +36,7 @@
       return false;
     }
 
-    hevc_config_.reset(new mp4::HEVCDecoderConfigurationRecord());
+    hevc_config_ = std::make_unique<mp4::HEVCDecoderConfigurationRecord>();
 
     if (!hevc_config_->Parse(stream_codec_parameters_->extradata,
                              stream_codec_parameters_->extradata_size)) {
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index 8b5daa3..2ce1db44 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -56,9 +56,10 @@
 
 class FFmpegVideoDecoderTest : public testing::Test {
  public:
-  FFmpegVideoDecoderTest() : decoder_(new FFmpegVideoDecoder(&media_log_)) {
+  FFmpegVideoDecoderTest()
+      : decoder_(std::make_unique<FFmpegVideoDecoder>(&media_log_)) {
     // Initialize various test buffers.
-    frame_buffer_.reset(new uint8_t[kCodedSize.GetArea()]);
+    frame_buffer_ = std::make_unique<uint8_t[]>(kCodedSize.GetArea());
     end_of_stream_buffer_ = DecoderBuffer::CreateEOSBuffer();
     i_frame_buffer_ = ReadTestDataFile("vp8-I-frame-320x240");
     corrupt_i_frame_buffer_ = ReadTestDataFile("vp8-corrupt-I-frame");
diff --git a/media/filters/frame_buffer_pool_unittest.cc b/media/filters/frame_buffer_pool_unittest.cc
index 7c5bb5fe..fb9c17d 100644
--- a/media/filters/frame_buffer_pool_unittest.cc
+++ b/media/filters/frame_buffer_pool_unittest.cc
@@ -14,7 +14,7 @@
 
 TEST(FrameBufferPool, BasicFunctionality) {
   base::TestMessageLoop message_loop;
-  scoped_refptr<FrameBufferPool> pool = new FrameBufferPool();
+  auto pool = base::MakeRefCounted<FrameBufferPool>();
 
   void* priv1 = nullptr;
   uint8_t* buf1 = pool->GetFrameBuffer(kBufferSize, &priv1);
@@ -59,7 +59,7 @@
 
 TEST(FrameBufferPool, ForceAllocationError) {
   base::TestMessageLoop message_loop;
-  scoped_refptr<FrameBufferPool> pool = new FrameBufferPool();
+  auto pool = base::MakeRefCounted<FrameBufferPool>();
   pool->force_allocation_error_for_testing();
 
   void* priv1 = nullptr;
@@ -71,7 +71,7 @@
 
 TEST(FrameBufferPool, DeferredDestruction) {
   base::TestMessageLoop message_loop;
-  scoped_refptr<FrameBufferPool> pool = new FrameBufferPool();
+  auto pool = base::MakeRefCounted<FrameBufferPool>();
   base::SimpleTestTickClock test_clock;
   pool->set_tick_clock_for_testing(&test_clock);
 
diff --git a/media/filters/h265_to_annex_b_bitstream_converter_unittest.cc b/media/filters/h265_to_annex_b_bitstream_converter_unittest.cc
index 7481e10..bee71785 100644
--- a/media/filters/h265_to_annex_b_bitstream_converter_unittest.cc
+++ b/media/filters/h265_to_annex_b_bitstream_converter_unittest.cc
@@ -62,7 +62,7 @@
   EXPECT_GT(config_size, 0U);
 
   // Go on with converting the headers.
-  output.reset(new uint8_t[config_size]);
+  output = std::make_unique<uint8_t[]>(config_size);
   EXPECT_TRUE(output.get() != nullptr);
   EXPECT_TRUE(converter.ConvertHEVCDecoderConfigToByteStream(
       hevc_config_, output.get(), &config_size));
@@ -72,7 +72,7 @@
       kPacketDataOkWithFieldLen4, sizeof(kPacketDataOkWithFieldLen4),
       &hevc_config_);
   EXPECT_GT(output_size, 0U);
-  output.reset(new uint8_t[output_size]);
+  output = std::make_unique<uint8_t[]>(output_size);
   EXPECT_TRUE(output.get() != nullptr);
 
   uint32_t output_size_left_for_nal_unit = output_size;
@@ -112,7 +112,7 @@
   EXPECT_GT(config_size, 0U);
 
   // Go on with converting the headers.
-  output.reset(new uint8_t[config_size]);
+  output = std::make_unique<uint8_t[]>(config_size);
   EXPECT_TRUE(output.get() != nullptr);
   EXPECT_TRUE(converter.ConvertHEVCDecoderConfigToByteStream(
       hevc_config_, output.get(), &config_size));
@@ -130,7 +130,7 @@
 
   // Ignore the error and try to go on with conversion simulating wrong usage.
   output_size = sizeof(kPacketDataOkWithFieldLen4);
-  output.reset(new uint8_t[output_size]);
+  output = std::make_unique<uint8_t[]>(output_size);
   EXPECT_TRUE(output.get() != nullptr);
 
   uint32_t output_size_left_for_nal_unit = output_size;
@@ -156,7 +156,7 @@
 
   // Go on with converting the headers with too small buffer.
   config_size -= 10;
-  output.reset(new uint8_t[config_size]);
+  output = std::make_unique<uint8_t[]>(config_size);
   EXPECT_TRUE(output.get() != nullptr);
   EXPECT_FALSE(converter.ConvertHEVCDecoderConfigToByteStream(
       hevc_config_, output.get(), &config_size));
@@ -164,7 +164,7 @@
 
   // Still too small (but only 1 byte short).
   config_size = real_config_size - 1;
-  output.reset(new uint8_t[config_size]);
+  output = std::make_unique<uint8_t[]>(config_size);
   EXPECT_TRUE(output.get() != nullptr);
   EXPECT_FALSE(converter.ConvertHEVCDecoderConfigToByteStream(
       hevc_config_, output.get(), &config_size));
@@ -172,7 +172,7 @@
 
   // Finally, retry with valid buffer.
   config_size = real_config_size;
-  output.reset(new uint8_t[config_size]);
+  output = std::make_unique<uint8_t[]>(config_size);
   EXPECT_TRUE(output.get() != nullptr);
   EXPECT_TRUE(converter.ConvertHEVCDecoderConfigToByteStream(
       hevc_config_, output.get(), &config_size));
@@ -184,7 +184,7 @@
   EXPECT_GT(output_size, 0U);
   // Simulate too small output buffer.
   output_size -= 1;
-  output.reset(new uint8_t[output_size]);
+  output = std::make_unique<uint8_t[]>(output_size);
   EXPECT_TRUE(output.get() != nullptr);
 
   uint32_t output_size_left_for_nal_unit = output_size;
@@ -225,7 +225,7 @@
   EXPECT_GT(config_size, 0U);
 
   // Go on with converting the headers.
-  output.reset(new uint8_t[config_size]);
+  output = std::make_unique<uint8_t[]>(config_size);
   EXPECT_TRUE(converter.ConvertHEVCDecoderConfigToByteStream(
       hevc_config_, output.get(), &config_size));
 
diff --git a/media/filters/mac/audio_toolbox_audio_decoder.cc b/media/filters/mac/audio_toolbox_audio_decoder.cc
index f68e429..36e258d 100644
--- a/media/filters/mac/audio_toolbox_audio_decoder.cc
+++ b/media/filters/mac/audio_toolbox_audio_decoder.cc
@@ -190,6 +190,11 @@
     return;
   }
 
+  if (!DecoderBuffer::DoSubsamplesMatch(*buffer)) {
+    std::move(decode_cb).Run(DecoderStatus::Codes::kFailed);
+    return;
+  }
+
   InputData input_data;
   input_data.buffer = buffer.get();
   if (!buffer->end_of_stream())
diff --git a/media/filters/mac/audio_toolbox_audio_encoder.cc b/media/filters/mac/audio_toolbox_audio_encoder.cc
index e2ada20b..5f34862 100644
--- a/media/filters/mac/audio_toolbox_audio_encoder.cc
+++ b/media/filters/mac/audio_toolbox_audio_encoder.cc
@@ -375,8 +375,7 @@
       return;
     }
 
-    std::unique_ptr<uint8_t[]> packet_buffer(
-        new uint8_t[temp_output_buf_.size()]);
+    auto packet_buffer = std::make_unique<uint8_t[]>(temp_output_buf_.size());
     std::memcpy(packet_buffer.get(), temp_output_buf_.data(),
                 temp_output_buf_.size());
 
diff --git a/media/filters/passthrough_dts_audio_decoder.cc b/media/filters/passthrough_dts_audio_decoder.cc
index aa0bd5d4..14c31ca 100644
--- a/media/filters/passthrough_dts_audio_decoder.cc
+++ b/media/filters/passthrough_dts_audio_decoder.cc
@@ -16,7 +16,7 @@
     MediaLog* media_log)
     : task_runner_(task_runner),
       media_log_(media_log),
-      pool_(new AudioBufferMemoryPool()) {
+      pool_(base::MakeRefCounted<AudioBufferMemoryPool>()) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
diff --git a/media/filters/video_renderer_algorithm_unittest.cc b/media/filters/video_renderer_algorithm_unittest.cc
index 231dce2..030055d 100644
--- a/media/filters/video_renderer_algorithm_unittest.cc
+++ b/media/filters/video_renderer_algorithm_unittest.cc
@@ -73,7 +73,7 @@
 class VideoRendererAlgorithmTest : public testing::Test {
  public:
   VideoRendererAlgorithmTest()
-      : tick_clock_(new base::SimpleTestTickClock()),
+      : tick_clock_(std::make_unique<base::SimpleTestTickClock>()),
         algorithm_(base::BindRepeating(&WallClockTimeSource::GetWallClockTimes,
                                        base::Unretained(&time_source_)),
                    &media_log_) {
diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc
index 40499029..07b61370 100644
--- a/media/filters/vpx_video_decoder.cc
+++ b/media/filters/vpx_video_decoder.cc
@@ -253,7 +253,7 @@
            VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER);
 
     DCHECK(!memory_pool_);
-    memory_pool_ = new FrameBufferPool();
+    memory_pool_ = base::MakeRefCounted<FrameBufferPool>();
 
     if (vpx_codec_set_frame_buffer_functions(
             vpx_codec_.get(), &GetVP9FrameBuffer, &ReleaseVP9FrameBuffer,
diff --git a/media/filters/vpx_video_decoder_unittest.cc b/media/filters/vpx_video_decoder_unittest.cc
index 0df350a..ff63abf 100644
--- a/media/filters/vpx_video_decoder_unittest.cc
+++ b/media/filters/vpx_video_decoder_unittest.cc
@@ -28,7 +28,7 @@
 class VpxVideoDecoderTest : public testing::Test {
  public:
   VpxVideoDecoderTest()
-      : decoder_(new VpxVideoDecoder()),
+      : decoder_(std::make_unique<VpxVideoDecoder>()),
         i_frame_buffer_(ReadTestDataFile("vp9-I-frame-320x240")) {}
 
   VpxVideoDecoderTest(const VpxVideoDecoderTest&) = delete;
diff --git a/media/filters/win/media_foundation_audio_decoder.cc b/media/filters/win/media_foundation_audio_decoder.cc
index 9d15eb6..96441a9f 100644
--- a/media/filters/win/media_foundation_audio_decoder.cc
+++ b/media/filters/win/media_foundation_audio_decoder.cc
@@ -180,6 +180,11 @@
 
 void MediaFoundationAudioDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
                                          DecodeCB decode_cb) {
+  if (!DecoderBuffer::DoSubsamplesMatch(*buffer)) {
+    std::move(decode_cb).Run(DecoderStatus::Codes::kFailed);
+    return;
+  }
+
   if (buffer->end_of_stream()) {
     switch (decoder_->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0)) {
       case S_OK: {
@@ -284,7 +289,7 @@
   if (hr != S_OK) {
     DLOG(ERROR) << "Reset failed with \"" << PrintHr(hr) << "\"";
   }
-  std::move(reset_cb).Run();
+  base::BindPostTaskToCurrentDefault(std::move(reset_cb)).Run();
 }
 
 bool MediaFoundationAudioDecoder::NeedsBitstreamConversion() const {
diff --git a/media/filters/wsola_internals.cc b/media/filters/wsola_internals.cc
index c82ef6b..76138505 100644
--- a/media/filters/wsola_internals.cc
+++ b/media/filters/wsola_internals.cc
@@ -164,7 +164,7 @@
   int channels = search_segment->channels();
   int block_size = target_block->frames();
   int num_candidate_blocks = search_segment->frames() - (block_size - 1);
-  std::unique_ptr<float[]> dot_prod(new float[channels]);
+  auto dot_prod = std::make_unique<float[]>(channels);
   float similarity[3];  // Three elements for cubic interpolation.
 
   int n = 0;
@@ -242,7 +242,7 @@
                const float* energy_candidate_blocks) {
   int channels = search_block->channels();
   int block_size = target_block->frames();
-  std::unique_ptr<float[]> dot_prod(new float[channels]);
+  auto dot_prod = std::make_unique<float[]>(channels);
 
   float best_similarity = std::numeric_limits<float>::min();
   int optimal_index = 0;
@@ -283,9 +283,9 @@
   // heuristically based on experiments.
   const int kSearchDecimation = 5;
 
-  std::unique_ptr<float[]> energy_target_block(new float[channels]);
-  std::unique_ptr<float[]> energy_candidate_blocks(
-      new float[channels * num_candidate_blocks]);
+  auto energy_target_block = std::make_unique<float[]>(channels);
+  auto energy_candidate_blocks =
+      std::make_unique<float[]>(channels * num_candidate_blocks);
 
   // Energy of all candid frames.
   MultiChannelMovingBlockEnergies(search_block, target_size,
diff --git a/media/gpu/android/media_codec_video_decoder.cc b/media/gpu/android/media_codec_video_decoder.cc
index 330f9e1..a4fa1ff 100644
--- a/media/gpu/android/media_codec_video_decoder.cc
+++ b/media/gpu/android/media_codec_video_decoder.cc
@@ -775,6 +775,12 @@
     std::move(decode_cb).Run(DecoderStatus::Codes::kFailed);
     return;
   }
+
+  if (!DecoderBuffer::DoSubsamplesMatch(*buffer)) {
+    std::move(decode_cb).Run(DecoderStatus::Codes::kFailed);
+    return;
+  }
+
   pending_decodes_.emplace_back(std::move(buffer), std::move(decode_cb));
 
   if (state_ == State::kInitializing) {
diff --git a/media/gpu/android/media_codec_video_decoder_unittest.cc b/media/gpu/android/media_codec_video_decoder_unittest.cc
index 4d2d2dc..d3bb9170 100644
--- a/media/gpu/android/media_codec_video_decoder_unittest.cc
+++ b/media/gpu/android/media_codec_video_decoder_unittest.cc
@@ -455,6 +455,12 @@
   PumpCodec();
 }
 
+TEST_P(MediaCodecVideoDecoderTest, MismatchedSubsamplesIsAnError) {
+  Initialize(TestVideoConfig::Large(codec_));
+  EXPECT_CALL(decode_cb_, Run(HasStatusCode(DecoderStatus::Codes::kFailed)));
+  mcvd_->Decode(CreateMismatchedBufferForTest(), decode_cb_.Get());
+}
+
 TEST_P(MediaCodecVideoDecoderTest, AfterInitCompletesTheCodecIsPolled) {
   auto* codec =
       InitializeFully_OneDecodePending(TestVideoConfig::Large(codec_));
diff --git a/media/gpu/v4l2/test/upstream_pix_fmt.h b/media/gpu/v4l2/test/upstream_pix_fmt.h
index 5aacb57d..7ff4cd01 100644
--- a/media/gpu/v4l2/test/upstream_pix_fmt.h
+++ b/media/gpu/v4l2/test/upstream_pix_fmt.h
@@ -23,4 +23,9 @@
 #define V4L2_PIX_FMT_MM21 v4l2_fourcc('M', 'M', '2', '1')
 #endif
 
+#ifndef V4L2_PIX_FMT_MT2T
+// MTK 10-bit block mode, two non-contiguous planes.
+#define V4L2_PIX_FMT_MT2T v4l2_fourcc('M', 'T', '2', 'T')
+#endif
+
 #endif  // MEDIA_GPU_V4L2_TEST_UPSTREAM_PIX_FMT_H_
diff --git a/media/gpu/v4l2/test/video_decoder.cc b/media/gpu/v4l2/test/video_decoder.cc
index f64ee50..937db281 100644
--- a/media/gpu/v4l2/test/video_decoder.cc
+++ b/media/gpu/v4l2/test/video_decoder.cc
@@ -53,8 +53,8 @@
 VideoDecoder::~VideoDecoder() = default;
 
 void VideoDecoder::NegotiateCAPTUREFormat() {
-  constexpr uint32_t kPreferredFormats[] = {V4L2_PIX_FMT_NV12,
-                                            V4L2_PIX_FMT_MM21};
+  constexpr uint32_t kPreferredFormats[] = {
+      V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_MM21, V4L2_PIX_FMT_MT2T};
 
   struct v4l2_format fmt;
 
@@ -105,10 +105,12 @@
   LOG_ASSERT((V4L2_PIX_FMT_MM21 == fourcc &&
               CAPTURE_queue_->num_planes() == fmt.fmt.pix_mp.num_planes) ||
              (V4L2_PIX_FMT_NV12 == fourcc &&
+              CAPTURE_queue_->num_planes() == fmt.fmt.pix_mp.num_planes) ||
+             (V4L2_PIX_FMT_MT2T == fourcc &&
               CAPTURE_queue_->num_planes() == fmt.fmt.pix_mp.num_planes))
       << media::FourccToString(fourcc)
       << " does not have the correct number of planes: "
-      << fmt.fmt.pix_mp.num_planes;
+      << static_cast<uint32_t>(fmt.fmt.pix_mp.num_planes);
 }
 
 void VideoDecoder::Initialize(bool resolution_changed) {
@@ -235,8 +237,8 @@
                                 uint32_t fourcc) {
   const gfx::Size half_dest_size((dest_size.width() + 1) / 2,
                                  (dest_size.height() + 1) / 2);
-  const uint32_t dest_y_stride = dest_size.width();
-  const uint32_t dest_uv_stride = half_dest_size.width();
+  const uint32_t dest_full_stride = dest_size.width();
+  const uint32_t dest_half_stride = half_dest_size.width();
 
   dest_y.resize(dest_size.GetArea());
   dest_u.resize(half_dest_size.GetArea());
@@ -250,9 +252,9 @@
     const uint8_t* src_uv = src + src_size.width() * src_size.height();
 
     libyuv::NV12ToI420(src, src_size.width(), src_uv, src_size.width(),
-                       &dest_y[0], dest_y_stride, &dest_u[0], dest_uv_stride,
-                       &dest_v[0], dest_uv_stride, dest_size.width(),
-                       dest_size.height());
+                       &dest_y[0], dest_full_stride, &dest_u[0],
+                       dest_half_stride, &dest_v[0], dest_half_stride,
+                       dest_size.width(), dest_size.height());
   } else if (fourcc == V4L2_PIX_FMT_MM21) {
     CHECK_EQ(planes.size(), 2u)
         << "MM21 should have exactly 2 planes but CAPTURE queue does not.";
@@ -260,9 +262,37 @@
     const uint8_t* src_uv = static_cast<uint8_t*>(planes[1].start_addr);
 
     libyuv::MM21ToI420(src_y, src_size.width(), src_uv, src_size.width(),
-                       &dest_y[0], dest_y_stride, &dest_u[0], dest_uv_stride,
-                       &dest_v[0], dest_uv_stride, dest_size.width(),
-                       dest_size.height());
+                       &dest_y[0], dest_full_stride, &dest_u[0],
+                       dest_half_stride, &dest_v[0], dest_half_stride,
+                       dest_size.width(), dest_size.height());
+  } else if (fourcc == V4L2_PIX_FMT_MT2T) {
+    CHECK_EQ(planes.size(), 2u)
+        << "MT2T should have exactly 2 planes but CAPTURE queue does not.";
+
+    const uint8_t* src_y = static_cast<uint8_t*>(planes[0].start_addr);
+    const uint8_t* src_uv = static_cast<uint8_t*>(planes[1].start_addr);
+
+    dest_y.resize(dest_size.GetArea() * 2);
+    dest_u.resize(half_dest_size.GetArea() * 2);
+    dest_v.resize(half_dest_size.GetArea() * 2);
+
+    std::vector<uint16_t> tmp_y(dest_size.GetArea());
+    std::vector<uint16_t> tmp_uv(dest_size.GetArea());
+
+    // stride is 5/4 because MT2T is a packed 10bit format
+    const uint32_t src_stride_mt2t = (src_size.width() * 5) >> 2;
+
+    libyuv::MT2TToP010(src_y, src_stride_mt2t, src_uv, src_stride_mt2t,
+                       &tmp_y[0], dest_full_stride, &tmp_uv[0],
+                       dest_full_stride, dest_size.width(), dest_size.height());
+
+    libyuv::P010ToI010(
+        &tmp_y[0], dest_full_stride, &tmp_uv[0], dest_full_stride,
+        reinterpret_cast<uint16_t*>(&dest_y[0]), dest_full_stride,
+        reinterpret_cast<uint16_t*>(&dest_u[0]), dest_half_stride,
+        reinterpret_cast<uint16_t*>(&dest_v[0]), dest_half_stride,
+        dest_size.width(), dest_size.height());
+
   } else {
     LOG(FATAL) << "Unsupported CAPTURE queue format";
   }
diff --git a/media/gpu/windows/d3d11_h264_accelerator.cc b/media/gpu/windows/d3d11_h264_accelerator.cc
index 2d217da..dbc1e80b 100644
--- a/media/gpu/windows/d3d11_h264_accelerator.cc
+++ b/media/gpu/windows/d3d11_h264_accelerator.cc
@@ -28,10 +28,10 @@
 
 namespace media {
 
-using DecoderStatus = H264Decoder::H264Accelerator::Status;
-
 namespace {
 
+using H264DecoderStatus = H264Decoder::H264Accelerator::Status;
+
 // Converts SubsampleEntry to D3D11_VIDEO_DECODER_SUB_SAMPLE_MAPPING_BLOCK.
 void AppendSubsamples(
     const std::vector<SubsampleEntry>& from,
@@ -91,7 +91,7 @@
   return base::MakeRefCounted<D3D11H264Picture>(picture);
 }
 
-DecoderStatus D3D11H264Accelerator::SubmitFrameMetadata(
+H264DecoderStatus D3D11H264Accelerator::SubmitFrameMetadata(
     const H264SPS* sps,
     const H264PPS* pps,
     const H264DPB& dpb,
@@ -103,14 +103,14 @@
   if (is_encrypted) {
     RecordFailure("Cannot find decrypt context for the frame.",
                   D3D11Status::Codes::kCryptoConfigFailed);
-    return DecoderStatus::kFail;
+    return H264DecoderStatus::kFail;
   }
 
   HRESULT hr;
   for (;;) {
     D3D11H264Picture* d3d11_pic = pic->AsD3D11H264Picture();
     if (!d3d11_pic)
-      return DecoderStatus::kFail;
+      return H264DecoderStatus::kFail;
 
     ID3D11VideoDecoderOutputView* output_view = nullptr;
     auto result = d3d11_pic->picture->AcquireOutputView();
@@ -118,7 +118,7 @@
       output_view = std::move(result).value();
     } else {
       RecordFailure(std::move(result).error());
-      return DecoderStatus::kFail;
+      return H264DecoderStatus::kFail;
     }
 
     hr = video_context_->DecoderBeginFrame(video_decoder_.Get(), output_view, 0,
@@ -131,7 +131,7 @@
     } else if (!SUCCEEDED(hr)) {
       RecordFailure("DecoderBeginFrame failed",
                     D3D11Status::Codes::kDecoderBeginFrameFailed, hr);
-      return DecoderStatus::kFail;
+      return H264DecoderStatus::kFail;
     } else {
       break;
     }
@@ -156,7 +156,7 @@
     // something is clearly wrong, and we should just fail decoding rather than
     // try to sort out which pictures really shouldn't be included.
     if (i >= media::kRefFrameMaxCount)
-      return DecoderStatus::kFail;
+      return H264DecoderStatus::kFail;
 
     D3D11H264Picture* our_ref_pic = it->get()->AsD3D11H264Picture();
     // How does a non-d3d11 picture get here you might ask? The decoder
@@ -177,7 +177,8 @@
     non_existing_frame_flags_ |= (our_ref_pic->nonexisting) << i;
   }
   slice_info_.clear();
-  return RetrieveBitstreamBuffer() ? DecoderStatus::kOk : DecoderStatus::kFail;
+  return RetrieveBitstreamBuffer() ? H264DecoderStatus::kOk
+                                   : H264DecoderStatus::kFail;
 }
 
 bool D3D11H264Accelerator::RetrieveBitstreamBuffer() {
@@ -327,7 +328,7 @@
   }
 }
 
-DecoderStatus D3D11H264Accelerator::SubmitSlice(
+H264DecoderStatus D3D11H264Accelerator::SubmitSlice(
     const H264PPS* pps,
     const H264SliceHeader* slice_hdr,
     const H264Picture::Vector& ref_pic_list0,
@@ -342,12 +343,12 @@
 
   PicParamsFromSPS(&pic_param, &sps_, slice_hdr->field_pic_flag);
   if (!PicParamsFromPPS(&pic_param, pps))
-    return DecoderStatus::kFail;
+    return H264DecoderStatus::kFail;
   PicParamsFromSliceHeader(&pic_param, slice_hdr);
 
   D3D11H264Picture* d3d11_pic = pic->AsD3D11H264Picture();
   if (!d3d11_pic)
-    return DecoderStatus::kFail;
+    return H264DecoderStatus::kFail;
   PicParamsFromPic(&pic_param, d3d11_pic);
 
   memcpy(pic_param.RefFrameList, ref_frame_list_,
@@ -369,7 +370,7 @@
   if (!SUCCEEDED(hr)) {
     RecordFailure("GetDecoderBuffer (PictureParams) failed",
                   D3D11Status::Codes::kGetPicParamBufferFailed, hr);
-    return DecoderStatus::kFail;
+    return H264DecoderStatus::kFail;
   }
 
   memcpy(buffer, &pic_param, sizeof(pic_param));
@@ -378,7 +379,7 @@
   if (!SUCCEEDED(hr)) {
     RecordFailure("ReleaseDecoderBuffer (PictureParams) failed",
                   D3D11Status::Codes::kReleasePicParamBufferFailed, hr);
-    return DecoderStatus::kFail;
+    return H264DecoderStatus::kFail;
   }
 
   DXVA_Qmatrix_H264 iq_matrix_buf = {};
@@ -415,7 +416,7 @@
   if (!SUCCEEDED(hr)) {
     RecordFailure("GetDecoderBuffer (QuantMatrix) failed",
                   D3D11Status::Codes::kGetQuantBufferFailed, hr);
-    return DecoderStatus::kFail;
+    return H264DecoderStatus::kFail;
   }
   memcpy(buffer, &iq_matrix_buf, sizeof(iq_matrix_buf));
   hr = video_context_->ReleaseDecoderBuffer(
@@ -424,7 +425,7 @@
   if (!SUCCEEDED(hr)) {
     RecordFailure("ReleaseDecoderBuffer (QuantMatrix) failed",
                   D3D11Status::Codes::kReleaseQuantBufferFailed, hr);
-    return DecoderStatus::kFail;
+    return H264DecoderStatus::kFail;
   }
 
   // Ideally all slices in a frame are put in the same bitstream buffer.
@@ -444,7 +445,7 @@
                         ") too big to fit in the bistream buffer (" +
                         base::NumberToString(bitstream_buffer_size_) + ").",
                     D3D11Status::Codes::kBitstreamBufferSliceTooBig);
-      return DecoderStatus::kFail;
+      return H264DecoderStatus::kFail;
     }
 
     AppendSubsamples(subsamples, &subsamples_);
@@ -464,10 +465,10 @@
     if (bitstream_buffer_size_ < remaining_bitstream &&
         slice_info_.size() > 0) {
       if (!SubmitSliceData())
-        return DecoderStatus::kFail;
+        return H264DecoderStatus::kFail;
 
       if (!RetrieveBitstreamBuffer())
-        return DecoderStatus::kFail;
+        return H264DecoderStatus::kFail;
     }
 
     size_t bytes_to_copy = remaining_bitstream;
@@ -507,7 +508,7 @@
     bitstream_buffer_bytes_ += bytes_to_copy;
   }
 
-  return DecoderStatus::kOk;
+  return H264DecoderStatus::kOk;
 }
 
 bool D3D11H264Accelerator::SubmitSliceData() {
@@ -586,19 +587,19 @@
   return true;
 }
 
-DecoderStatus D3D11H264Accelerator::SubmitDecode(
+H264DecoderStatus D3D11H264Accelerator::SubmitDecode(
     scoped_refptr<H264Picture> pic) {
   if (!SubmitSliceData())
-    return DecoderStatus::kFail;
+    return H264DecoderStatus::kFail;
 
   HRESULT hr = video_context_->DecoderEndFrame(video_decoder_.Get());
   if (!SUCCEEDED(hr)) {
     RecordFailure("DecoderEndFrame failed",
                   D3D11Status::Codes::kDecoderEndFrameFailed, hr);
-    return DecoderStatus::kFail;
+    return H264DecoderStatus::kFail;
   }
 
-  return DecoderStatus::kOk;
+  return H264DecoderStatus::kOk;
 }
 
 void D3D11H264Accelerator::Reset() {
diff --git a/media/gpu/windows/d3d11_h265_accelerator.cc b/media/gpu/windows/d3d11_h265_accelerator.cc
index d5cf9c5..21608f7 100644
--- a/media/gpu/windows/d3d11_h265_accelerator.cc
+++ b/media/gpu/windows/d3d11_h265_accelerator.cc
@@ -29,10 +29,10 @@
 
 namespace media {
 
-using DecoderStatus = H265Decoder::H265Accelerator::Status;
-
 namespace {
 
+using H265DecoderStatus = H265Decoder::H265Accelerator::Status;
+
 // Converts SubsampleEntry to D3D11_VIDEO_DECODER_SUB_SAMPLE_MAPPING_BLOCK.
 void AppendSubsamples(
     const std::vector<SubsampleEntry>& from,
@@ -99,7 +99,7 @@
          chroma_sampling == VideoChromaSampling::k444;
 }
 
-DecoderStatus D3D11H265Accelerator::SubmitFrameMetadata(
+H265DecoderStatus D3D11H265Accelerator::SubmitFrameMetadata(
     const H265SPS* sps,
     const H265PPS* pps,
     const H265SliceHeader* slice_hdr,
@@ -109,14 +109,14 @@
   if (is_encrypted) {
     RecordFailure("Cannot find decrypt context for the frame.",
                   D3D11Status::Codes::kCryptoConfigFailed);
-    return DecoderStatus::kFail;
+    return H265DecoderStatus::kFail;
   }
 
   HRESULT hr;
   for (;;) {
     D3D11H265Picture* d3d11_pic = pic->AsD3D11H265Picture();
     if (!d3d11_pic)
-      return DecoderStatus::kFail;
+      return H265DecoderStatus::kFail;
 
     ID3D11VideoDecoderOutputView* output_view = nullptr;
     auto result = d3d11_pic->picture->AcquireOutputView();
@@ -124,7 +124,7 @@
       output_view = std::move(result).value();
     } else {
       RecordFailure(std::move(result).error());
-      return DecoderStatus::kFail;
+      return H265DecoderStatus::kFail;
     }
 
     hr = video_context_->DecoderBeginFrame(video_decoder_.Get(), output_view, 0,
@@ -134,7 +134,7 @@
     } else if (!SUCCEEDED(hr)) {
       RecordFailure("DecoderBeginFrame failed",
                     D3D11Status::Codes::kDecoderBeginFrameFailed, hr);
-      return DecoderStatus::kFail;
+      return H265DecoderStatus::kFail;
     } else {
       break;
     }
@@ -156,7 +156,7 @@
   // list in picture param.
   if (ref_pic_list.size() > kMaxRefPicListSize) {
     DLOG(ERROR) << "Invalid fef pic list size.";
-    return DecoderStatus::kFail;
+    return H265DecoderStatus::kFail;
   }
 
   int i = 0;
@@ -173,7 +173,8 @@
     i++;
   }
   slice_info_.clear();
-  return RetrieveBitstreamBuffer() ? DecoderStatus::kOk : DecoderStatus::kFail;
+  return RetrieveBitstreamBuffer() ? H265DecoderStatus::kOk
+                                   : H265DecoderStatus::kFail;
 }
 
 bool D3D11H265Accelerator::RetrieveBitstreamBuffer() {
@@ -497,7 +498,7 @@
   return true;
 }
 
-DecoderStatus D3D11H265Accelerator::SubmitSlice(
+H265DecoderStatus D3D11H265Accelerator::SubmitSlice(
     const H265SPS* sps,
     const H265PPS* pps,
     const H265SliceHeader* slice_hdr,
@@ -514,7 +515,7 @@
 
   D3D11H265Picture* d3d11_pic = pic->AsD3D11H265Picture();
   if (!d3d11_pic) {
-    return DecoderStatus::kFail;
+    return H265DecoderStatus::kFail;
   }
 
   FillPicParamsWithConstants(&pic_param);
@@ -528,7 +529,7 @@
   if (!PicParamsFromRefLists(&pic_param, ref_pic_set_lt_curr,
                              ref_pic_set_st_curr_after,
                              ref_pic_set_st_curr_before)) {
-    return DecoderStatus::kFail;
+    return H265DecoderStatus::kFail;
   }
 
   pic_param.main.StatusReportFeedbackNumber =
@@ -542,7 +543,7 @@
   if (!SUCCEEDED(hr)) {
     RecordFailure("GetDecoderBuffer (PictureParams) failed",
                   D3D11Status::Codes::kGetPicParamBufferFailed, hr);
-    return DecoderStatus::kFail;
+    return H265DecoderStatus::kFail;
   }
 
   memcpy(buffer, &pic_param, sizeof(pic_param));
@@ -551,7 +552,7 @@
   if (!SUCCEEDED(hr)) {
     RecordFailure("ReleaseDecoderBuffer (PictureParams) failed",
                   D3D11Status::Codes::kReleasePicParamBufferFailed, hr);
-    return DecoderStatus::kFail;
+    return H265DecoderStatus::kFail;
   }
 
   // Fill up the quantitization matrix data structure when
@@ -613,7 +614,7 @@
     if (!SUCCEEDED(hr)) {
       RecordFailure("GetDecoderBuffer (QuantMatrix) failed",
                     D3D11Status::Codes::kGetQuantBufferFailed, hr);
-      return DecoderStatus::kFail;
+      return H265DecoderStatus::kFail;
     }
     memcpy(buffer, &iq_matrix_buf, sizeof(iq_matrix_buf));
     hr = video_context_->ReleaseDecoderBuffer(
@@ -622,7 +623,7 @@
     if (!SUCCEEDED(hr)) {
       RecordFailure("ReleaseDecoderBuffer (QuantMatrix) failed",
                     D3D11Status::Codes::kReleaseQuantBufferFailed, hr);
-      return DecoderStatus::kFail;
+      return H265DecoderStatus::kFail;
     }
   }
 
@@ -642,7 +643,7 @@
                         ") too big to fit in the bistream buffer (" +
                         base::NumberToString(bitstream_buffer_size_) + ").",
                     D3D11Status::Codes::kBitstreamBufferSliceTooBig);
-      return DecoderStatus::kFail;
+      return H265DecoderStatus::kFail;
     }
 
     AppendSubsamples(subsamples, &subsamples_);
@@ -656,10 +657,10 @@
     if (bitstream_buffer_size_ < remaining_bitstream &&
         slice_info_.size() > 0) {
       if (!SubmitSliceData())
-        return DecoderStatus::kFail;
+        return H265DecoderStatus::kFail;
 
       if (!RetrieveBitstreamBuffer())
-        return DecoderStatus::kFail;
+        return H265DecoderStatus::kFail;
     }
 
     size_t bytes_to_copy = remaining_bitstream;
@@ -698,7 +699,7 @@
     bitstream_buffer_bytes_ += bytes_to_copy;
   }
 
-  return DecoderStatus::kOk;
+  return H265DecoderStatus::kOk;
 }
 
 bool D3D11H265Accelerator::SubmitSliceData() {
@@ -790,19 +791,19 @@
   return true;
 }
 
-DecoderStatus D3D11H265Accelerator::SubmitDecode(
+H265DecoderStatus D3D11H265Accelerator::SubmitDecode(
     scoped_refptr<H265Picture> pic) {
   if (!SubmitSliceData())
-    return DecoderStatus::kFail;
+    return H265DecoderStatus::kFail;
 
   HRESULT hr = video_context_->DecoderEndFrame(video_decoder_.Get());
   if (!SUCCEEDED(hr)) {
     RecordFailure("DecoderEndFrame failed",
                   D3D11Status::Codes::kDecoderEndFrameFailed, hr);
-    return DecoderStatus::kFail;
+    return H265DecoderStatus::kFail;
   }
 
-  return DecoderStatus::kOk;
+  return H265DecoderStatus::kOk;
 }
 
 void D3D11H265Accelerator::Reset() {
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
index 8a0b996..f01a4cb6f 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
@@ -203,10 +203,18 @@
   Microsoft::WRL::ComPtr<IMFTransform> encoder;
   Microsoft::WRL::ComPtr<ICodecAPI> codec_api;
   HRESULT hr = activate->ActivateObject(IID_PPV_ARGS(&encoder));
-  RETURN_ON_HR_FAILURE(hr, "Failed to activate encoder", false);
+  if (FAILED(hr)) {
+    // Log to VLOG since errors are expected as part of GetSupportedProfiles().
+    DVLOG(2) << "Failed to activate encoder: " << PrintHr(hr);
+    return false;
+  }
 
   hr = encoder.As(&codec_api);
-  RETURN_ON_HR_FAILURE(hr, "Failed to get encoder as CodecAPI", false);
+  if (FAILED(hr)) {
+    // Log to VLOG since errors are expected as part of GetSupportedProfiles().
+    DVLOG(2) << "Failed to get encoder as CodecAPI: " << PrintHr(hr);
+    return false;
+  }
 
   if (codec_api->IsSupported(&CODECAPI_AVEncVideoTemporalLayerCount) != S_OK) {
     return false;
@@ -237,10 +245,15 @@
   output_info.guidSubtype = VideoCodecToMFSubtype(codec);
 
   uint32_t count = 0;
-  RETURN_ON_HR_FAILURE(
-      MFTEnumEx(MFT_CATEGORY_VIDEO_ENCODER, flags, &input_info, &output_info,
-                activates, &count),
-      "Failed to enumerate hardware encoders for " << GetCodecName(codec), 0);
+  auto hr = MFTEnumEx(MFT_CATEGORY_VIDEO_ENCODER, flags, &input_info,
+                      &output_info, activates, &count);
+  if (FAILED(hr)) {
+    // Log to VLOG since errors are expected as part of GetSupportedProfiles().
+    DVLOG(2) << "Failed to enumerate hardware encoders for "
+             << GetCodecName(codec) << ": " << PrintHr(hr);
+    return 0;
+  }
+
   return count;
 }
 
diff --git a/media/remoting/integration_test.cc b/media/remoting/integration_test.cc
index 383bfcd..70e5ed5b 100644
--- a/media/remoting/integration_test.cc
+++ b/media/remoting/integration_test.cc
@@ -41,7 +41,7 @@
   ASSERT_TRUE(WaitUntilOnEnded());
 
   EXPECT_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash());
-  EXPECT_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash());
+  EXPECT_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash().ToString());
 }
 
 TEST_F(MediaRemotingIntegrationTest, BasicPlayback_MediaSource) {
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index 2c85178..616c94d 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -51,9 +51,10 @@
 #include "media/filters/win/media_foundation_audio_decoder.h"
 #endif
 
-#define EXPECT_HASH_EQ(a, b) EXPECT_EQ(a, b)
-#define EXPECT_VIDEO_FORMAT_EQ(a, b) EXPECT_EQ(a, b)
-#define EXPECT_COLOR_SPACE_EQ(a, b) EXPECT_EQ(a, b)
+#define EXPECT_AUDIO_HASH(expected)                        \
+  EXPECT_TRUE(GetAudioHash().IsEquivalent(expected, 0.04)) \
+      << "Audio hashes differ. Expected: " << expected     \
+      << " Actual: " << GetAudioHash().ToString()
 
 using ::testing::_;
 using ::testing::AnyNumber;
@@ -65,80 +66,46 @@
 namespace media {
 
 #if BUILDFLAG(ENABLE_AV1_DECODER)
-const int kAV110bitMp4FileDurationMs = 2735;
-const int kAV1640WebMFileDurationMs = 2736;
+constexpr int kAV110bitMp4FileDurationMs = 2735;
+constexpr int kAV1640WebMFileDurationMs = 2736;
 #endif  // BUILDFLAG(ENABLE_AV1_DECODER)
 
 // Constants for the Media Source config change tests.
-const int kAppendTimeSec = 1;
-const int kAppendTimeMs = kAppendTimeSec * 1000;
-const int k320WebMFileDurationMs = 2736;
-const int k640WebMFileDurationMs = 2762;
-const int kVP9WebMFileDurationMs = 2736;
-const int kVP8AWebMFileDurationMs = 2734;
+constexpr int kAppendTimeSec = 1;
+constexpr int kAppendTimeMs = kAppendTimeSec * 1000;
+constexpr int k320WebMFileDurationMs = 2736;
+constexpr int k640WebMFileDurationMs = 2762;
+constexpr int kVP9WebMFileDurationMs = 2736;
+constexpr int kVP8AWebMFileDurationMs = 2734;
 
-static const char kSfxLosslessHash[] = "3.03,2.86,2.99,3.31,3.57,4.06,";
+constexpr char kSfxLosslessHash[] = "3.03,2.86,2.99,3.31,3.57,4.06,";
 
-#if defined(OPUS_FIXED_POINT)
-// NOTE: These hashes are specific to ARM devices, which use fixed-point Opus
-// implementation. x86 uses floating-point Opus, so x86 hashes won't match
-#if defined(ARCH_CPU_ARM64)
-static const char kOpusEndTrimmingHash_1[] =
-    "-4.58,-5.68,-6.53,-6.28,-4.35,-3.59,";
-static const char kOpusEndTrimmingHash_2[] =
-    "-11.92,-11.11,-8.25,-7.10,-7.84,-10.00,";
-static const char kOpusEndTrimmingHash_3[] =
-    "-13.33,-14.38,-13.68,-11.66,-10.18,-10.49,";
-static const char kOpusSmallCodecDelayHash_1[] =
-    "-0.48,-0.09,1.27,1.06,1.54,-0.22,";
-static const char kOpusSmallCodecDelayHash_2[] =
-    "0.29,0.15,-0.19,0.25,0.68,0.83,";
-static const char kOpusMonoOutputHash[] = "-2.39,-1.66,0.81,1.54,1.48,-0.91,";
-#else
-static const char kOpusEndTrimmingHash_1[] =
-    "-4.57,-5.66,-6.52,-6.30,-4.37,-3.61,";
-static const char kOpusEndTrimmingHash_2[] =
-    "-11.91,-11.11,-8.27,-7.13,-7.86,-10.00,";
-static const char kOpusEndTrimmingHash_3[] =
-    "-13.31,-14.38,-13.70,-11.71,-10.21,-10.49,";
-static const char kOpusSmallCodecDelayHash_1[] =
-    "-0.48,-0.09,1.27,1.06,1.54,-0.22,";
-static const char kOpusSmallCodecDelayHash_2[] =
-    "0.29,0.14,-0.20,0.24,0.68,0.83,";
-static const char kOpusMonoOutputHash[] = "-2.41,-1.66,0.79,1.53,1.46,-0.91,";
-#endif  // defined(ARCH_CPU_ARM64)
-
-#else
 // Hash for a full playthrough of "opus-trimming-test.(webm|ogg)".
-static const char kOpusEndTrimmingHash_1[] =
+constexpr char kOpusEndTrimmingHash_1[] =
     "-4.57,-5.67,-6.52,-6.28,-4.34,-3.58,";
+
 // The above hash, plus an additional playthrough starting from T=1s.
-static const char kOpusEndTrimmingHash_2[] =
+constexpr char kOpusEndTrimmingHash_2[] =
     "-11.91,-11.10,-8.24,-7.08,-7.82,-9.99,";
+
 // The above hash, plus an additional playthrough starting from T=6.36s.
-static const char kOpusEndTrimmingHash_3[] =
+constexpr char kOpusEndTrimmingHash_3[] =
     "-13.31,-14.36,-13.66,-11.65,-10.16,-10.47,";
+
 // Hash for a full playthrough of "bear-opus.webm".
-static const char kOpusSmallCodecDelayHash_1[] =
+constexpr char kOpusSmallCodecDelayHash_1[] =
     "-0.47,-0.09,1.28,1.07,1.55,-0.22,";
+
 // The above hash, plus an additional playthrough starting from T=1.414s.
-static const char kOpusSmallCodecDelayHash_2[] =
-    "0.31,0.15,-0.18,0.25,0.70,0.84,";
+constexpr char kOpusSmallCodecDelayHash_2[] = "0.31,0.15,-0.18,0.25,0.70,0.84,";
+
 // For BasicPlaybackOpusWebmHashed_MonoOutput test case.
-static const char kOpusMonoOutputHash[] = "-2.36,-1.64,0.84,1.55,1.51,-0.90,";
-#endif  // defined(OPUS_FIXED_POINT)
+constexpr char kOpusMonoOutputHash[] = "-2.36,-1.64,0.84,1.55,1.51,-0.90,";
 
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
-const int k640IsoCencFileDurationMs = 2769;
-const int k1280IsoFileDurationMs = 2736;
+constexpr int k1280IsoFileDurationMs = 2736;
 
-// TODO(wolenetz): Update to 2769 once MSE endOfStream implementation no longer
-// truncates duration to the highest in intersection ranges, but compliantly to
-// the largest track buffer ranges end time across all tracks and SourceBuffers.
-// See https://crbug.com/639144.
-const int k1280IsoFileDurationMsAV = 2763;
-
-const int k1280IsoAVC3FileDurationMs = 2736;
+constexpr int k1280IsoAVC3FileDurationMs = 2736;
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 
 // Return a timeline offset for bear-320x240-live.webm.
@@ -738,8 +705,8 @@
 
   ASSERT_TRUE(WaitUntilOnEnded());
 
-  EXPECT_HASH_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash());
-  EXPECT_HASH_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash());
+  EXPECT_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash());
+  EXPECT_AUDIO_HASH("-3.59,-2.06,-0.43,2.15,0.77,-0.95,");
   EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());
 }
 
@@ -791,7 +758,7 @@
   Pause();
 
   // Verify that no audio has been played, since we disabled audio tracks.
-  EXPECT_HASH_EQ(kNullAudioHash, GetAudioHash());
+  EXPECT_AUDIO_HASH(kNullAudioHash);
 
   // Re-enable audio.
   std::vector<MediaTrack::Id> audio_track_id;
@@ -804,7 +771,7 @@
   ASSERT_TRUE(WaitUntilOnEnded());
 
   // Verify that audio has been playing after being enabled.
-  EXPECT_HASH_EQ("-1.53,0.21,1.23,1.56,-0.34,-0.94,", GetAudioHash());
+  EXPECT_AUDIO_HASH("-1.53,0.21,1.23,1.56,-0.34,-0.94,");
 }
 
 TEST_F(PipelineIntegrationTest, PlaybackWithVideoTrackDisabledThenEnabled) {
@@ -831,7 +798,7 @@
   Pause();
 
   // Verify that no video has been rendered, since we disabled video tracks.
-  EXPECT_HASH_EQ(kNullVideoHash, GetVideoHash());
+  EXPECT_EQ(kNullVideoHash, GetVideoHash());
 
   // Re-enable video.
   OnSelectedVideoTrackChanged(MediaTrack::Id("1"));
@@ -847,7 +814,7 @@
   ASSERT_TRUE(WaitUntilOnEnded());
 
   // Verify that video has been rendered after being enabled.
-  EXPECT_HASH_EQ("fd59357dfd9c144ab4fb8181b2de32c3", GetVideoHash());
+  EXPECT_EQ("fd59357dfd9c144ab4fb8181b2de32c3", GetVideoHash());
 }
 
 TEST_F(PipelineIntegrationTest, TrackStatusChangesBeforePipelineStarted) {
@@ -1025,20 +992,20 @@
   Play();
 
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusEndTrimmingHash_1, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusEndTrimmingHash_1);
 
   // Seek within the pre-skip section, this should not cause a beep.
   ASSERT_TRUE(Seek(base::Seconds(1)));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusEndTrimmingHash_2, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusEndTrimmingHash_2);
 
   // Seek somewhere outside of the pre-skip / end-trim section, demuxer should
   // correctly preroll enough to accurately decode this segment.
   ASSERT_TRUE(Seek(base::Milliseconds(6360)));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusEndTrimmingHash_3, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusEndTrimmingHash_3);
 }
 
 TEST_F(PipelineIntegrationTest, BasicPlaybackOpusWebmTrimmingHashed) {
@@ -1047,20 +1014,20 @@
   Play();
 
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusEndTrimmingHash_1, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusEndTrimmingHash_1);
 
   // Seek within the pre-skip section, this should not cause a beep.
   ASSERT_TRUE(Seek(base::Seconds(1)));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusEndTrimmingHash_2, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusEndTrimmingHash_2);
 
   // Seek somewhere outside of the pre-skip / end-trim section, demuxer should
   // correctly preroll enough to accurately decode this segment.
   ASSERT_TRUE(Seek(base::Milliseconds(6360)));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusEndTrimmingHash_3, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusEndTrimmingHash_3);
 }
 
 TEST_F(PipelineIntegrationTest, BasicPlaybackOpusMp4TrimmingHashed) {
@@ -1070,23 +1037,24 @@
 
   // TODO(dalecurtis): The test clip currently does not have the edit list
   // entries required to achieve correctness here. Delete this comment and
-  // uncomment the EXPECT_HASH_EQ lines when https://crbug.com/876544 is fixed.
+  // uncomment the EXPECT_AUDIO_HASH lines when https://crbug.com/876544 is
+  // fixed.
 
   ASSERT_TRUE(WaitUntilOnEnded());
-  // EXPECT_HASH_EQ(kOpusEndTrimmingHash_1, GetAudioHash());
+  // EXPECT_AUDIO_HASH(kOpusEndTrimmingHash_1);
 
   // Seek within the pre-skip section, this should not cause a beep.
   ASSERT_TRUE(Seek(base::Seconds(1)));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  // EXPECT_HASH_EQ(kOpusEndTrimmingHash_2, GetAudioHash());
+  // EXPECT_AUDIO_HASH(kOpusEndTrimmingHash_2);
 
   // Seek somewhere outside of the pre-skip / end-trim section, demuxer should
   // correctly preroll enough to accurately decode this segment.
   ASSERT_TRUE(Seek(base::Milliseconds(6360)));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  // EXPECT_HASH_EQ(kOpusEndTrimmingHash_3, GetAudioHash());
+  // EXPECT_AUDIO_HASH(kOpusEndTrimmingHash_3);
 }
 
 TEST_F(PipelineIntegrationTest, MSE_BasicPlaybackOpusWebmTrimmingHashed) {
@@ -1098,7 +1066,7 @@
   Play();
 
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusEndTrimmingHash_1, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusEndTrimmingHash_1);
 
   // Seek within the pre-skip section, this should not cause a beep.
   base::TimeDelta seek_time = base::Seconds(1);
@@ -1106,7 +1074,7 @@
   ASSERT_TRUE(Seek(seek_time));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusEndTrimmingHash_2, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusEndTrimmingHash_2);
 
   // Seek somewhere outside of the pre-skip / end-trim section, demuxer should
   // correctly preroll enough to accurately decode this segment.
@@ -1115,7 +1083,7 @@
   ASSERT_TRUE(Seek(seek_time));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusEndTrimmingHash_3, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusEndTrimmingHash_3);
 }
 
 TEST_F(PipelineIntegrationTest, MSE_BasicPlaybackOpusMp4TrimmingHashed) {
@@ -1138,7 +1106,7 @@
   Play();
 
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusEndTrimmingHash_1, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusEndTrimmingHash_1);
 
   // Seek within the pre-skip section, this should not cause a beep.
   base::TimeDelta seek_time = base::Seconds(1);
@@ -1146,7 +1114,7 @@
   ASSERT_TRUE(Seek(seek_time));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusEndTrimmingHash_2, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusEndTrimmingHash_2);
 
   // Seek somewhere outside of the pre-skip / end-trim section, demuxer should
   // correctly preroll enough to accurately decode this segment.
@@ -1155,7 +1123,7 @@
   ASSERT_TRUE(Seek(seek_time));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusEndTrimmingHash_3, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusEndTrimmingHash_3);
 }
 
 TEST_F(PipelineIntegrationTest, BasicPlaybackOpusWebmHashed_MonoOutput) {
@@ -1175,7 +1143,7 @@
   ASSERT_TRUE(WaitUntilOnEnded());
 
   // Hash has very slight differences when phase inversion is enabled.
-  EXPECT_HASH_EQ(kOpusMonoOutputHash, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusMonoOutputHash);
 }
 
 TEST_F(PipelineIntegrationTest, BasicPlaybackOpusPrerollExceedsCodecDelay) {
@@ -1192,13 +1160,13 @@
 
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_1, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusSmallCodecDelayHash_1);
 
   // Seek halfway through the file to invoke seek preroll.
   ASSERT_TRUE(Seek(base::Seconds(1.414)));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_2, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusSmallCodecDelayHash_2);
 }
 
 TEST_F(PipelineIntegrationTest, BasicPlaybackOpusMp4PrerollExceedsCodecDelay) {
@@ -1215,17 +1183,18 @@
 
   // TODO(dalecurtis): The test clip currently does not have the edit list
   // entries required to achieve correctness here. Delete this comment and
-  // uncomment the EXPECT_HASH_EQ lines when https://crbug.com/876544 is fixed.
+  // uncomment the EXPECT_AUDIO_HASH lines when https://crbug.com/876544 is
+  // fixed.
 
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  // EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_1, GetAudioHash());
+  // EXPECT_AUDIO_HASH(kOpusSmallCodecDelayHash_1);
 
   // Seek halfway through the file to invoke seek preroll.
   ASSERT_TRUE(Seek(base::Seconds(1.414)));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  // EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_2, GetAudioHash());
+  // EXPECT_AUDIO_HASH(kOpusSmallCodecDelayHash_2);
 }
 
 TEST_F(PipelineIntegrationTest, MSE_BasicPlaybackOpusPrerollExceedsCodecDelay) {
@@ -1245,7 +1214,7 @@
 
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_1, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusSmallCodecDelayHash_1);
 
   // Seek halfway through the file to invoke seek preroll.
   base::TimeDelta seek_time = base::Seconds(1.414);
@@ -1253,7 +1222,7 @@
   ASSERT_TRUE(Seek(seek_time));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_2, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusSmallCodecDelayHash_2);
 }
 
 TEST_F(PipelineIntegrationTest,
@@ -1285,7 +1254,7 @@
 
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_1, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusSmallCodecDelayHash_1);
 
   // Seek halfway through the file to invoke seek preroll.
   base::TimeDelta seek_time = base::Seconds(1.414);
@@ -1293,7 +1262,7 @@
   ASSERT_TRUE(Seek(seek_time));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_2, GetAudioHash());
+  EXPECT_AUDIO_HASH(kOpusSmallCodecDelayHash_2);
 }
 
 TEST_F(PipelineIntegrationTest, BasicPlaybackLive) {
@@ -1307,8 +1276,8 @@
 
   ASSERT_TRUE(WaitUntilOnEnded());
 
-  EXPECT_HASH_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash());
-  EXPECT_HASH_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash());
+  EXPECT_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash());
+  EXPECT_AUDIO_HASH("-3.59,-2.06,-0.43,2.15,0.77,-0.95,");
   EXPECT_EQ(kLiveTimelineOffset(), demuxer_->GetTimelineOffset());
 }
 
@@ -1316,16 +1285,16 @@
   ASSERT_EQ(PIPELINE_OK, Start("sfx_s32le.wav", kHashed));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(std::string(kNullVideoHash), GetVideoHash());
-  EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash());
+  EXPECT_EQ(kNullVideoHash, GetVideoHash());
+  EXPECT_AUDIO_HASH(kSfxLosslessHash);
 }
 
 TEST_F(PipelineIntegrationTest, F32PlaybackHashed) {
   ASSERT_EQ(PIPELINE_OK, Start("sfx_f32le.wav", kHashed));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(std::string(kNullVideoHash), GetVideoHash());
-  EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash());
+  EXPECT_EQ(kNullVideoHash, GetVideoHash());
+  EXPECT_AUDIO_HASH(kSfxLosslessHash);
 }
 
 TEST_F(PipelineIntegrationTest, BasicPlaybackEncrypted) {
@@ -1347,8 +1316,8 @@
   ASSERT_EQ(PIPELINE_OK, Start("sfx.flac", kHashed));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(std::string(kNullVideoHash), GetVideoHash());
-  EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash());
+  EXPECT_EQ(kNullVideoHash, GetVideoHash());
+  EXPECT_AUDIO_HASH(kSfxLosslessHash);
 }
 
 TEST_F(PipelineIntegrationTest, MSE_BasicPlayback) {
@@ -1445,7 +1414,7 @@
 
   ASSERT_TRUE(WaitUntilOnEnded());
   source.Shutdown();
-  EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_YUV420P10);
+  EXPECT_EQ(last_video_frame_format_, PIXEL_FORMAT_YUV420P10);
   Stop();
 }
 
@@ -1840,7 +1809,7 @@
 
   ASSERT_TRUE(WaitUntilOnEnded());
   source.Shutdown();
-  EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_YUV420P10);
+  EXPECT_EQ(last_video_frame_format_, PIXEL_FORMAT_YUV420P10);
   Stop();
 }
 #endif
@@ -1857,8 +1826,8 @@
 
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(std::string(kNullVideoHash), GetVideoHash());
-  EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash());
+  EXPECT_EQ(kNullVideoHash, GetVideoHash());
+  EXPECT_AUDIO_HASH(kSfxLosslessHash);
 }
 
 TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_MP3) {
@@ -1869,15 +1838,15 @@
   ASSERT_TRUE(WaitUntilOnEnded());
 
   // Verify codec delay and preroll are stripped.
-  EXPECT_HASH_EQ("1.30,2.72,4.56,5.08,3.74,2.03,", GetAudioHash());
+  EXPECT_AUDIO_HASH("1.30,2.72,4.56,5.08,3.74,2.03,");
 }
 
 TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_FlacInMp4) {
   ASSERT_EQ(PIPELINE_OK, Start("sfx-flac.mp4", kHashed));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ(std::string(kNullVideoHash), GetVideoHash());
-  EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash());
+  EXPECT_EQ(kNullVideoHash, GetVideoHash());
+  EXPECT_AUDIO_HASH(kSfxLosslessHash);
 }
 
 #if BUILDFLAG(ENABLE_AV1_DECODER)
@@ -1938,7 +1907,7 @@
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
 
-  EXPECT_HASH_EQ(config.hash, GetAudioHash());
+  EXPECT_AUDIO_HASH(config.hash);
 }
 
 // CBR seeks should always be fast and accurate.
@@ -1982,7 +1951,7 @@
   EXPECT_TRUE(WaitUntilOnEnded());
 
   // Verify that codec delay was stripped.
-  EXPECT_HASH_EQ("1.01,2.71,4.18,4.32,3.04,1.12,", GetAudioHash());
+  EXPECT_AUDIO_HASH("1.01,2.71,4.18,4.32,3.04,1.12,");
 }
 
 TEST_F(PipelineIntegrationTest, MSE_MP3_TimestampOffset) {
@@ -2038,7 +2007,7 @@
   EXPECT_TRUE(WaitUntilOnEnded());
 
   // Verify that nothing was stripped.
-  EXPECT_HASH_EQ("0.46,1.72,4.26,4.57,3.39,1.53,", GetAudioHash());
+  EXPECT_AUDIO_HASH("0.46,1.72,4.26,4.57,3.39,1.53,");
 }
 
 TEST_F(PipelineIntegrationTest, MSE_ADTS_TimestampOffset) {
@@ -2069,7 +2038,7 @@
   EXPECT_EQ(592, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
 
   // Verify preroll is stripped.
-  EXPECT_HASH_EQ("-1.76,-1.35,-0.72,0.70,1.24,0.52,", GetAudioHash());
+  EXPECT_AUDIO_HASH("-1.76,-1.35,-0.72,0.70,1.24,0.52,");
 }
 
 TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_ADTS) {
@@ -2080,7 +2049,7 @@
   ASSERT_TRUE(WaitUntilOnEnded());
 
   // Verify codec delay and preroll are stripped.
-  EXPECT_HASH_EQ("1.80,1.66,2.31,3.26,4.46,3.36,", GetAudioHash());
+  EXPECT_AUDIO_HASH("1.80,1.66,2.31,3.26,4.46,3.36,");
 }
 
 TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_M4A) {
@@ -2092,7 +2061,7 @@
   // Verify preroll is stripped. This file uses a preroll of 2112 frames, which
   // spans all three packets in the file. Postroll is not correctly stripped at
   // present; see the note below.
-  EXPECT_HASH_EQ("3.84,4.25,4.33,3.58,3.27,3.16,", GetAudioHash());
+  EXPECT_AUDIO_HASH("3.84,4.25,4.33,3.58,3.27,3.16,");
 
   // Note the above hash is incorrect since the <audio> path doesn't properly
   // trim trailing silence at end of stream for AAC decodes. This isn't a huge
@@ -2102,7 +2071,7 @@
   // The WebAudio path via AudioFileReader computes this correctly, so the hash
   // below is taken from that test.
   //
-  // EXPECT_HASH_EQ("3.77,4.53,4.75,3.48,3.67,3.76,", GetAudioHash());
+  // EXPECT_AUDIO_HASH("3.77,4.53,4.75,3.48,3.67,3.76,");
 }
 
 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN)
@@ -2225,6 +2194,13 @@
 
   EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
   EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
+
+  // TODO(wolenetz): Update to 2769 once MSE endOfStream implementation no
+  // longer truncates duration to the highest in intersection ranges, but
+  // compliantly to the largest track buffer ranges end time across all tracks
+  // and SourceBuffers. See https://crbug.com/639144.
+  constexpr int k1280IsoFileDurationMsAV = 2763;
+
   EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMsAV,
             pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
 
@@ -2336,6 +2312,7 @@
   EXPECT_EQ(33, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
 
   // The second video was not added, so its time has not been added.
+  constexpr int k640IsoCencFileDurationMs = 2769;
   EXPECT_EQ(k640IsoCencFileDurationMs,
             pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
 
@@ -2821,7 +2798,7 @@
   ASSERT_EQ(PIPELINE_OK, Start("spherical.mp4", kHashed));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_HASH_EQ("1cb7f980020d99ea852e22dd6bd8d9de", GetVideoHash());
+  EXPECT_EQ("1cb7f980020d99ea852e22dd6bd8d9de", GetVideoHash());
 }
 
 TEST_F(PipelineIntegrationTest, StereoAACMarkedAsMono) {
@@ -2891,7 +2868,7 @@
   ASSERT_EQ(PIPELINE_OK, Start("bear-vp8a.webm"));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);
+  EXPECT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);
 }
 
 // Verify that VP8A video with odd width/height can be played back.
@@ -2899,7 +2876,7 @@
   ASSERT_EQ(PIPELINE_OK, Start("bear-vp8a-odd-dimensions.webm"));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);
+  EXPECT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);
 }
 
 // Verify that VP9 video with odd width/height can be played back.
@@ -2914,7 +2891,7 @@
   ASSERT_EQ(PIPELINE_OK, Start("bear-vp9a.webm"));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);
+  EXPECT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);
 }
 
 // Verify that VP9A video with odd width/height can be played back.
@@ -2922,7 +2899,7 @@
   ASSERT_EQ(PIPELINE_OK, Start("bear-vp9a-odd-dimensions.webm"));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);
+  EXPECT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);
 }
 
 // Verify that VP9 video with 4:4:4 subsampling can be played back.
@@ -2930,7 +2907,7 @@
   ASSERT_EQ(PIPELINE_OK, Start("bear-320x240-P444.webm"));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I444);
+  EXPECT_EQ(last_video_frame_format_, PIXEL_FORMAT_I444);
 }
 
 // Verify that frames of VP9 video in the BT.709 color space have the YV12HD
@@ -2939,9 +2916,8 @@
   ASSERT_EQ(PIPELINE_OK, Start("bear-vp9-bt709.webm"));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420);
-  EXPECT_COLOR_SPACE_EQ(last_video_frame_color_space_,
-                        gfx::ColorSpace::CreateREC709());
+  EXPECT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420);
+  EXPECT_EQ(last_video_frame_color_space_, gfx::ColorSpace::CreateREC709());
 }
 
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
@@ -2950,8 +2926,7 @@
   ASSERT_EQ(PIPELINE_OK, Start("blackwhite_yuvj420p.mp4"));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_COLOR_SPACE_EQ(last_video_frame_color_space_,
-                        gfx::ColorSpace::CreateJpeg());
+  EXPECT_EQ(last_video_frame_color_space_, gfx::ColorSpace::CreateJpeg());
 }
 #endif
 
diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc
index 08d5f299..fe013e0 100644
--- a/media/test/pipeline_integration_test_base.cc
+++ b/media/test/pipeline_integration_test_base.cc
@@ -575,7 +575,7 @@
   return base::MD5DigestToBase16(digest);
 }
 
-std::string PipelineIntegrationTestBase::GetAudioHash() {
+const AudioHash& PipelineIntegrationTestBase::GetAudioHash() const {
   DCHECK(hashing_enabled_);
 
   if (clockless_playback_)
diff --git a/media/test/pipeline_integration_test_base.h b/media/test/pipeline_integration_test_base.h
index ca719b4..0a431b2 100644
--- a/media/test/pipeline_integration_test_base.h
+++ b/media/test/pipeline_integration_test_base.h
@@ -120,7 +120,7 @@
   // Returns the hash of all audio frames seen.  Should only be called once
   // after playback completes.  Pipeline must have been started with hashing
   // enabled.
-  std::string GetAudioHash();
+  const AudioHash& GetAudioHash() const;
 
   // Reset video hash to restart hashing from scratch (e.g. after a seek or
   // after disabling a media track).
diff --git a/net/cert/cert_verify_proc_builtin.cc b/net/cert/cert_verify_proc_builtin.cc
index dd9d25b..db678315 100644
--- a/net/cert/cert_verify_proc_builtin.cc
+++ b/net/cert/cert_verify_proc_builtin.cc
@@ -523,12 +523,6 @@
     *cert_status |= CERT_STATUS_INVALID;
 }
 
-bssl::UniquePtr<CRYPTO_BUFFER> CreateCertBuffers(
-    const std::shared_ptr<const ParsedCertificate>& certificate) {
-  return X509Certificate::CreateCertBufferFromBytes(
-      certificate->der_cert().AsSpan());
-}
-
 // Creates a X509Certificate (chain) to return as the verified result.
 //
 //  * |target_cert|: The original X509Certificate that was passed in to
@@ -540,8 +534,9 @@
   std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
 
   // Skip the first certificate in the path as that is the target certificate
-  for (size_t i = 1; i < path.certs.size(); ++i)
-    intermediates.push_back(CreateCertBuffers(path.certs[i]));
+  for (size_t i = 1; i < path.certs.size(); ++i) {
+    intermediates.push_back(bssl::UpRef(path.certs[i]->cert_buffer()));
+  }
 
   scoped_refptr<X509Certificate> result = X509Certificate::CreateFromBuffer(
       bssl::UpRef(target_cert->cert_buffer()), std::move(intermediates));
diff --git a/net/cert/coalescing_cert_verifier.cc b/net/cert/coalescing_cert_verifier.cc
index ef3622bab..350f9643 100644
--- a/net/cert/coalescing_cert_verifier.cc
+++ b/net/cert/coalescing_cert_verifier.cc
@@ -433,11 +433,11 @@
   IncrementGenerationAndMakeCurrentJobsUnjoinable();
 }
 
-void CoalescingCertVerifier::AddObserver(Observer* observer) {
+void CoalescingCertVerifier::AddObserver(CertVerifier::Observer* observer) {
   verifier_->AddObserver(observer);
 }
 
-void CoalescingCertVerifier::RemoveObserver(Observer* observer) {
+void CoalescingCertVerifier::RemoveObserver(CertVerifier::Observer* observer) {
   verifier_->RemoveObserver(observer);
 }
 
diff --git a/net/cert/coalescing_cert_verifier.h b/net/cert/coalescing_cert_verifier.h
index aa8a7fb..3a0d0030 100644
--- a/net/cert/coalescing_cert_verifier.h
+++ b/net/cert/coalescing_cert_verifier.h
@@ -46,8 +46,8 @@
              std::unique_ptr<CertVerifier::Request>* out_req,
              const NetLogWithSource& net_log) override;
   void SetConfig(const CertVerifier::Config& config) override;
-  void AddObserver(Observer* observer) override;
-  void RemoveObserver(Observer* observer) override;
+  void AddObserver(CertVerifier::Observer* observer) override;
+  void RemoveObserver(CertVerifier::Observer* observer) override;
 
   uint64_t requests_for_testing() const { return requests_; }
   uint64_t inflight_joins_for_testing() const { return inflight_joins_; }
diff --git a/net/cert/trial_comparison_cert_verifier.h b/net/cert/trial_comparison_cert_verifier.h
index 1712a81..d8a9329 100644
--- a/net/cert/trial_comparison_cert_verifier.h
+++ b/net/cert/trial_comparison_cert_verifier.h
@@ -89,8 +89,8 @@
              std::unique_ptr<Request>* out_req,
              const NetLogWithSource& net_log) override;
   void SetConfig(const Config& config) override;
-  void AddObserver(Observer* observer) override;
-  void RemoveObserver(Observer* observer) override;
+  void AddObserver(CertVerifier::Observer* observer) override;
+  void RemoveObserver(CertVerifier::Observer* observer) override;
   void UpdateVerifyProcData(
       scoped_refptr<CertNetFetcher> cert_net_fetcher,
       const CertVerifyProcFactory::ImplParams& impl_params) override;
diff --git a/net/cert/x509_certificate.cc b/net/cert/x509_certificate.cc
index d201aed..dc406a0 100644
--- a/net/cert/x509_certificate.cc
+++ b/net/cert/x509_certificate.cc
@@ -112,6 +112,21 @@
   return NormalizeName(issuer_value, out_normalized_issuer, &errors);
 }
 
+bssl::UniquePtr<CRYPTO_BUFFER> CreateCertBufferFromBytesWithSanityCheck(
+    base::span<const uint8_t> data) {
+  der::Input tbs_certificate_tlv;
+  der::Input signature_algorithm_tlv;
+  der::BitString signature_value;
+  // Do a bare minimum of DER parsing here to see if the input looks
+  // certificate-ish.
+  if (!ParseCertificate(der::Input(data.data(), data.size()),
+                        &tbs_certificate_tlv, &signature_algorithm_tlv,
+                        &signature_value, nullptr)) {
+    return nullptr;
+  }
+  return x509_util::CreateCryptoBuffer(data);
+}
+
 }  // namespace
 
 // static
@@ -157,24 +172,13 @@
   std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediate_ca_certs;
   intermediate_ca_certs.reserve(der_certs.size() - 1);
   for (size_t i = 1; i < der_certs.size(); i++) {
-    bssl::UniquePtr<CRYPTO_BUFFER> handle = CreateCertBufferFromBytes(
-        base::as_bytes(base::make_span(der_certs[i])));
-    if (!handle)
-      break;
-    intermediate_ca_certs.push_back(std::move(handle));
+    intermediate_ca_certs.push_back(
+        x509_util::CreateCryptoBuffer(der_certs[i]));
   }
 
-  // Return NULL if we failed to parse any of the certs.
-  if (der_certs.size() - 1 != intermediate_ca_certs.size())
-    return nullptr;
-
-  bssl::UniquePtr<CRYPTO_BUFFER> handle =
-      CreateCertBufferFromBytes(base::as_bytes(base::make_span(der_certs[0])));
-  if (!handle)
-    return nullptr;
-
   return CreateFromBufferUnsafeOptions(
-      std::move(handle), std::move(intermediate_ca_certs), options);
+      x509_util::CreateCryptoBuffer(der_certs[0]),
+      std::move(intermediate_ca_certs), options);
 }
 
 // static
@@ -187,12 +191,8 @@
 scoped_refptr<X509Certificate> X509Certificate::CreateFromBytesUnsafeOptions(
     base::span<const uint8_t> data,
     UnsafeCreateOptions options) {
-  bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer = CreateCertBufferFromBytes(data);
-  if (!cert_buffer)
-    return nullptr;
-
-  scoped_refptr<X509Certificate> cert =
-      CreateFromBufferUnsafeOptions(std::move(cert_buffer), {}, options);
+  scoped_refptr<X509Certificate> cert = CreateFromBufferUnsafeOptions(
+      x509_util::CreateCryptoBuffer(data), {}, options);
   return cert;
 }
 
@@ -246,8 +246,8 @@
 
     bssl::UniquePtr<CRYPTO_BUFFER> handle;
     if (format & FORMAT_PEM_CERT_SEQUENCE) {
-      handle =
-          CreateCertBufferFromBytes(base::as_bytes(base::make_span(decoded)));
+      handle = CreateCertBufferFromBytesWithSanityCheck(
+          base::as_bytes(base::make_span(decoded)));
     }
     if (handle) {
       // Parsed a DER encoded certificate. All PEM blocks that follow must
@@ -640,24 +640,6 @@
 }
 
 // static
-bssl::UniquePtr<CRYPTO_BUFFER> X509Certificate::CreateCertBufferFromBytes(
-    base::span<const uint8_t> data) {
-  der::Input tbs_certificate_tlv;
-  der::Input signature_algorithm_tlv;
-  der::BitString signature_value;
-  // Do a bare minimum of DER parsing here to make sure the input is not
-  // completely crazy. (This is required for at least
-  // CreateCertificateListFromBytes with FORMAT_AUTO, if not more.)
-  if (!ParseCertificate(der::Input(data.data(), data.size()),
-                        &tbs_certificate_tlv, &signature_algorithm_tlv,
-                        &signature_value, nullptr)) {
-    return nullptr;
-  }
-
-  return x509_util::CreateCryptoBuffer(data);
-}
-
-// static
 std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>
 X509Certificate::CreateCertBuffersFromBytes(base::span<const uint8_t> data,
                                             Format format) {
@@ -665,7 +647,8 @@
 
   switch (format) {
     case FORMAT_SINGLE_CERTIFICATE: {
-      bssl::UniquePtr<CRYPTO_BUFFER> handle = CreateCertBufferFromBytes(data);
+      bssl::UniquePtr<CRYPTO_BUFFER> handle =
+          CreateCertBufferFromBytesWithSanityCheck(data);
       if (handle)
         results.push_back(std::move(handle));
       break;
diff --git a/net/cert/x509_certificate.h b/net/cert/x509_certificate.h
index d3fcbf97..447683c 100644
--- a/net/cert/x509_certificate.h
+++ b/net/cert/x509_certificate.h
@@ -241,13 +241,6 @@
     return intermediate_ca_certs_;
   }
 
-  // Creates a CRYPTO_BUFFER from the DER-encoded representation. Unlike
-  // creating a CRYPTO_BUFFER directly, this function does some minimal
-  // checking to reject obviously invalid inputs.
-  // Returns NULL on failure.
-  static bssl::UniquePtr<CRYPTO_BUFFER> CreateCertBufferFromBytes(
-      base::span<const uint8_t> data);
-
   // Creates all possible CRYPTO_BUFFERs from |data| encoded in a specific
   // |format|. Returns an empty collection on failure.
   static std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> CreateCertBuffersFromBytes(
diff --git a/net/cert/x509_certificate_unittest.cc b/net/cert/x509_certificate_unittest.cc
index 5ead4fe6..cbf4518f 100644
--- a/net/cert/x509_certificate_unittest.cc
+++ b/net/cert/x509_certificate_unittest.cc
@@ -654,14 +654,14 @@
   bssl::UniquePtr<CRYPTO_BUFFER> thawte_cert_handle;
 
   // Add a single certificate to the certificate cache.
-  google_cert_handle = X509Certificate::CreateCertBufferFromBytes(google_der);
+  google_cert_handle = x509_util::CreateCryptoBuffer(google_der);
   ASSERT_TRUE(google_cert_handle);
   scoped_refptr<X509Certificate> cert1(
       X509Certificate::CreateFromBuffer(std::move(google_cert_handle), {}));
   ASSERT_TRUE(cert1);
 
   // Add the same certificate, but as a new handle.
-  google_cert_handle = X509Certificate::CreateCertBufferFromBytes(google_der);
+  google_cert_handle = x509_util::CreateCryptoBuffer(google_der);
   ASSERT_TRUE(google_cert_handle);
   scoped_refptr<X509Certificate> cert2(
       X509Certificate::CreateFromBuffer(std::move(google_cert_handle), {}));
@@ -677,8 +677,8 @@
   // Add the same certificate, but this time with an intermediate. This
   // should result in the intermediate being cached. Note that this is not
   // a legitimate chain, but is suitable for testing.
-  google_cert_handle = X509Certificate::CreateCertBufferFromBytes(google_der);
-  thawte_cert_handle = X509Certificate::CreateCertBufferFromBytes(thawte_der);
+  google_cert_handle = x509_util::CreateCryptoBuffer(google_der);
+  thawte_cert_handle = x509_util::CreateCryptoBuffer(thawte_der);
   ASSERT_TRUE(google_cert_handle);
   ASSERT_TRUE(thawte_cert_handle);
   std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
@@ -697,10 +697,10 @@
 
 TEST(X509CertificateTest, Pickle) {
   bssl::UniquePtr<CRYPTO_BUFFER> google_cert_handle =
-      X509Certificate::CreateCertBufferFromBytes(google_der);
+      x509_util::CreateCryptoBuffer(google_der);
   ASSERT_TRUE(google_cert_handle);
   bssl::UniquePtr<CRYPTO_BUFFER> thawte_cert_handle =
-      X509Certificate::CreateCertBufferFromBytes(thawte_der);
+      x509_util::CreateCryptoBuffer(thawte_der);
   ASSERT_TRUE(thawte_cert_handle);
 
   std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
@@ -738,7 +738,7 @@
 
   bssl::UniquePtr<CRYPTO_BUFFER> google_handle;
   // Create object with no intermediates:
-  google_handle = X509Certificate::CreateCertBufferFromBytes(google_der);
+  google_handle = x509_util::CreateCryptoBuffer(google_der);
   scoped_refptr<X509Certificate> cert1;
   cert1 =
       X509Certificate::CreateFromBuffer(bssl::UpRef(google_handle.get()), {});
diff --git a/net/cert/x509_util_apple.cc b/net/cert/x509_util_apple.cc
index d50af1c..164a79b 100644
--- a/net/cert/x509_util_apple.cc
+++ b/net/cert/x509_util_apple.cc
@@ -14,6 +14,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "build/build_config.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "third_party/boringssl/src/include/openssl/pool.h"
 
 namespace net {
@@ -30,7 +31,7 @@
   if (!der_data) {
     return nullptr;
   }
-  return X509Certificate::CreateCertBufferFromBytes(
+  return CreateCryptoBuffer(
       base::make_span(CFDataGetBytePtr(der_data),
                       base::checked_cast<size_t>(CFDataGetLength(der_data))));
 }
diff --git a/net/cert/x509_util_nss.cc b/net/cert/x509_util_nss.cc
index 7adaf25..38f01db 100644
--- a/net/cert/x509_util_nss.cc
+++ b/net/cert/x509_util_nss.cc
@@ -22,6 +22,7 @@
 #include "base/strings/stringprintf.h"
 #include "crypto/nss_util.h"
 #include "crypto/scoped_nss_types.h"
+#include "net/cert/x509_util.h"
 #include "third_party/boringssl/src/include/openssl/pool.h"
 
 namespace net::x509_util {
@@ -251,30 +252,24 @@
     CERTCertificate* nss_cert,
     const std::vector<CERTCertificate*>& nss_chain,
     X509Certificate::UnsafeCreateOptions options) {
-  if (!nss_cert || !nss_cert->derCert.len)
+  if (!nss_cert || !nss_cert->derCert.len) {
     return nullptr;
-  bssl::UniquePtr<CRYPTO_BUFFER> cert_handle(
-      X509Certificate::CreateCertBufferFromBytes(
-          base::make_span(nss_cert->derCert.data, nss_cert->derCert.len)));
-  if (!cert_handle)
-    return nullptr;
+  }
+  bssl::UniquePtr<CRYPTO_BUFFER> cert_handle(x509_util::CreateCryptoBuffer(
+      base::make_span(nss_cert->derCert.data, nss_cert->derCert.len)));
 
   std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
   intermediates.reserve(nss_chain.size());
   for (const CERTCertificate* nss_intermediate : nss_chain) {
-    if (!nss_intermediate || !nss_intermediate->derCert.len)
+    if (!nss_intermediate || !nss_intermediate->derCert.len) {
       return nullptr;
-    bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle(
-        X509Certificate::CreateCertBufferFromBytes(base::make_span(
-            nss_intermediate->derCert.data, nss_intermediate->derCert.len)));
-    if (!intermediate_cert_handle)
-      return nullptr;
-    intermediates.push_back(std::move(intermediate_cert_handle));
+    }
+    intermediates.push_back(x509_util::CreateCryptoBuffer(base::make_span(
+        nss_intermediate->derCert.data, nss_intermediate->derCert.len)));
   }
-  scoped_refptr<X509Certificate> result(
-      X509Certificate::CreateFromBufferUnsafeOptions(
-          std::move(cert_handle), std::move(intermediates), options));
-  return result;
+
+  return X509Certificate::CreateFromBufferUnsafeOptions(
+      std::move(cert_handle), std::move(intermediates), options);
 }
 
 scoped_refptr<X509Certificate> CreateX509CertificateFromCERTCertificate(
diff --git a/net/cert/x509_util_win.cc b/net/cert/x509_util_win.cc
index 72c537a..8b87421 100644
--- a/net/cert/x509_util_win.cc
+++ b/net/cert/x509_util_win.cc
@@ -8,6 +8,7 @@
 #include "crypto/scoped_capi_types.h"
 #include "crypto/sha2.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/net_buildflags.h"
 #include "third_party/boringssl/src/include/openssl/pool.h"
 
@@ -27,27 +28,20 @@
     X509Certificate::UnsafeCreateOptions options) {
   if (!os_cert || !os_cert->pbCertEncoded || !os_cert->cbCertEncoded)
     return nullptr;
-  bssl::UniquePtr<CRYPTO_BUFFER> cert_handle(
-      X509Certificate::CreateCertBufferFromBytes(
-          base::make_span(os_cert->pbCertEncoded, os_cert->cbCertEncoded)));
-  if (!cert_handle)
-    return nullptr;
+  bssl::UniquePtr<CRYPTO_BUFFER> cert_handle(x509_util::CreateCryptoBuffer(
+      base::make_span(os_cert->pbCertEncoded, os_cert->cbCertEncoded)));
+
   std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
   for (PCCERT_CONTEXT os_intermediate : os_chain) {
     if (!os_intermediate || !os_intermediate->pbCertEncoded ||
         !os_intermediate->cbCertEncoded)
       return nullptr;
-    bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle(
-        X509Certificate::CreateCertBufferFromBytes(base::make_span(
-            os_intermediate->pbCertEncoded, os_intermediate->cbCertEncoded)));
-    if (!intermediate_cert_handle)
-      return nullptr;
-    intermediates.push_back(std::move(intermediate_cert_handle));
+    intermediates.push_back(x509_util::CreateCryptoBuffer(base::make_span(
+        os_intermediate->pbCertEncoded, os_intermediate->cbCertEncoded)));
   }
-  scoped_refptr<X509Certificate> result(
-      X509Certificate::CreateFromBufferUnsafeOptions(
-          std::move(cert_handle), std::move(intermediates), options));
-  return result;
+
+  return X509Certificate::CreateFromBufferUnsafeOptions(
+      std::move(cert_handle), std::move(intermediates), options);
 }
 
 crypto::ScopedPCCERT_CONTEXT CreateCertContextWithChain(
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins
index 76090ea..0c2e4798 100644
--- a/net/http/transport_security_state_static.pins
+++ b/net/http/transport_security_state_static.pins
@@ -43,9 +43,9 @@
 #   hash function for preloaded entries again (we have already done so once).
 #
 
-# Last updated: 2023-04-14 12:54 UTC
+# Last updated: 2023-04-15 12:53 UTC
 PinsListTimestamp
-1681476844
+1681563225
 
 TestSPKI
 sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
diff --git a/net/ssl/client_cert_store_nss.cc b/net/ssl/client_cert_store_nss.cc
index 2a7bab14..cc26f7a 100644
--- a/net/ssl/client_cert_store_nss.cc
+++ b/net/ssl/client_cert_store_nss.cc
@@ -23,6 +23,7 @@
 #include "crypto/nss_util.h"
 #include "crypto/scoped_nss_types.h"
 #include "net/cert/scoped_nss_types.h"
+#include "net/cert/x509_util.h"
 #include "net/cert/x509_util_nss.h"
 #include "net/ssl/ssl_cert_request_info.h"
 #include "net/ssl/ssl_platform_key_nss.h"
@@ -119,12 +120,8 @@
     std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
     intermediates.reserve(nss_intermediates.size());
     for (const ScopedCERTCertificate& nss_intermediate : nss_intermediates) {
-      bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle(
-          X509Certificate::CreateCertBufferFromBytes(base::make_span(
-              nss_intermediate->derCert.data, nss_intermediate->derCert.len)));
-      if (!intermediate_cert_handle)
-        break;
-      intermediates.push_back(std::move(intermediate_cert_handle));
+      intermediates.push_back(x509_util::CreateCryptoBuffer(base::make_span(
+          nss_intermediate->derCert.data, nss_intermediate->derCert.len)));
     }
 
     // Retain a copy of the intermediates. Some deployments expect the client to
diff --git a/remoting/proto/remoting/v1/BUILD.gn b/remoting/proto/remoting/v1/BUILD.gn
index ac56b1a9..9f6849f 100644
--- a/remoting/proto/remoting/v1/BUILD.gn
+++ b/remoting/proto/remoting/v1/BUILD.gn
@@ -8,6 +8,10 @@
   sources = [ "host_info.proto" ]
 }
 
+proto_library("chrome_os_enterprise_options") {
+  sources = [ "chrome_os_enterprise_options.proto" ]
+}
+
 proto_library("directory_proto") {
   sources = [ "directory_messages.proto" ]
   deps = [ ":host_info_proto" ]
@@ -31,7 +35,10 @@
 
 proto_library("remote_support_host_messages") {
   sources = [ "remote_support_host_messages.proto" ]
-  deps = [ ":host_info_proto" ]
+  deps = [
+    ":chrome_os_enterprise_options",
+    ":host_info_proto",
+  ]
 }
 
 proto_library("chromoting_event_proto") {
diff --git a/remoting/proto/remoting/v1/chrome_os_enterprise_options.proto b/remoting/proto/remoting/v1/chrome_os_enterprise_options.proto
new file mode 100644
index 0000000..e6813cfe
--- /dev/null
+++ b/remoting/proto/remoting/v1/chrome_os_enterprise_options.proto
@@ -0,0 +1,18 @@
+syntax = "proto2";
+
+package remoting.apis.v1;
+
+option optimize_for = LITE_RUNTIME;
+
+// Defines the UX and capabilities for a Chrome OS enterprise session.
+message ChromeOsEnterpriseOptions {
+  // Indicates whether to show the admin troubleshooting tools in the client UI.
+  optional bool allow_troubleshooting_tools = 1;
+
+  // Indicates whether the client should attempt to reconnect if the connection
+  // is dropped.
+  optional bool allow_reconnections = 2;
+
+  // Indicates whether to show the file transfer section in the client UI.
+  optional bool allow_file_transfer = 3;
+}
diff --git a/remoting/proto/remoting/v1/remote_support_host_messages.proto b/remoting/proto/remoting/v1/remote_support_host_messages.proto
index 78a719ea..5da637c 100644
--- a/remoting/proto/remoting/v1/remote_support_host_messages.proto
+++ b/remoting/proto/remoting/v1/remote_support_host_messages.proto
@@ -3,6 +3,7 @@
 package remoting.apis.v1;
 
 import "host_info.proto";
+import "chrome_os_enterprise_options.proto";
 
 option optimize_for = LITE_RUNTIME;
 
@@ -42,6 +43,10 @@
   // host. Only authorized accounts can make a successful GetSupportHostRequest.
   // If this field isn't set, then anyone can call GetSupportHost for this host.
   optional string authorized_helper = 7;
+
+  // The set of options for a Chrome OS enterprise session. This field must not
+  // be set for any other session type or the request will fail.
+  optional ChromeOsEnterpriseOptions chrome_os_enterprise_options = 8;
 }
 
 // The response to a RegisterSupportHostRequest.
diff --git a/sandbox/win/src/file_policy_test.cc b/sandbox/win/src/file_policy_test.cc
index a28f5bd..b06ec828 100644
--- a/sandbox/win/src/file_policy_test.cc
+++ b/sandbox/win/src/file_policy_test.cc
@@ -452,7 +452,7 @@
   EXPECT_TRUE(runner->AddRuleSys32(Semantics::kFilesAllowAny, L"notfound.exe"));
   EXPECT_TRUE(runner->AddRuleSys32(Semantics::kFilesAllowAny, L"drivers"));
   EXPECT_TRUE(
-      runner->AddRuleSys32(Semantics::kFilesAllowQuery, L"ipconfig.exe"));
+      runner->AddRuleSys32(Semantics::kFilesAllowReadonly, L"ipconfig.exe"));
   return runner;
 }
 
diff --git a/sandbox/win/src/filesystem_policy.cc b/sandbox/win/src/filesystem_policy.cc
index 1685cf59..42d11a6 100644
--- a/sandbox/win/src/filesystem_policy.cc
+++ b/sandbox/win/src/filesystem_policy.cc
@@ -83,6 +83,8 @@
 bool FileSystemPolicy::GenerateRules(const wchar_t* name,
                                      Semantics semantics,
                                      LowLevelPolicy* policy) {
+  CHECK(semantics == Semantics::kFilesAllowReadonly ||
+        semantics == Semantics::kFilesAllowAny);
   std::wstring mod_name(name);
   if (mod_name.empty()) {
     return false;
@@ -105,85 +107,54 @@
 
   EvalResult result = ASK_BROKER;
 
-  // List of supported calls for the filesystem.
-  const unsigned kCallNtCreateFile = 0x1;
-  const unsigned kCallNtOpenFile = 0x2;
-  const unsigned kCallNtQueryAttributesFile = 0x4;
-  const unsigned kCallNtQueryFullAttributesFile = 0x8;
-  const unsigned kCallNtSetInfoRename = 0x10;
-
-  DWORD rule_to_add = kCallNtOpenFile | kCallNtCreateFile |
-                      kCallNtQueryAttributesFile |
-                      kCallNtQueryFullAttributesFile | kCallNtSetInfoRename;
-
+  // Rules added for both read-only and write scenarios.
   PolicyRule create(result);
   PolicyRule open(result);
   PolicyRule query(result);
   PolicyRule query_full(result);
-  PolicyRule rename(result);
 
-  switch (semantics) {
-    case Semantics::kFilesAllowReadonly: {
-      // We consider all flags that are not known to be readonly as potentially
-      // used for write.
-      DWORD allowed_flags = FILE_READ_DATA | FILE_READ_ATTRIBUTES |
-                            FILE_READ_EA | SYNCHRONIZE | FILE_EXECUTE |
-                            GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL;
-      DWORD restricted_flags = ~allowed_flags;
-      open.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
-      open.AddNumberMatch(IF, OpenFile::OPENONLY, true, EQUAL);
-      create.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
-      create.AddNumberMatch(IF, OpenFile::OPENONLY, true, EQUAL);
+  if (semantics == Semantics::kFilesAllowReadonly) {
+    // We consider all flags that are not known to be readonly as potentially
+    // used for write.
+    DWORD allowed_flags = FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA |
+                          SYNCHRONIZE | FILE_EXECUTE | GENERIC_READ |
+                          GENERIC_EXECUTE | READ_CONTROL;
+    DWORD restricted_flags = ~allowed_flags;
+    open.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
+    open.AddNumberMatch(IF, OpenFile::OPENONLY, true, EQUAL);
+    create.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
+    create.AddNumberMatch(IF, OpenFile::OPENONLY, true, EQUAL);
+  }
 
-      // Read only access don't work for rename.
-      rule_to_add &= ~kCallNtSetInfoRename;
-      break;
-    }
-    case Semantics::kFilesAllowQuery: {
-      // Here we don't want to add policy for the open or the create.
-      rule_to_add &=
-          ~(kCallNtOpenFile | kCallNtCreateFile | kCallNtSetInfoRename);
-      break;
-    }
-    case Semantics::kFilesAllowAny: {
-      break;
-    }
-    default: {
-      NOTREACHED();
+  if (!create.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
+      !policy->AddRule(IpcTag::NTCREATEFILE, &create)) {
+    return false;
+  }
+
+  if (!open.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
+      !policy->AddRule(IpcTag::NTOPENFILE, &open)) {
+    return false;
+  }
+
+  if (!query.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
+      !policy->AddRule(IpcTag::NTQUERYATTRIBUTESFILE, &query)) {
+    return false;
+  }
+
+  if (!query_full.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
+      !policy->AddRule(IpcTag::NTQUERYFULLATTRIBUTESFILE, &query_full)) {
+    return false;
+  }
+
+  // Rename is not allowed for read-only and does not make sense for pipes.
+  if (semantics == Semantics::kFilesAllowAny && !is_pipe) {
+    PolicyRule rename(result);
+    if (!rename.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
+        !policy->AddRule(IpcTag::NTSETINFO_RENAME, &rename)) {
       return false;
     }
   }
 
-  if ((rule_to_add & kCallNtCreateFile) &&
-      (!create.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
-       !policy->AddRule(IpcTag::NTCREATEFILE, &create))) {
-    return false;
-  }
-
-  if ((rule_to_add & kCallNtOpenFile) &&
-      (!open.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
-       !policy->AddRule(IpcTag::NTOPENFILE, &open))) {
-    return false;
-  }
-
-  if ((rule_to_add & kCallNtQueryAttributesFile) &&
-      (!query.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
-       !policy->AddRule(IpcTag::NTQUERYATTRIBUTESFILE, &query))) {
-    return false;
-  }
-
-  if ((rule_to_add & kCallNtQueryFullAttributesFile) &&
-      (!query_full.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
-       !policy->AddRule(IpcTag::NTQUERYFULLATTRIBUTESFILE, &query_full))) {
-    return false;
-  }
-
-  if ((rule_to_add & kCallNtSetInfoRename) && !is_pipe &&
-      (!rename.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
-       !policy->AddRule(IpcTag::NTSETINFO_RENAME, &rename))) {
-    return false;
-  }
-
   return true;
 }
 
diff --git a/sandbox/win/src/sandbox_nt_util_unittest.cc b/sandbox/win/src/sandbox_nt_util_unittest.cc
index cd06021..748c629d 100644
--- a/sandbox/win/src/sandbox_nt_util_unittest.cc
+++ b/sandbox/win/src/sandbox_nt_util_unittest.cc
@@ -41,8 +41,10 @@
 TEST(SandboxNtUtil, IsSameProcessDifferentProcess) {
   STARTUPINFO si = {sizeof(si)};
   PROCESS_INFORMATION pi = {};
-  wchar_t notepad[] = L"notepad";
-  ASSERT_TRUE(CreateProcessW(nullptr, notepad, nullptr, nullptr, false, 0,
+  // Calc is preferred over notepad because notepad will fail to launch on
+  // Windows if the store version is not installed.
+  wchar_t command_line[] = L"calc";
+  ASSERT_TRUE(CreateProcessW(nullptr, command_line, nullptr, nullptr, false, 0,
                              nullptr, nullptr, &si, &pi));
   base::win::ScopedProcessInformation process_info(pi);
 
diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h
index 89f4780..be6c89e 100644
--- a/sandbox/win/src/sandbox_policy.h
+++ b/sandbox/win/src/sandbox_policy.h
@@ -42,8 +42,8 @@
 enum class Semantics {
   kFilesAllowAny,       // Allows open or create for any kind of access that
                         // the file system supports.
-  kFilesAllowReadonly,  // Allows open or create with read access only.
-  kFilesAllowQuery,     // Allows access to query the attributes of a file.
+  kFilesAllowReadonly,  // Allows open or create with read access only
+                        // (includes access to query the attributes of a file).
   kNamedPipesAllowAny,  // Allows creation of a named pipe.
   kFakeGdiInit,         // Fakes user32 and gdi32 initialization. This can
                         // be used to allow the DLLs to load and initialize
diff --git a/sandbox/win/src/unload_dll_test.cc b/sandbox/win/src/unload_dll_test.cc
index b6724d8..136666d 100644
--- a/sandbox/win/src/unload_dll_test.cc
+++ b/sandbox/win/src/unload_dll_test.cc
@@ -46,9 +46,9 @@
   auto runner = std::make_unique<TestRunner>();
   runner->SetTestState(BEFORE_REVERT);
   runner->SetTimeout(2000);
-  // Add a registry rule, because that ensures that the interception agent has
+  // Add a file rule, because that ensures that the interception agent has
   // more than one item in its internal table.
-  runner->AddRule(SubSystem::kFiles, Semantics::kFilesAllowQuery,
+  runner->AddRule(SubSystem::kFiles, Semantics::kFilesAllowReadonly,
                   L"\\??\\*.exe");
   return runner;
 }
@@ -91,9 +91,9 @@
   // Add a couple of rules that ensures that the interception agent add EAT
   // patching on the client which makes sure that the unload dll record does
   // not interact badly with them.
-  runner->AddRule(SubSystem::kFiles, Semantics::kFilesAllowQuery,
+  runner->AddRule(SubSystem::kFiles, Semantics::kFilesAllowReadonly,
                   L"\\??\\*.exe");
-  runner->AddRule(SubSystem::kFiles, Semantics::kFilesAllowQuery,
+  runner->AddRule(SubSystem::kFiles, Semantics::kFilesAllowReadonly,
                   L"\\??\\*.log");
   return runner;
 }
diff --git a/sandbox/win/src/win_utils_unittest.cc b/sandbox/win/src/win_utils_unittest.cc
index 30eb661..7337c97 100644
--- a/sandbox/win/src/win_utils_unittest.cc
+++ b/sandbox/win/src/win_utils_unittest.cc
@@ -52,6 +52,11 @@
     return true;
   }
   modules.resize(size_needed / sizeof(HMODULE));
+  // Avoid the undefined-behavior of calling modules[0] on an empty list. This
+  // can happen if the process has not yet started or has already exited.
+  if (modules.size() == 0) {
+    return false;
+  }
   if (EnumProcessModules(
           process, &modules[0],
           base::checked_cast<DWORD>(modules.size() * sizeof(HMODULE)),
@@ -228,7 +233,11 @@
   using sandbox::GetProcessBaseAddress;
   STARTUPINFO start_info = {};
   PROCESS_INFORMATION proc_info = {};
-  WCHAR command_line[] = L"notepad";
+  // The child process for this test must be a GUI app so that WaitForInputIdle
+  // can be used to guarantee that the child process has started but has not
+  // exited. notepad was used but will fail on Windows 11 if the store version
+  // of notepad is not installed.
+  WCHAR command_line[] = L"calc";
   start_info.cb = sizeof(start_info);
   start_info.dwFlags = STARTF_USESHOWWINDOW;
   start_info.wShowWindow = SW_HIDE;
diff --git a/services/audio/BUILD.gn b/services/audio/BUILD.gn
index c3ebab2d..98ec0c8 100644
--- a/services/audio/BUILD.gn
+++ b/services/audio/BUILD.gn
@@ -79,6 +79,10 @@
     "//build:chromeos_buildflags",
   ]
 
+  if (is_android) {
+    deps += [ ":audio_service_jni_headers" ]
+  }
+
   public_deps = [
     "//base",
     "//media",
@@ -130,6 +134,12 @@
   ]
 }
 
+if (is_android) {
+  generate_jni("audio_service_jni_headers") {
+    sources = [ "public/java/src/org/chromium/audio/AudioFeatureList.java" ]
+  }
+}
+
 # NOTE: This is its own component target because it exposes static storage
 # consumed by multiple binary targets that get linked together (e.g.
 # content/utility and content_browsertests in a component build). Consider
diff --git a/services/audio/public/cpp/BUILD.gn b/services/audio/public/cpp/BUILD.gn
index 76e79e1..d7d46af 100644
--- a/services/audio/public/cpp/BUILD.gn
+++ b/services/audio/public/cpp/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/features.gni")
+
 component("cpp") {
   sources = [
     "audio_system_to_service_adapter.cc",
@@ -36,6 +38,29 @@
   output_name = "audio_public_cpp"
 }
 
+component("audio_features") {
+  public = [ "audio_features.h" ]
+  sources = [
+    "audio_features.cc",
+    "audio_features_export.h",
+  ]
+  configs += [ "//build/config/compiler:wexit_time_destructors" ]
+  public_deps = [ "//base" ]
+
+  defines = [ "AUDIO_FEATURES_IMPLEMENTATION" ]
+}
+
+if (is_android) {
+  source_set("audio_feature_list") {
+    sources = [ "audio_feature_list.cc" ]
+    deps = [
+      ":audio_features",
+      "//base",
+      "//services/audio:audio_service_jni_headers",
+    ]
+  }
+}
+
 source_set("test_support") {
   testonly = true
 
diff --git a/services/audio/public/cpp/audio_feature_list.cc b/services/audio/public/cpp/audio_feature_list.cc
new file mode 100644
index 0000000..72d8c5b
--- /dev/null
+++ b/services/audio/public/cpp/audio_feature_list.cc
@@ -0,0 +1,47 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_string.h"
+#include "base/feature_list.h"
+#include "base/notreached.h"
+#include "services/audio/audio_service_jni_headers/AudioFeatureList_jni.h"
+#include "services/audio/public/cpp/audio_features.h"
+
+using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
+
+namespace features {
+
+namespace {
+
+// Array of features exposed through the Java ContentFeatureList API. Entries in
+// this array may either refer to features defined in the header of this file or
+// in other locations in the code base (e.g. content_features.h).
+const base::Feature* const kFeaturesExposedToJava[] = {
+    &kBlockMidiByDefault,
+};
+
+// TODO(crbug.com/1060097): Removethis once a generalized FeatureList exists.
+const base::Feature* FindFeatureExposedToJava(const std::string& feature_name) {
+  for (const base::Feature* feature : kFeaturesExposedToJava) {
+    if (feature->name == feature_name) {
+      return feature;
+    }
+  }
+  NOTREACHED() << "Queried feature cannot be found in AuiodFeatureList: "
+               << feature_name;
+  return nullptr;
+}
+
+}  // namespace
+
+static jboolean JNI_AudioFeatureList_IsEnabled(
+    JNIEnv* env,
+    const JavaParamRef<jstring>& jfeature_name) {
+  const base::Feature* feature =
+      FindFeatureExposedToJava(ConvertJavaStringToUTF8(env, jfeature_name));
+  return base::FeatureList::IsEnabled(*feature);
+}
+
+}  // namespace features
diff --git a/services/audio/public/cpp/audio_features.cc b/services/audio/public/cpp/audio_features.cc
new file mode 100644
index 0000000..f0e5b45
--- /dev/null
+++ b/services/audio/public/cpp/audio_features.cc
@@ -0,0 +1,14 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/audio/public/cpp/audio_features.h"
+
+namespace features {
+
+// Enables disallowing MIDI permission by default.
+BASE_FEATURE(kBlockMidiByDefault,
+             "BlockMidiByDefault",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+}  // namespace features
diff --git a/services/audio/public/cpp/audio_features.h b/services/audio/public/cpp/audio_features.h
new file mode 100644
index 0000000..0d5c18d
--- /dev/null
+++ b/services/audio/public/cpp/audio_features.h
@@ -0,0 +1,23 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines all the public base::FeatureList features for the
+// services/audio module.
+
+#ifndef SERVICES_AUDIO_PUBLIC_CPP_AUDIO_FEATURES_H_
+#define SERVICES_AUDIO_PUBLIC_CPP_AUDIO_FEATURES_H_
+
+#include "base/feature_list.h"
+#include "build/build_config.h"
+#include "services/audio/public/cpp/audio_features_export.h"
+
+namespace features {
+
+// The features should be documented alongside the definition of their values
+// in the .cc file.
+AUDIO_FEATURES_EXPORT BASE_DECLARE_FEATURE(kBlockMidiByDefault);
+
+}  // namespace features
+
+#endif  // SERVICES_AUDIO_PUBLIC_CPP_AUDIO_FEATURES_H_
diff --git a/services/audio/public/cpp/audio_features_export.h b/services/audio/public/cpp/audio_features_export.h
new file mode 100644
index 0000000..5b3e8eb6
--- /dev/null
+++ b/services/audio/public/cpp/audio_features_export.h
@@ -0,0 +1,34 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_AUDIO_PUBLIC_CPP_AUDIO_FEATURES_EXPORT_H_
+#define SERVICES_AUDIO_PUBLIC_CPP_AUDIO_FEATURES_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+
+#if defined(WIN32)
+
+#if defined(AUDIO_FEATURES_IMPLEMENTATION)
+#define AUDIO_FEATURES_EXPORT __declspec(dllexport)
+#else
+#define AUDIO_FEATURES_EXPORT __declspec(dllimport)
+#endif
+
+#else  // !defined(WIN32)
+
+#if defined(AUDIO_FEATURES_IMPLEMENTATION)
+#define AUDIO_FEATURES_EXPORT __attribute__((visibility("default")))
+#else
+#define AUDIO_FEATURES_EXPORT
+#endif
+
+#endif
+
+#else  // !defined(COMPONENT_BUILD)
+
+#define AUDIO_FEATURES_EXPORT
+
+#endif
+
+#endif  // SERVICES_AUDIO_PUBLIC_CPP_AUDIO_FEATURES_EXPORT_H_
diff --git a/services/audio/public/java/src/org/chromium/audio/AudioFeatureList.java b/services/audio/public/java/src/org/chromium/audio/AudioFeatureList.java
new file mode 100644
index 0000000..9e120dd
--- /dev/null
+++ b/services/audio/public/java/src/org/chromium/audio/AudioFeatureList.java
@@ -0,0 +1,43 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.audio;
+
+import org.chromium.base.FeatureList;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
+import org.chromium.build.annotations.MainDex;
+
+/**
+ * Provides an API for querying the status of Audio Service Features.
+ */
+// TODO(crbug.com/1060097): Remove/update this once a generalized FeatureList exists.
+@JNINamespace("features")
+@MainDex
+public class AudioFeatureList {
+    public static final String BLOCK_MIDI_BY_DEFAULT = "BlockMidiByDefault";
+
+    private AudioFeatureList() {}
+
+    /**
+     * Returns whether the specified feature is enabled or not.
+     *
+     * Note: Features queried through this API must be added to the array
+     * |kFeaturesExposedToJava| in //services/audio/public/cpp/audio_feature_list.cc.
+     *
+     * @param featureName The name of the feature to query.
+     * @return Whether the feature is enabled or not.
+     */
+    public static boolean isEnabled(String featureName) {
+        Boolean testValue = FeatureList.getTestValueForFeature(featureName);
+        if (testValue != null) return testValue;
+        assert FeatureList.isNativeInitialized();
+        return AudioFeatureListJni.get().isEnabled(featureName);
+    }
+
+    @NativeMethods
+    interface Natives {
+        boolean isEnabled(String featureName);
+    }
+}
diff --git a/services/cert_verifier/cert_verifier_service_unittest.cc b/services/cert_verifier/cert_verifier_service_unittest.cc
index 5f549b2..253014f 100644
--- a/services/cert_verifier/cert_verifier_service_unittest.cc
+++ b/services/cert_verifier/cert_verifier_service_unittest.cc
@@ -30,6 +30,7 @@
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/crl_set.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/log/net_log.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
@@ -83,6 +84,7 @@
 
     if (sync_response_params_.find(params) != sync_response_params_.end()) {
       verify_result->cert_status = kExpectedCertStatus;
+      verify_result->verified_cert = params.certificate();
       return kExpectedNetError;
     }
 
@@ -120,6 +122,7 @@
     dummy_requests_.erase(it);
     req->cancel_cb.Reset();
     req->verify_result->cert_status = kExpectedCertStatus;
+    req->verify_result->verified_cert = params.certificate();
     std::move(req->callback).Run(kExpectedNetError);
   }
 
@@ -315,6 +318,54 @@
   TestCompletions(5, true);
 }
 
+TEST_F(CertVerifierServiceTest, TestInvalidIntermediate) {
+  auto leaf = GetTestCert();
+
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(
+      net::x509_util::CreateCryptoBuffer(base::StringPiece("F")));
+
+  scoped_refptr<net::X509Certificate> test_cert =
+      net::X509Certificate::CreateFromBuffer(bssl::UpRef(leaf->cert_buffer()),
+                                             std::move(intermediates));
+  ASSERT_TRUE(test_cert);
+
+  net::CertVerifier::RequestParams dummy_params(test_cert, "example.com", 0,
+                                                /*ocsp_response=*/std::string(),
+                                                /*sct_list=*/std::string());
+
+  // Perform a verification request using the Remote<CertVerifierService>,
+  // which forwards to the CertVerifierServiceImpl.
+  DummyCVServiceRequest cv_service_req;
+  mojo::Receiver<mojom::CertVerifierRequest> cv_request_receiver(
+      &cv_service_req);
+
+  cv_service_remote()->Verify(
+      dummy_params,
+      static_cast<uint32_t>(net::NetLogSourceType::CERT_VERIFIER_JOB),
+      /*netlog_source_id=*/1234, base::TimeTicks::Now(),
+      cv_request_receiver.BindNewPipeAndPassRemote());
+
+  // Handle async Mojo request.
+  cv_service_remote().FlushForTesting();
+
+  ASSERT_FALSE(cv_service_req.is_completed);
+  ASSERT_FALSE(cv_service_req.result.verified_cert);
+  dummy_cv()->RespondToRequest(dummy_params);
+
+  // FlushForTesting() so the CertVerifierServiceImpl Mojo response is
+  // handled.
+  cv_service_remote().FlushForTesting();
+
+  // Request should have completed (should not be rejected at deserialization).
+  ASSERT_TRUE(cv_service_req.is_completed);
+  EXPECT_EQ(cv_service_req.net_error, kExpectedNetError);
+  // Check that the invalid intermediate can be successfully round-tripped.
+  ASSERT_TRUE(cv_service_req.result.verified_cert);
+  EXPECT_TRUE(test_cert->EqualsIncludingChain(
+      cv_service_req.result.verified_cert.get()));
+}
+
 TEST_F(CertVerifierServiceTest, TestRequestDisconnectionCancelsCVRequest) {
   net::CertVerifier::RequestParams dummy_params(GetTestCert(), "example.com", 0,
                                                 /*ocsp_response=*/std::string(),
diff --git a/services/device/geolocation/network_location_request.cc b/services/device/geolocation/network_location_request.cc
index 75795bc..0dd25117 100644
--- a/services/device/geolocation/network_location_request.cc
+++ b/services/device/geolocation/network_location_request.cc
@@ -79,6 +79,15 @@
                               count, min, max, buckets);
 }
 
+void RecordUmaRequestInterval(base::TimeDelta time_delta) {
+  const int kMin = 1;
+  const int kMax = 11;
+  const int kBuckets = 10;
+  UMA_HISTOGRAM_CUSTOM_COUNTS(
+      "Geolocation.NetworkLocationRequest.RequestInterval",
+      time_delta.InMinutes(), kMin, kMax, kBuckets);
+}
+
 // Local functions
 
 // Returns a URL for a request to the Google Maps geolocation API. If the
@@ -136,6 +145,10 @@
     url_loader_.reset();
   }
   wifi_data_ = wifi_data;
+
+  if (!wifi_timestamp_.is_null()) {
+    RecordUmaRequestInterval(wifi_timestamp - wifi_timestamp_);
+  }
   wifi_timestamp_ = wifi_timestamp;
 
   net::NetworkTrafficAnnotationTag traffic_annotation =
diff --git a/services/device/geolocation/wifi_data_provider_chromeos.cc b/services/device/geolocation/wifi_data_provider_chromeos.cc
index e04ec58..7b4cbf6 100644
--- a/services/device/geolocation/wifi_data_provider_chromeos.cc
+++ b/services/device/geolocation/wifi_data_provider_chromeos.cc
@@ -8,6 +8,7 @@
 
 #include <stdint.h>
 
+#include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
 #include "base/ranges/algorithm.h"
@@ -16,6 +17,7 @@
 #include "chromeos/ash/components/network/geolocation_handler.h"
 #include "chromeos/ash/components/network/network_handler.h"
 #include "services/device/geolocation/wifi_data_provider_handle.h"
+#include "services/device/public/cpp/device_features.h"
 
 using ::ash::NetworkHandler;
 
@@ -29,6 +31,10 @@
 const int kTwoNoChangePollingIntervalMilliseconds = 10 * 60 * 1000;  // 10 mins
 const int kNoWifiPollingIntervalMilliseconds = 20 * 1000;            // 20s
 
+// Experimental polling interval for kCrOSGeolocationReducedWifiPollingInterval
+// flag.
+const int kOneMinPollingIntervalMilliseconds = 60 * 1000;  // 1 min
+
 // The mobile location service (MLS) imposes a hard-coded limit on the number of
 // access points that can be used to generate a position estimate.
 constexpr size_t kApUseLimit = 20;
@@ -119,6 +125,15 @@
 
 std::unique_ptr<WifiPollingPolicy>
 WifiDataProviderChromeOs::CreatePollingPolicy() {
+  // Experiment for using shorter wifi polling interval to get updated wifi data
+  // sooner.
+  if (base::FeatureList::IsEnabled(
+          features::kCrOSGeolocationReducedWifiPollingInterval)) {
+    return std::make_unique<GenericWifiPollingPolicy<
+        kDefaultPollingIntervalMilliseconds, kOneMinPollingIntervalMilliseconds,
+        kOneMinPollingIntervalMilliseconds,
+        kNoWifiPollingIntervalMilliseconds>>();
+  }
   return std::make_unique<GenericWifiPollingPolicy<
       kDefaultPollingIntervalMilliseconds, kNoChangePollingIntervalMilliseconds,
       kTwoNoChangePollingIntervalMilliseconds,
diff --git a/services/device/hid/hid_device_info.cc b/services/device/hid/hid_device_info.cc
index 959bd47..6b7939d5 100644
--- a/services/device/hid/hid_device_info.cc
+++ b/services/device/hid/hid_device_info.cc
@@ -5,7 +5,7 @@
 #include "services/device/hid/hid_device_info.h"
 
 #include "base/containers/contains.h"
-#include "base/guid.h"
+#include "base/uuid.h"
 #include "build/build_config.h"
 #include "services/device/public/cpp/hid/hid_blocklist.h"
 #include "services/device/public/cpp/hid/hid_report_descriptor.h"
@@ -85,8 +85,8 @@
   platform_device_id_map_.emplace_back(report_ids, platform_device_id);
 
   device_ = mojom::HidDeviceInfo::New(
-      base::GenerateGUID(), physical_device_id, vendor_id, product_id,
-      product_name, serial_number, bus_type,
+      base::Uuid::GenerateRandomV4().AsLowercaseString(), physical_device_id,
+      vendor_id, product_id, product_name, serial_number, bus_type,
       std::vector<uint8_t>(report_descriptor.begin(), report_descriptor.end()),
       std::move(collections), has_report_id, max_input_report_size,
       max_output_report_size, max_feature_report_size, device_node,
@@ -127,8 +127,8 @@
       HidBlocklist::Get().IsVendorProductBlocked(vendor_id, product_id);
 
   device_ = mojom::HidDeviceInfo::New(
-      base::GenerateGUID(), physical_device_id, vendor_id, product_id,
-      product_name, serial_number, bus_type,
+      base::Uuid::GenerateRandomV4().AsLowercaseString(), physical_device_id,
+      vendor_id, product_id, product_name, serial_number, bus_type,
       /*report_descriptor=*/std::vector<uint8_t>{}, std::move(collections),
       has_report_id, max_input_report_size, max_output_report_size,
       max_feature_report_size, /*device_node=*/"", protected_input_report_ids,
diff --git a/services/device/public/cpp/device_features.cc b/services/device/public/cpp/device_features.cc
index e40e7409..2d2bb27 100644
--- a/services/device/public/cpp/device_features.cc
+++ b/services/device/public/cpp/device_features.cc
@@ -26,5 +26,10 @@
 BASE_FEATURE(kAsyncSensorCalls,
              "AsyncSensorCalls",
              base::FEATURE_ENABLED_BY_DEFAULT);
+// Reduces the interval between WiFi polls to fetch new WiFi data sooner. This
+// can be useful in situations where new WiFi data is needed frequently.
+BASE_FEATURE(kCrOSGeolocationReducedWifiPollingInterval,
+             "ReducedWifiPollingInterval",
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 }  // namespace features
diff --git a/services/device/public/cpp/device_features.h b/services/device/public/cpp/device_features.h
index a75d5f7..ca1bc26 100644
--- a/services/device/public/cpp/device_features.h
+++ b/services/device/public/cpp/device_features.h
@@ -20,6 +20,8 @@
 DEVICE_FEATURES_EXPORT BASE_DECLARE_FEATURE(kWinrtGeolocationImplementation);
 DEVICE_FEATURES_EXPORT BASE_DECLARE_FEATURE(kMacCoreLocationBackend);
 DEVICE_FEATURES_EXPORT BASE_DECLARE_FEATURE(kAsyncSensorCalls);
+DEVICE_FEATURES_EXPORT BASE_DECLARE_FEATURE(
+    kCrOSGeolocationReducedWifiPollingInterval);
 
 }  // namespace features
 
diff --git a/services/device/public/cpp/hid/hid_blocklist_unittest.cc b/services/device/public/cpp/hid/hid_blocklist_unittest.cc
index 5cd37333..96373aa0 100644
--- a/services/device/public/cpp/hid/hid_blocklist_unittest.cc
+++ b/services/device/public/cpp/hid/hid_blocklist_unittest.cc
@@ -5,10 +5,10 @@
 #include "services/device/public/cpp/hid/hid_blocklist.h"
 
 #include "base/command_line.h"
-#include "base/guid.h"
 #include "base/memory/raw_ref.h"
 #include "base/strings/string_piece.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/uuid.h"
 #include "services/device/public/cpp/hid/hid_switches.h"
 #include "services/device/public/cpp/test/hid_test_util.h"
 #include "services/device/public/cpp/test/test_report_descriptors.h"
@@ -72,7 +72,7 @@
       collection->feature_reports.push_back(std::move(report));
 
     auto device = mojom::HidDeviceInfo::New();
-    device->guid = base::GenerateGUID();
+    device->guid = base::Uuid::GenerateRandomV4().AsLowercaseString();
     device->vendor_id = vendor_id;
     device->product_id = product_id;
     device->has_report_id = has_report_id;
@@ -125,7 +125,7 @@
     }
 
     auto device = mojom::HidDeviceInfo::New();
-    device->guid = base::GenerateGUID();
+    device->guid = base::Uuid::GenerateRandomV4().AsLowercaseString();
     device->vendor_id = vendor_id;
     device->product_id = product_id;
     device->has_report_id = true;
@@ -223,7 +223,7 @@
 
 TEST_F(HidBlocklistTest, UnexcludedDeviceWithNoCollections) {
   auto device = mojom::HidDeviceInfo::New();
-  device->guid = base::GenerateGUID();
+  device->guid = base::Uuid::GenerateRandomV4().AsLowercaseString();
   device->vendor_id = kTestVendorId;
   device->product_id = kTestProductId;
   EXPECT_FALSE(device->is_excluded_by_blocklist);
diff --git a/services/device/public/cpp/test/fake_hid_manager.cc b/services/device/public/cpp/test/fake_hid_manager.cc
index 689c5bb..fbcbb251 100644
--- a/services/device/public/cpp/test/fake_hid_manager.cc
+++ b/services/device/public/cpp/test/fake_hid_manager.cc
@@ -8,7 +8,7 @@
 #include <utility>
 
 #include "base/containers/contains.h"
-#include "base/guid.h"
+#include "base/uuid.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "services/device/public/cpp/hid/hid_blocklist.h"
@@ -237,7 +237,7 @@
   collection->input_reports.push_back(mojom::HidReportDescription::New());
 
   auto device = mojom::HidDeviceInfo::New();
-  device->guid = base::GenerateGUID();
+  device->guid = base::Uuid::GenerateRandomV4().AsLowercaseString();
   device->physical_device_id = physical_device_id;
   device->vendor_id = vendor_id;
   device->product_id = product_id;
diff --git a/services/device/public/cpp/test/fake_usb_device_info.cc b/services/device/public/cpp/test/fake_usb_device_info.cc
index ce8fbc2..dd4ee7d 100644
--- a/services/device/public/cpp/test/fake_usb_device_info.cc
+++ b/services/device/public/cpp/test/fake_usb_device_info.cc
@@ -6,8 +6,8 @@
 
 #include <utility>
 
-#include "base/guid.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/uuid.h"
 #include "services/device/public/cpp/usb/usb_utils.h"
 
 namespace device {
@@ -27,7 +27,7 @@
                                      const std::string& manufacturer_string,
                                      const std::string& product_string,
                                      const std::string& serial_number) {
-  device_info_.guid = base::GenerateGUID();
+  device_info_.guid = base::Uuid::GenerateRandomV4().AsLowercaseString();
   device_info_.usb_version_major = usb_version >> 8;
   device_info_.usb_version_minor = usb_version >> 4 & 0xf;
   device_info_.usb_version_subminor = usb_version & 0xf;
diff --git a/services/device/public/cpp/test/hid_test_util.cc b/services/device/public/cpp/test/hid_test_util.cc
index eb3c1242..fd71bda 100644
--- a/services/device/public/cpp/test/hid_test_util.cc
+++ b/services/device/public/cpp/test/hid_test_util.cc
@@ -4,7 +4,7 @@
 
 #include "services/device/public/cpp/test/hid_test_util.h"
 
-#include "base/guid.h"
+#include "base/uuid.h"
 #include "services/device/public/cpp/hid/hid_blocklist.h"
 #include "services/device/public/cpp/hid/hid_report_descriptor.h"
 #include "services/device/public/mojom/hid.mojom.h"
@@ -16,7 +16,7 @@
     uint16_t product_id,
     base::span<const uint8_t> report_descriptor_data) {
   auto device = mojom::HidDeviceInfo::New();
-  device->guid = base::GenerateGUID();
+  device->guid = base::Uuid::GenerateRandomV4().AsLowercaseString();
   device->vendor_id = vendor_id;
   device->product_id = product_id;
   device->product_name = "Test Device";
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index c1c05950..03339e6 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -7796,18 +7796,21 @@
       net::HttpRequestHeaders headers,
       int options = mojom::kURLLoadOptionNone,
       mojom::RequestMode mode = mojom::RequestMode::kNoCors,
-      net::HttpRequestHeaders cors_exempt_headers = net::HttpRequestHeaders()) {
-    CreateLoaderAndStart(InitializeURLLoaderFactory(options),
-                         BuildResourceRequest(url, std::move(headers), mode,
-                                              std::move(cors_exempt_headers)),
-                         options);
+      net::HttpRequestHeaders cors_exempt_headers = net::HttpRequestHeaders(),
+      bool set_request_body = false) {
+    CreateLoaderAndStart(
+        InitializeURLLoaderFactory(options),
+        BuildResourceRequest(url, std::move(headers), mode,
+                             std::move(cors_exempt_headers), set_request_body),
+        options);
   }
 
   ResourceRequest BuildResourceRequest(
       const GURL& url,
       net::HttpRequestHeaders headers,
       mojom::RequestMode mode,
-      net::HttpRequestHeaders cors_exempt_headers) {
+      net::HttpRequestHeaders cors_exempt_headers,
+      bool set_request_body = false) {
     ResourceRequest request;
     request.url = url;
     request.method = "GET";
@@ -7818,6 +7821,9 @@
     request.trusted_params = ResourceRequest::TrustedParams();
     request.trusted_params->allow_cookies_from_browser =
         AllowCookiesFromBrowser();
+    if (set_request_body) {
+      request.request_body = new network::ResourceRequestBody();
+    }
     return request;
   }
 
@@ -7992,6 +7998,28 @@
   ValidateRequestHeaderValue(kHeader2Name, kHeader2Value);
 }
 
+TEST_P(NetworkContextBrowserCookieTest, RequestWithBody) {
+  StartLoadingURL(test_server()->GetURL("/echo"), GenerateTestRequestHeaders(),
+                  mojom::kURLLoadOptionNone, mojom::RequestMode::kNoCors,
+                  net::HttpRequestHeaders(),
+                  /*set_request_body=*/true);
+  url_loader_client()->RunUntilComplete();
+  EXPECT_EQ(net::OK, url_loader_client()->completion_status().error_code);
+
+  // Confirm that the processed request contains the expected headers.
+  if (AllowCookiesFromBrowser()) {
+    // Only the non-existing new cookie is added.
+    ValidateRequestHeaderValue(
+        net::HttpRequestHeaders::kCookie,
+        base::JoinString({kCookie1, kCookie2, kCookie3}, "; "));
+  } else {
+    ValidateRequestHeaderValue(net::HttpRequestHeaders::kCookie,
+                               base::JoinString({kCookie1, kCookie2}, "; "));
+  }
+  ValidateRequestHeaderValue(kHeader1Name, kHeader1Value);
+  ValidateRequestHeaderValue(kHeader2Name, kHeader2Value);
+}
+
 // Request cookies should still be stored even when a header client is present.
 TEST_P(NetworkContextBrowserCookieTest, HeaderClient) {
   ResourceRequest request = BuildResourceRequest(
diff --git a/services/network/shared_dictionary/shared_dictionary_disk_cache.cc b/services/network/shared_dictionary/shared_dictionary_disk_cache.cc
index 4b4ff62..ddb3e50 100644
--- a/services/network/shared_dictionary/shared_dictionary_disk_cache.cc
+++ b/services/network/shared_dictionary/shared_dictionary_disk_cache.cc
@@ -138,8 +138,12 @@
     backend_ = std::move(result.backend);
   }
   auto tasks = std::move(pending_disk_cache_tasks_);
+  base::WeakPtr<SharedDictionaryDiskCache> weak_ptr = GetWeakPtr();
   for (auto& task : tasks) {
     std::move(task).Run();
+    if (!weak_ptr) {
+      return;
+    }
   }
 }
 
diff --git a/services/network/shared_dictionary/shared_dictionary_disk_cache_unittest.cc b/services/network/shared_dictionary/shared_dictionary_disk_cache_unittest.cc
index 9b9d6d53..26fc51a8 100644
--- a/services/network/shared_dictionary/shared_dictionary_disk_cache_unittest.cc
+++ b/services/network/shared_dictionary/shared_dictionary_disk_cache_unittest.cc
@@ -309,6 +309,21 @@
   EXPECT_EQ(net::ERR_FAILED, ClearAll(disk_cache.get()));
 }
 
+TEST_F(SharedDictionaryDiskCacheTest, DeletedWhileRuningDidCreateBackend) {
+  // Corrupt the disk cache so that the callback is called synchronously.
+  CorruptDiskCache();
+
+  std::unique_ptr<SharedDictionaryDiskCache> disk_cache = CreateDiskCache();
+
+  // Test that UAF doesn't happen when `disk_cache` is synchronously deleted in
+  // the callback.
+  disk_cache->DoomEntry(
+      kTestKey, base::BindLambdaForTesting([&](int) { disk_cache.reset(); }));
+  disk_cache->DoomEntry(kTestKey,
+                        base::BindOnce([](int) { ASSERT_TRUE(false); }));
+  FlushCacheTasks();
+}
+
 #endif  // !BUILDFLAG(IS_FUCHSIA)
 
 }  // namespace network
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index bd09094..f2fa6521 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -644,6 +644,13 @@
         request.trusted_params->allow_cookies_from_browser;
   }
 
+  // Store any cookies passed from the browser process to later attach them to
+  // the request.
+  if (allow_cookies_from_browser_) {
+    cookies_from_browser_ =
+        GetCookiesFromHeaders(request.headers, request.cors_exempt_headers);
+  }
+
   throttling_token_ = network::ScopedThrottlingToken::MaybeCreate(
       url_request_->net_log().source().id, request.throttling_profile_id);
 
@@ -749,13 +756,6 @@
     return;
   }
 
-  // Store any cookies passed from the browser process to later attach them to
-  // the request.
-  if (allow_cookies_from_browser_) {
-    cookies_from_browser_ =
-        GetCookiesFromHeaders(request.headers, request.cors_exempt_headers);
-  }
-
   BeginTrustTokenOperationIfNecessaryAndThenScheduleStart(request);
 }
 
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 9241544d..4d13b30 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -46,6 +46,8 @@
     "SK_DISABLE_LEGACY_MAKE_TEXTURE_IMAGE",
     "SK_DISABLE_LEGACY_IMAGE_FLUSH",
     "SK_DISABLE_LEGACY_GET_BACKEND_TEXTURE",
+    "SK_DISABLE_LEGACY_IMAGE_ENCODE_METHODS",
+    "SK_DISABLE_LEGACY_IMAGE_ENCODER",
   ]
 
   include_dirs = [ "//third_party/skia" ]
@@ -316,6 +318,9 @@
   public += skia_effects_imagefilter_public
   public += skia_utils_chromium
   public += skia_discardable_memory_chromium
+  public += skia_encode_public
+  public += skia_encode_png_public
+  public += skia_encode_webp_public
 
   # The imported Skia gni source paths are made absolute by gn.
   defines = []
@@ -339,6 +344,7 @@
     sources += skia_codec_core
     sources += skia_codec_decode_bmp
     sources += skia_encode_jpeg_srcs
+    public += skia_encode_jpeg_public
     sources += [
       "//third_party/skia/src/codec/SkEncodedInfo.cpp",
       "//third_party/skia/src/codec/SkIcoCodec.cpp",
diff --git a/skia/ext/skia_utils_base.cc b/skia/ext/skia_utils_base.cc
index 8cd490c4..7458457 100644
--- a/skia/ext/skia_utils_base.cc
+++ b/skia/ext/skia_utils_base.cc
@@ -10,7 +10,6 @@
 #include "base/strings/stringprintf.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkData.h"
-#include "third_party/skia/include/core/SkEncodedImageFormat.h"
 #include "third_party/skia/include/core/SkImage.h"
 #include "third_party/skia/include/core/SkImageInfo.h"
 #include "third_party/skia/include/core/SkSerialProcs.h"
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index ceff1c7..86456ad 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5621,9 +5621,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5634,8 +5634,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -5653,9 +5653,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.dev.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5666,8 +5666,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
@@ -5786,9 +5786,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5799,8 +5799,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -5817,9 +5817,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5830,8 +5830,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
@@ -5933,9 +5933,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5946,8 +5946,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -5965,9 +5965,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5978,8 +5978,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json
index 7cd3ef04..90c003b 100644
--- a/testing/buildbot/chromium.coverage.json
+++ b/testing/buildbot/chromium.coverage.json
@@ -25211,9 +25211,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25224,8 +25224,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -25243,9 +25243,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.dev.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25256,8 +25256,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
@@ -25376,9 +25376,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25389,8 +25389,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -25407,9 +25407,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25420,8 +25420,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
@@ -25523,9 +25523,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25536,8 +25536,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -25555,9 +25555,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25568,8 +25568,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.dawn.json b/testing/buildbot/chromium.dawn.json
index 941b6c4..b3c54d2 100644
--- a/testing/buildbot/chromium.dawn.json
+++ b/testing/buildbot/chromium.dawn.json
@@ -2574,6 +2574,7 @@
           "--enable-dawn-backend-validation",
           "--jobs=4"
         ],
+        "ci_only": true,
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
@@ -2736,6 +2737,7 @@
           "--enable-dawn-backend-validation",
           "--jobs=4"
         ],
+        "ci_only": true,
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
@@ -4722,6 +4724,7 @@
           "--enable-dawn-backend-validation",
           "--jobs=4"
         ],
+        "ci_only": true,
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
@@ -4884,6 +4887,7 @@
           "--enable-dawn-backend-validation",
           "--jobs=4"
         ],
+        "ci_only": true,
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
           "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
diff --git a/testing/buildbot/chromium.fuchsia.fyi.json b/testing/buildbot/chromium.fuchsia.fyi.json
index d859e912..ff67b9e8 100644
--- a/testing/buildbot/chromium.fuchsia.fyi.json
+++ b/testing/buildbot/chromium.fuchsia.fyi.json
@@ -3489,7 +3489,6 @@
           "dimension_sets": [
             {
               "kvm": "1",
-              "machine_type": "e2-standard-2",
               "os": "Ubuntu-20.04",
               "pool": "chromium.tests.fuchsia"
             }
@@ -3511,7 +3510,6 @@
           "dimension_sets": [
             {
               "kvm": "1",
-              "machine_type": "e2-standard-2",
               "os": "Ubuntu-20.04",
               "pool": "chromium.tests.fuchsia"
             }
@@ -3533,7 +3531,6 @@
           "dimension_sets": [
             {
               "kvm": "1",
-              "machine_type": "e2-standard-2",
               "os": "Ubuntu-20.04",
               "pool": "chromium.tests.fuchsia"
             }
@@ -3555,7 +3552,6 @@
           "dimension_sets": [
             {
               "kvm": "1",
-              "machine_type": "e2-standard-2",
               "os": "Ubuntu-20.04",
               "pool": "chromium.tests.fuchsia"
             }
@@ -3577,7 +3573,6 @@
           "dimension_sets": [
             {
               "kvm": "1",
-              "machine_type": "e2-standard-2",
               "os": "Ubuntu-20.04",
               "pool": "chromium.tests.fuchsia"
             }
@@ -3600,7 +3595,6 @@
           "dimension_sets": [
             {
               "kvm": "1",
-              "machine_type": "e2-standard-2",
               "os": "Ubuntu-20.04",
               "pool": "chromium.tests.fuchsia"
             }
@@ -3622,7 +3616,6 @@
           "dimension_sets": [
             {
               "kvm": "1",
-              "machine_type": "e2-standard-2",
               "os": "Ubuntu-20.04",
               "pool": "chromium.tests.fuchsia"
             }
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 0c004b3d..cffa48e 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -33949,9 +33949,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -33961,8 +33961,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -33981,9 +33981,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.dev.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -33993,8 +33993,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
@@ -34114,9 +34114,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -34126,8 +34126,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -34145,9 +34145,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -34157,8 +34157,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
@@ -34261,9 +34261,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -34273,8 +34273,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -34293,9 +34293,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -34305,8 +34305,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
@@ -35701,9 +35701,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -35713,8 +35713,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -35733,9 +35733,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.dev.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -35745,8 +35745,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
@@ -35866,9 +35866,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -35878,8 +35878,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -35897,9 +35897,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -35909,8 +35909,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
@@ -36013,9 +36013,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -36025,8 +36025,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -36045,9 +36045,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -36057,8 +36057,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
@@ -36742,9 +36742,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -36754,8 +36754,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -36773,9 +36773,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -36785,8 +36785,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index b233455..a6b5975 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -17723,12 +17723,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -17739,8 +17739,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -17758,12 +17758,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.dev.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -17774,8 +17774,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
@@ -17908,12 +17908,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -17924,8 +17924,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -17942,12 +17942,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -17958,8 +17958,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
@@ -18070,12 +18070,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 114.0.5714.0",
+        "description": "Run with ash-chrome version 114.0.5715.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -18086,8 +18086,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5714.0",
-              "revision": "version:114.0.5714.0"
+              "location": "lacros_version_skew_tests_v114.0.5715.0",
+              "revision": "version:114.0.5715.0"
             }
           ],
           "dimension_sets": [
@@ -18105,12 +18105,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 114.0.5703.0",
+        "description": "Run with ash-chrome version 114.0.5707.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -18121,8 +18121,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v114.0.5703.0",
-              "revision": "version:114.0.5703.0"
+              "location": "lacros_version_skew_tests_v114.0.5707.0",
+              "revision": "version:114.0.5707.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/filters/fuchsia.lsan.content_unittests.filter b/testing/buildbot/filters/fuchsia.lsan.content_unittests.filter
index 59c4d3d..466e11436 100644
--- a/testing/buildbot/filters/fuchsia.lsan.content_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.lsan.content_unittests.filter
@@ -8,3 +8,4 @@
 -SharedStorageRunOperationTest*
 -SharedStorageWorkletGlobalScopeTest*
 -SharedStoragePrivateAggregationTest*
+-SharedStoragePrivateAggregationPermissionsPolicyDisabledTest*
\ No newline at end of file
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 589bfc1..08c3f7e 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -4587,6 +4587,12 @@
       'Dawn Linux x64 Release (Intel UHD 630)': {
         'ci_only': True,
       },
+      'Dawn Mac x64 DEPS Release (AMD)': {
+        'ci_only': True,
+      },
+      'Dawn Mac x64 Release (AMD)': {
+        'ci_only': True,
+      },
     },
   },
   'webgpu_swiftshader_web_platform_cts_with_validation_tests': {
@@ -4605,6 +4611,12 @@
       'Dawn Linux x64 Release (Intel UHD 630)': {
         'ci_only': True,
       },
+      'Dawn Mac x64 DEPS Release (AMD)': {
+        'ci_only': True,
+      },
+      'Dawn Mac x64 Release (AMD)': {
+        'ci_only': True,
+      },
     },
   },
   'webkit_unit_tests': {
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 70595d0..b9a30a2 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -22,32 +22,32 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5714.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5715.0/test_ash_chrome',
     ],
-    'description': 'Run with ash-chrome version 114.0.5714.0',
+    'description': 'Run with ash-chrome version 114.0.5715.0',
     'identifier': 'Lacros version skew testing ash canary',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v114.0.5714.0',
-          'revision': 'version:114.0.5714.0',
+          'location': 'lacros_version_skew_tests_v114.0.5715.0',
+          'revision': 'version:114.0.5715.0',
         },
       ],
     },
   },
   'LACROS_VERSION_SKEW_DEV': {
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5703.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v114.0.5707.0/test_ash_chrome',
     ],
-    'description': 'Run with ash-chrome version 114.0.5703.0',
+    'description': 'Run with ash-chrome version 114.0.5707.0',
     'identifier': 'Lacros version skew testing ash dev',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v114.0.5703.0',
-          'revision': 'version:114.0.5703.0',
+          'location': 'lacros_version_skew_tests_v114.0.5707.0',
+          'revision': 'version:114.0.5707.0',
         },
       ],
     },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 76a05d27..3b73f779 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2879,7 +2879,6 @@
           'dimension_sets': [
             {
               'kvm': '1',
-              'machine_type': 'e2-standard-2',
               'pool': 'chromium.tests.fuchsia',
             },
           ],
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index e49f22d..21f56043 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -1437,6 +1437,24 @@
              "ImageLoadingPrioritizationFix",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Boost the priority of the first N not-small images.
+// crbug.com/1431169
+BASE_FEATURE(kBoostImagePriority,
+             "BoostImagePriority",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+// The number of images to bopost the priority of before returning
+// to the default (low) priority.
+const base::FeatureParam<int> kBoostImagePriorityImageCount{
+    &kBoostImagePriority, "image_count", 5};
+// Maximum size of an image (in px^2) to be considered "small".
+// Small images, where dimensions are specified in the markup, are not boosted.
+const base::FeatureParam<int> kBoostImagePriorityImageSize{&kBoostImagePriority,
+                                                           "image_size", 10000};
+// Number of medium-priority requests to allow in tight-mode independent of the
+// total number of outstanding requests.
+const base::FeatureParam<int> kBoostImagePriorityTightMediumLimit{
+    &kBoostImagePriority, "tight_medium_limit", 1};
+
 BASE_FEATURE(kAllowSourceSwitchOnPausedVideoMediaStream,
              "AllowSourceSwitchOnPausedVideoMediaStream",
              base::FEATURE_ENABLED_BY_DEFAULT);
@@ -1656,10 +1674,6 @@
              "SSVTrailerEnforceExposureAssertion",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-BASE_FEATURE(kAbortSignalHandleBasedRemoval,
-             "AbortSignalHandleBasedRemoval",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kForceHighPerformanceGPUForWebGL,
              "ForceHighPerformanceGPUForWebGL",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 8b3bf44..286460af 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -695,6 +695,16 @@
 // applied. See https://crbug.com/1369823.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kImageLoadingPrioritizationFix);
 
+// Boost the priority of the first N not-small images.
+// crbug.com/1431169
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kBoostImagePriority);
+BLINK_COMMON_EXPORT extern const base::FeatureParam<int>
+    kBoostImagePriorityImageCount;
+BLINK_COMMON_EXPORT extern const base::FeatureParam<int>
+    kBoostImagePriorityImageSize;
+BLINK_COMMON_EXPORT extern const base::FeatureParam<int>
+    kBoostImagePriorityTightMediumLimit;
+
 // If enabled, allows MediaStreamVideoSource objects to be restarted by a
 // successful source switch. Normally, switching the source would only allowed
 // on streams that are in started state. However, changing the source also first
@@ -931,9 +941,6 @@
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kSSVTrailerWriteExposureAssertion);
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kSSVTrailerEnforceExposureAssertion);
 
-// Kill switch for AbortSignal algorithm handle-based removal.
-BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kAbortSignalHandleBasedRemoval);
-
 // Forces the attribute powerPreference to be set to "high-performance" for
 // WebGL contexts.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kForceHighPerformanceGPUForWebGL);
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index 1d52fd0..8a00d3e 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -1534,6 +1534,7 @@
       // Setting zoom affects the _EffectiveZoom_, which in turns affects every px value
       // stored on ComputedStyle; see CSSToLengthConversionData::ZoomedComputedPixels.
       supports_incremental_style: false,
+      runtime_flag: "CSSZoom",
     },
     {
       name: "accent-color",
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index 64a109b..ddc408af 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -1551,14 +1551,6 @@
     // place during StyleBuilder::ApplyProperty.
     ApplyLengthConversionFlags(state);
 
-    // AdjustComputedStyle() will set these flags if needed,
-    // but will (generally) not unset them, so reset them before
-    // computation.
-    state.StyleBuilder()
-        .SetInsideFragmentationContextWithNondeterministicEngine(
-            state.ParentStyle()
-                ->InsideFragmentationContextWithNondeterministicEngine());
-
     StyleAdjuster::AdjustComputedStyle(
         state, style_request.IsPseudoStyleRequest() ? nullptr : element);
 
diff --git a/third_party/blink/renderer/core/dom/abort_signal.cc b/third_party/blink/renderer/core/dom/abort_signal.cc
index 40966d05..6949c43e 100644
--- a/third_party/blink/renderer/core/dom/abort_signal.cc
+++ b/third_party/blink/renderer/core/dom/abort_signal.cc
@@ -6,10 +6,8 @@
 
 #include <utility>
 
-#include "base/feature_list.h"
 #include "base/functional/callback.h"
 #include "base/time/time.h"
-#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
 #include "third_party/blink/renderer/core/dom/abort_signal_composition_manager.h"
@@ -72,89 +70,6 @@
   Member<AbortSignal> following_;
 };
 
-// Variant of `AbortAlgorithmCollection` that implements removal. This holds
-// weak references to algorithm handles, leaving the lifetime up to algorithm
-// creators. Used only when features::kAbortSignalHandleBasedRemoval is true.
-class RemovableAbortAlgorithmCollection final
-    : public AbortSignal::AbortAlgorithmCollection {
- public:
-  RemovableAbortAlgorithmCollection() = default;
-  ~RemovableAbortAlgorithmCollection() = default;
-
-  RemovableAbortAlgorithmCollection(const RemovableAbortAlgorithmCollection&) =
-      delete;
-  RemovableAbortAlgorithmCollection& operator=(
-      const RemovableAbortAlgorithmCollection&) = delete;
-
-  void AddAlgorithm(AbortSignal::AlgorithmHandle* handle) override {
-    DCHECK(!abort_algorithms_.Contains(handle));
-    // This always appends since `handle` is not already in the collection.
-    abort_algorithms_.insert(handle);
-  }
-
-  void RemoveAlgorithm(AbortSignal::AlgorithmHandle* handle) override {
-    abort_algorithms_.erase(handle);
-  }
-
-  void Clear() override { abort_algorithms_.clear(); }
-
-  bool Empty() const override { return abort_algorithms_.empty(); }
-
-  void Run() override {
-    for (AbortSignal::AlgorithmHandle* handle : abort_algorithms_) {
-      handle->GetAlgorithm()->Run();
-    }
-  }
-
-  void Trace(Visitor* visitor) const override {
-    visitor->Trace(abort_algorithms_);
-    AbortAlgorithmCollection::Trace(visitor);
-  }
-
- private:
-  HeapLinkedHashSet<WeakMember<AbortSignal::AlgorithmHandle>> abort_algorithms_;
-};
-
-// Variant of `AbortAlgorithmCollection` that does not implement removal. This
-// holds strong references to algorithms, leaving algorithms around for as long
-// as the signal is alive. Enabled when features::kAbortSignalHandleBasedRemoval
-// is false.
-class UnremovableAbortAlgorithmCollection final
-    : public AbortSignal::AbortAlgorithmCollection {
- public:
-  UnremovableAbortAlgorithmCollection() = default;
-  ~UnremovableAbortAlgorithmCollection() = default;
-
-  UnremovableAbortAlgorithmCollection(
-      const UnremovableAbortAlgorithmCollection&) = delete;
-  UnremovableAbortAlgorithmCollection& operator=(
-      const UnremovableAbortAlgorithmCollection&) = delete;
-
-  void AddAlgorithm(AbortSignal::AlgorithmHandle* handle) override {
-    abort_algorithms_.push_back(handle->GetAlgorithm());
-  }
-
-  void RemoveAlgorithm(AbortSignal::AlgorithmHandle* handle) override {}
-
-  void Clear() override { abort_algorithms_.clear(); }
-
-  bool Empty() const override { return abort_algorithms_.empty(); }
-
-  void Run() override {
-    for (AbortSignal::Algorithm* algorithm : abort_algorithms_) {
-      algorithm->Run();
-    }
-  }
-
-  void Trace(Visitor* visitor) const override {
-    visitor->Trace(abort_algorithms_);
-    AbortAlgorithmCollection::Trace(visitor);
-  }
-
- private:
-  HeapVector<Member<AbortSignal::Algorithm>> abort_algorithms_;
-};
-
 }  // namespace
 
 AbortSignal::AbortSignal(ExecutionContext* execution_context)
@@ -199,14 +114,6 @@
          signal_type != SignalType::kComposite);
   execution_context_ = execution_context;
   signal_type_ = signal_type;
-
-  if (base::FeatureList::IsEnabled(features::kAbortSignalHandleBasedRemoval)) {
-    abort_algorithms_ =
-        MakeGarbageCollected<RemovableAbortAlgorithmCollection>();
-  } else {
-    abort_algorithms_ =
-        MakeGarbageCollected<UnremovableAbortAlgorithmCollection>();
-  }
 }
 
 AbortSignal::~AbortSignal() = default;
@@ -305,18 +212,12 @@
     return nullptr;
   }
   auto* handle = MakeGarbageCollected<AlgorithmHandle>(algorithm);
-  abort_algorithms_->AddAlgorithm(handle);
+  CHECK(!abort_algorithms_.Contains(handle));
+  // This always appends since `handle` is not already in the collection.
+  abort_algorithms_.insert(handle);
   return handle;
 }
 
-void AbortSignal::RemoveAlgorithm(AlgorithmHandle* handle) {
-  if (aborted() || (RuntimeEnabledFeatures::AbortSignalCompositionEnabled() &&
-                    composition_manager_->IsSettled())) {
-    return;
-  }
-  abort_algorithms_->RemoveAlgorithm(handle);
-}
-
 AbortSignal::AlgorithmHandle* AbortSignal::AddAlgorithm(
     base::OnceClosure algorithm) {
   if (aborted() || (RuntimeEnabledFeatures::AbortSignalCompositionEnabled() &&
@@ -326,10 +227,20 @@
   auto* callback_algorithm =
       MakeGarbageCollected<OnceCallbackAlgorithm>(std::move(algorithm));
   auto* handle = MakeGarbageCollected<AlgorithmHandle>(callback_algorithm);
-  abort_algorithms_->AddAlgorithm(handle);
+  CHECK(!abort_algorithms_.Contains(handle));
+  // This always appends since `handle` is not already in the collection.
+  abort_algorithms_.insert(handle);
   return handle;
 }
 
+void AbortSignal::RemoveAlgorithm(AlgorithmHandle* handle) {
+  if (aborted() || (RuntimeEnabledFeatures::AbortSignalCompositionEnabled() &&
+                    composition_manager_->IsSettled())) {
+    return;
+  }
+  abort_algorithms_.erase(handle);
+}
+
 void AbortSignal::SignalAbort(ScriptState* script_state) {
   v8::Local<v8::Value> dom_exception = V8ThrowDOMException::CreateOrEmpty(
       script_state->GetIsolate(), DOMExceptionCode::kAbortError,
@@ -352,10 +263,14 @@
   } else {
     abort_reason_ = reason;
   }
-  abort_algorithms_->Run();
+
+  for (AbortSignal::AlgorithmHandle* handle : abort_algorithms_) {
+    handle->GetAlgorithm()->Run();
+  }
+
   if (!RuntimeEnabledFeatures::AbortSignalCompositionEnabled()) {
     // This is cleared when the signal is settled when the feature is enabled.
-    abort_algorithms_->Clear();
+    abort_algorithms_.clear();
   }
   dependent_signal_algorithms_.clear();
   DispatchEvent(*Event::Create(event_type_names::kAbort));
@@ -418,7 +333,7 @@
 void AbortSignal::OnSignalSettled(AbortSignalCompositionType type) {
   DCHECK(RuntimeEnabledFeatures::AbortSignalCompositionEnabled());
   DCHECK_EQ(type, AbortSignalCompositionType::kAbort);
-  abort_algorithms_->Clear();
+  abort_algorithms_.clear();
 }
 
 bool AbortSignal::HasPendingActivity() const {
@@ -433,7 +348,7 @@
   }
   // Otherwise the signal needs to be kept alive if aborting can be observed.
   return HasEventListeners(event_type_names::kAbort) ||
-         !abort_algorithms_->Empty();
+         !abort_algorithms_.empty();
 }
 
 bool AbortSignal::CanAbort() const {
diff --git a/third_party/blink/renderer/core/dom/abort_signal.h b/third_party/blink/renderer/core/dom/abort_signal.h
index e9182cd..747e9e9 100644
--- a/third_party/blink/renderer/core/dom/abort_signal.h
+++ b/third_party/blink/renderer/core/dom/abort_signal.h
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/abort_signal_composition_type.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 
@@ -74,24 +75,6 @@
     Member<Algorithm> algorithm_;
   };
 
-  // The abort algorithm collection functionality is factored out into this
-  // interface so we can have a kill switch for the algorithm handle paths. With
-  // the remove feature enabled, handles are stored weakly and algorithms can
-  // no longer run once the handle is GCed. With the feature disabled, the
-  // algorithms are held with strong references to match the previous behavior.
-  //
-  // TODO(crbug.com/1296280): Remove along with kAbortSignalHandleBasedRemoval.
-  class AbortAlgorithmCollection
-      : public GarbageCollected<AbortAlgorithmCollection> {
-   public:
-    virtual void AddAlgorithm(AlgorithmHandle*) = 0;
-    virtual void RemoveAlgorithm(AlgorithmHandle*) = 0;
-    virtual void Clear() = 0;
-    virtual void Run() = 0;
-    virtual bool Empty() const = 0;
-    virtual void Trace(Visitor*) const {}
-  };
-
   // Constructs a SignalType::kInternal signal. This is only for non web-exposed
   // signals.
   explicit AbortSignal(ExecutionContext*);
@@ -201,7 +184,7 @@
   // ScriptValue::IsUndefined requires callers to enter a V8 context whereas
   // ScriptValue::IsEmpty does not.
   ScriptValue abort_reason_;
-  Member<AbortAlgorithmCollection> abort_algorithms_;
+  HeapLinkedHashSet<WeakMember<AbortSignal::AlgorithmHandle>> abort_algorithms_;
   Member<ExecutionContext> execution_context_;
   SignalType signal_type_;
 
diff --git a/third_party/blink/renderer/core/dom/abort_signal_registry.cc b/third_party/blink/renderer/core/dom/abort_signal_registry.cc
index 2950039..ded2f3d 100644
--- a/third_party/blink/renderer/core/dom/abort_signal_registry.cc
+++ b/third_party/blink/renderer/core/dom/abort_signal_registry.cc
@@ -4,8 +4,6 @@
 
 #include "third_party/blink/renderer/core/dom/abort_signal_registry.h"
 
-#include "base/feature_list.h"
-#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/renderer/core/dom/abort_signal.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
@@ -45,9 +43,6 @@
 void AbortSignalRegistry::RegisterAbortAlgorithm(
     EventListener* listener,
     AbortSignal::AlgorithmHandle* handle) {
-  if (!base::FeatureList::IsEnabled(features::kAbortSignalHandleBasedRemoval)) {
-    return;
-  }
   if (!GetExecutionContext() || GetExecutionContext()->IsContextDestroyed()) {
     return;
   }
diff --git a/third_party/blink/renderer/core/dom/abort_signal_test.cc b/third_party/blink/renderer/core/dom/abort_signal_test.cc
index 81801a78e..3db2a0f 100644
--- a/third_party/blink/renderer/core/dom/abort_signal_test.cc
+++ b/third_party/blink/renderer/core/dom/abort_signal_test.cc
@@ -24,19 +24,6 @@
 
 namespace {
 
-enum class TestType { kRemoveEnabled, kCompositionEnabled, kNoFeatures };
-
-const char* TestTypeToString(TestType test_type) {
-  switch (test_type) {
-    case TestType::kRemoveEnabled:
-      return "RemoveEnabled";
-    case TestType::kCompositionEnabled:
-      return "CompositionEnabled";
-    case TestType::kNoFeatures:
-      return "NoFeatures";
-  }
-}
-
 class TestEventListener : public NativeEventListener {
  public:
   TestEventListener() = default;
@@ -46,29 +33,9 @@
 
 }  // namespace
 
-class AbortSignalTest : public PageTestBase,
-                        public ::testing::WithParamInterface<TestType> {
+class AbortSignalTest : public PageTestBase {
  public:
-  AbortSignalTest() {
-    switch (GetParam()) {
-      case TestType::kRemoveEnabled:
-        feature_list_.InitWithFeatures(
-            {features::kAbortSignalHandleBasedRemoval},
-            {features::kAbortSignalComposition});
-        break;
-      case TestType::kCompositionEnabled:
-        feature_list_.InitWithFeatures(
-            {features::kAbortSignalComposition},
-            {features::kAbortSignalHandleBasedRemoval});
-        break;
-      case TestType::kNoFeatures:
-        feature_list_.InitWithFeatures(
-            {}, {features::kAbortSignalHandleBasedRemoval,
-                 features::kAbortSignalComposition});
-        break;
-    }
-    WebRuntimeFeatures::UpdateStatusFromBaseFeatures();
-  }
+  AbortSignalTest() = default;
 
   void SetUp() override {
     PageTestBase::SetUp();
@@ -91,10 +58,9 @@
   Persistent<AbortController> controller_;
   Persistent<AbortSignal> signal_;
   Persistent<AbortSignal::AlgorithmHandle> abort_handle_;
-  base::test::ScopedFeatureList feature_list_;
 };
 
-TEST_P(AbortSignalTest, AbortAlgorithmRuns) {
+TEST_F(AbortSignalTest, AbortAlgorithmRuns) {
   int count = 0;
   abort_handle_ = signal_->AddAlgorithm(
       WTF::BindOnce([](int* count) { ++(*count); }, WTF::Unretained(&count)));
@@ -110,7 +76,7 @@
   EXPECT_EQ(count, 1);
 }
 
-TEST_P(AbortSignalTest, AbortAlgorithmHandleRemoved) {
+TEST_F(AbortSignalTest, AbortAlgorithmHandleRemoved) {
   int count = 0;
   abort_handle_ = signal_->AddAlgorithm(
       WTF::BindOnce([](int* count) { ++(*count); }, WTF::Unretained(&count)));
@@ -118,10 +84,10 @@
   signal_->RemoveAlgorithm(abort_handle_.Get());
 
   SignalAbort();
-  EXPECT_EQ(count, GetParam() == TestType::kRemoveEnabled ? 0 : 1);
+  EXPECT_EQ(count, 0);
 }
 
-TEST_P(AbortSignalTest, AbortAlgorithmHandleGCed) {
+TEST_F(AbortSignalTest, AbortAlgorithmHandleGCed) {
   int count = 0;
   abort_handle_ = signal_->AddAlgorithm(
       WTF::BindOnce([](int* count) { ++(*count); }, WTF::Unretained(&count)));
@@ -130,10 +96,10 @@
   ThreadState::Current()->CollectAllGarbageForTesting();
 
   SignalAbort();
-  EXPECT_EQ(count, GetParam() == TestType::kRemoveEnabled ? 0 : 1);
+  EXPECT_EQ(count, 0);
 }
 
-TEST_P(AbortSignalTest, RegisteredSignalAlgorithmRuns) {
+TEST_F(AbortSignalTest, RegisteredSignalAlgorithmRuns) {
   int count = 0;
   Persistent<TestEventListener> listener =
       MakeGarbageCollected<TestEventListener>();
@@ -150,7 +116,7 @@
   EXPECT_EQ(count, 1);
 }
 
-TEST_P(AbortSignalTest, RegisteredSignalAlgorithmListenerGCed) {
+TEST_F(AbortSignalTest, RegisteredSignalAlgorithmListenerGCed) {
   int count = 0;
   Persistent<TestEventListener> listener =
       MakeGarbageCollected<TestEventListener>();
@@ -164,18 +130,43 @@
   ThreadState::Current()->CollectAllGarbageForTesting();
 
   SignalAbort();
-  EXPECT_EQ(count, GetParam() == TestType::kRemoveEnabled ? 0 : 1);
+  EXPECT_EQ(count, 0);
 }
 
-INSTANTIATE_TEST_SUITE_P(,
-                         AbortSignalTest,
-                         testing::Values(TestType::kRemoveEnabled,
-                                         TestType::kNoFeatures),
-                         [](const testing::TestParamInfo<TestType>& info) {
-                           return TestTypeToString(info.param);
-                         });
+namespace {
 
-class AbortSignalCompositionTest : public AbortSignalTest {};
+enum class TestType { kCompositionEnabled, kNoFeatures };
+
+const char* TestTypeToString(TestType test_type) {
+  switch (test_type) {
+    case TestType::kCompositionEnabled:
+      return "CompositionEnabled";
+    case TestType::kNoFeatures:
+      return "NoFeatures";
+  }
+}
+
+}  // namespace
+
+class AbortSignalCompositionTest
+    : public AbortSignalTest,
+      public ::testing::WithParamInterface<TestType> {
+ public:
+  AbortSignalCompositionTest() {
+    switch (GetParam()) {
+      case TestType::kCompositionEnabled:
+        feature_list_.InitWithFeatures({features::kAbortSignalComposition}, {});
+        break;
+      case TestType::kNoFeatures:
+        feature_list_.InitWithFeatures({}, {features::kAbortSignalComposition});
+        break;
+    }
+    WebRuntimeFeatures::UpdateStatusFromBaseFeatures();
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
 
 TEST_P(AbortSignalCompositionTest, CanAbort) {
   EXPECT_TRUE(signal_->CanAbort());
diff --git a/third_party/blink/renderer/core/html/html_image_element.cc b/third_party/blink/renderer/core/html/html_image_element.cc
index 3c8d5da..a70e232 100644
--- a/third_party/blink/renderer/core/html/html_image_element.cc
+++ b/third_party/blink/renderer/core/html/html_image_element.cc
@@ -831,11 +831,13 @@
   return exists;
 }
 
-FetchParameters::ResourceWidth HTMLImageElement::GetResourceWidth() const {
-  FetchParameters::ResourceWidth resource_width;
+absl::optional<float> HTMLImageElement::GetResourceWidth() const {
+  absl::optional<float> resource_width;
+  float width_value;
   Element* element = source_.Get();
-  resource_width.is_set = SourceSizeValue(element ? element : this,
-                                          GetDocument(), resource_width.width);
+  if (SourceSizeValue(element ? element : this, GetDocument(), width_value)) {
+    resource_width = width_value;
+  }
   return resource_width;
 }
 
diff --git a/third_party/blink/renderer/core/html/html_image_element.h b/third_party/blink/renderer/core/html/html_image_element.h
index 9628c59..202361a4 100644
--- a/third_party/blink/renderer/core/html/html_image_element.h
+++ b/third_party/blink/renderer/core/html/html_image_element.h
@@ -156,7 +156,7 @@
 
   void SetIsFallbackImage() { is_fallback_image_ = true; }
 
-  FetchParameters::ResourceWidth GetResourceWidth() const;
+  absl::optional<float> GetResourceWidth() const;
   float SourceSize(Element&);
 
   void ForceReload() const;
diff --git a/third_party/blink/renderer/core/html/html_image_element_test.cc b/third_party/blink/renderer/core/html/html_image_element_test.cc
index b75e55a2..093e0165 100644
--- a/third_party/blink/renderer/core/html/html_image_element_test.cc
+++ b/third_party/blink/renderer/core/html/html_image_element_test.cc
@@ -65,9 +65,9 @@
   image->setAttribute(html_names::kWidthAttr, "400");
   // TODO(yoav): `width` does not impact resourceWidth until we resolve
   // https://github.com/ResponsiveImagesCG/picture-element/issues/268
-  EXPECT_EQ(500, image->GetResourceWidth().width);
+  EXPECT_EQ(absl::nullopt, image->GetResourceWidth());
   image->setAttribute(html_names::kSizesAttr, "100vw");
-  EXPECT_EQ(500, image->GetResourceWidth().width);
+  EXPECT_EQ(500, image->GetResourceWidth());
 }
 
 TEST_F(HTMLImageElementTest, sourceSize) {
diff --git a/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc b/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
index a35fd41..ff052b1 100644
--- a/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
+++ b/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
@@ -258,7 +258,6 @@
 
     TextPosition position =
         TextPosition(source.CurrentLine(), source.CurrentColumn());
-    FetchParameters::ResourceWidth resource_width;
     float source_size = source_size_;
     bool source_size_set = source_size_set_;
     if (picture_data.picked) {
@@ -271,8 +270,9 @@
             : ResourceFetcher::kImageNotImageSet;
 
     if (source_size_set) {
-      resource_width.width = source_size;
-      resource_width.is_set = true;
+      // resource_width_ may have originally been set by an explicit width
+      // attribute on an img tag but it gets overridden by sizes if present.
+      resource_width_ = source_size;
     }
 
     if (type == absl::nullopt)
@@ -287,7 +287,7 @@
     auto request = PreloadRequest::CreateIfNeeded(
         InitiatorFor(tag_impl_, link_is_modulepreload_), position, url_to_load_,
         predicted_base_url, type.value(), referrer_policy, is_image_set,
-        exclusion_info, resource_width, request_type);
+        exclusion_info, resource_width_, resource_height_, request_type);
     if (!request)
       return nullptr;
 
@@ -416,22 +416,36 @@
                Match(attribute_name, html_names::kFetchpriorityAttr) &&
                priority_hints_origin_trial_enabled_) {
       SetFetchPriorityHint(attribute_value);
+    } else if (Match(attribute_name, html_names::kWidthAttr)) {
+      HTMLDimension dimension;
+      if (ParseDimensionValue(attribute_value, dimension) &&
+          dimension.IsAbsolute()) {
+        resource_width_ = dimension.Value();
+      }
+      if (width_attr_dimension_type_ ==
+              HTMLImageElement::LazyLoadDimensionType::kNotAbsolute &&
+          RuntimeEnabledFeatures::LazyImageLoadingEnabled()) {
+        width_attr_dimension_type_ =
+            HTMLImageElement::GetAttributeLazyLoadDimensionType(
+                attribute_value);
+      }
+    } else if (Match(attribute_name, html_names::kHeightAttr)) {
+      HTMLDimension dimension;
+      if (ParseDimensionValue(attribute_value, dimension) &&
+          dimension.IsAbsolute()) {
+        resource_height_ = dimension.Value();
+      }
+      if (height_attr_dimension_type_ ==
+              HTMLImageElement::LazyLoadDimensionType::kNotAbsolute &&
+          RuntimeEnabledFeatures::LazyImageLoadingEnabled()) {
+        height_attr_dimension_type_ =
+            HTMLImageElement::GetAttributeLazyLoadDimensionType(
+                attribute_value);
+      }
     } else if (loading_attr_value_ == LoadingAttributeValue::kAuto &&
                Match(attribute_name, html_names::kLoadingAttr) &&
                RuntimeEnabledFeatures::LazyImageLoadingEnabled()) {
       loading_attr_value_ = GetLoadingAttributeValue(attribute_value);
-    } else if (width_attr_dimension_type_ ==
-                   HTMLImageElement::LazyLoadDimensionType::kNotAbsolute &&
-               Match(attribute_name, html_names::kWidthAttr) &&
-               RuntimeEnabledFeatures::LazyImageLoadingEnabled()) {
-      width_attr_dimension_type_ =
-          HTMLImageElement::GetAttributeLazyLoadDimensionType(attribute_value);
-    } else if (height_attr_dimension_type_ ==
-                   HTMLImageElement::LazyLoadDimensionType::kNotAbsolute &&
-               Match(attribute_name, html_names::kHeightAttr) &&
-               RuntimeEnabledFeatures::LazyImageLoadingEnabled()) {
-      height_attr_dimension_type_ =
-          HTMLImageElement::GetAttributeLazyLoadDimensionType(attribute_value);
     } else if (Match(attribute_name, html_names::kAttributionsrcAttr)) {
       attributionsrc_attr_set_ = true;
     }
@@ -780,6 +794,8 @@
   bool priority_hints_origin_trial_enabled_;
   const HashSet<String>* disabled_image_types_;
   bool attributionsrc_attr_set_ = false;
+  absl::optional<float> resource_width_;
+  absl::optional<float> resource_height_;
 };
 
 TokenPreloadScanner::TokenPreloadScanner(
diff --git a/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc b/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
index ecedf47..837b907 100644
--- a/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
+++ b/third_party/blink/renderer/core/html/parser/html_preload_scanner_test.cc
@@ -132,7 +132,7 @@
       EXPECT_EQ(type, preload_request_->GetResourceType());
       EXPECT_EQ(url, preload_request_->ResourceURL());
       EXPECT_EQ(base_url, preload_request_->BaseURL().GetString());
-      EXPECT_EQ(width, preload_request_->ResourceWidth());
+      EXPECT_EQ(width, preload_request_->GetResourceWidth().value_or(0));
 
       ClientHintsPreferences preload_preferences;
       for (const auto& value : preload_data_->meta_ch_values) {
diff --git a/third_party/blink/renderer/core/html/parser/html_resource_preloader_test.cc b/third_party/blink/renderer/core/html/parser/html_resource_preloader_test.cc
index ada3399..0fad957 100644
--- a/third_party/blink/renderer/core/html/parser/html_resource_preloader_test.cc
+++ b/third_party/blink/renderer/core/html/parser/html_resource_preloader_test.cc
@@ -59,7 +59,8 @@
         String(), TextPosition::MinimumPosition(), test_case.url,
         KURL(test_case.base_url), ResourceType::kImage,
         network::mojom::ReferrerPolicy(), ResourceFetcher::kImageNotImageSet,
-        nullptr /* exclusion_info */, FetchParameters::ResourceWidth(),
+        nullptr /* exclusion_info */, absl::nullopt /* resource_width */,
+        absl::nullopt /* resource_height */,
         PreloadRequest::kRequestTypePreconnect);
     DCHECK(preload_request);
     if (test_case.is_cors)
diff --git a/third_party/blink/renderer/core/html/parser/preload_request.cc b/third_party/blink/renderer/core/html/parser/preload_request.cc
index d14a411..bca78f2 100644
--- a/third_party/blink/renderer/core/html/parser/preload_request.cc
+++ b/third_party/blink/renderer/core/html/parser/preload_request.cc
@@ -68,7 +68,8 @@
     const network::mojom::ReferrerPolicy referrer_policy,
     ResourceFetcher::IsImageSet is_image_set,
     const ExclusionInfo* exclusion_info,
-    const FetchParameters::ResourceWidth& resource_width,
+    absl::optional<float> resource_width,
+    absl::optional<float> resource_height,
     RequestType request_type) {
   // Never preload data URLs. We also disallow relative ref URLs which become
   // data URLs if the document's URL is a data URL. We don't want to create
@@ -84,7 +85,8 @@
 
   return base::WrapUnique(new PreloadRequest(
       initiator_name, initiator_position, resource_url, base_url, resource_type,
-      resource_width, request_type, referrer_policy, is_image_set));
+      resource_width, resource_height, request_type, referrer_policy,
+      is_image_set));
 }
 
 Resource* PreloadRequest::Start(Document* document) {
@@ -142,6 +144,7 @@
 
   params.SetDefer(defer_);
   params.SetResourceWidth(resource_width_);
+  params.SetResourceHeight(resource_height_);
   params.SetIntegrityMetadata(integrity_metadata_);
   params.SetContentSecurityPolicyNonce(nonce_);
   params.SetParserDisposition(kParserInserted);
diff --git a/third_party/blink/renderer/core/html/parser/preload_request.h b/third_party/blink/renderer/core/html/parser/preload_request.h
index dad33a8..1c3d75c 100644
--- a/third_party/blink/renderer/core/html/parser/preload_request.h
+++ b/third_party/blink/renderer/core/html/parser/preload_request.h
@@ -70,8 +70,8 @@
       const network::mojom::ReferrerPolicy referrer_policy,
       ResourceFetcher::IsImageSet is_image_set,
       const ExclusionInfo* exclusion_info,
-      const FetchParameters::ResourceWidth& resource_width =
-          FetchParameters::ResourceWidth(),
+      const absl::optional<float> resource_width = absl::nullopt,
+      const absl::optional<float> resource_height = absl::nullopt,
       RequestType request_type = kRequestTypePreload);
 
   Resource* Start(Document*);
@@ -99,9 +99,6 @@
   ResourceType GetResourceType() const { return resource_type_; }
 
   const String& ResourceURL() const { return resource_url_; }
-  float ResourceWidth() const {
-    return resource_width_.is_set ? resource_width_.width : 0;
-  }
   const KURL& BaseURL() const { return base_url_; }
   bool IsPreconnect() const { return request_type_ == kRequestTypePreconnect; }
   network::mojom::ReferrerPolicy GetReferrerPolicy() const {
@@ -143,13 +140,17 @@
     is_attribution_reporting_eligible_img_or_script_ = eligible;
   }
 
+  absl::optional<float> GetResourceWidth() const { return resource_width_; }
+  absl::optional<float> GetResourceHeight() const { return resource_height_; }
+
  private:
   PreloadRequest(const String& initiator_name,
                  const TextPosition& initiator_position,
                  const String& resource_url,
                  const KURL& base_url,
                  ResourceType resource_type,
-                 const FetchParameters::ResourceWidth& resource_width,
+                 const absl::optional<float> resource_width,
+                 const absl::optional<float> resource_height,
                  RequestType request_type,
                  const network::mojom::ReferrerPolicy referrer_policy,
                  ResourceFetcher::IsImageSet is_image_set)
@@ -159,6 +160,7 @@
         base_url_(base_url),
         resource_type_(resource_type),
         resource_width_(resource_width),
+        resource_height_(resource_height),
         request_type_(request_type),
         referrer_policy_(referrer_policy),
         is_image_set_(is_image_set) {}
@@ -177,7 +179,8 @@
       mojom::blink::FetchPriorityHint::kAuto;
   String nonce_;
   FetchParameters::DeferOption defer_ = FetchParameters::kNoDefer;
-  const FetchParameters::ResourceWidth resource_width_;
+  const absl::optional<float> resource_width_;
+  const absl::optional<float> resource_height_;
   const RequestType request_type_;
   const network::mojom::ReferrerPolicy referrer_policy_;
   IntegrityMetadataSet integrity_metadata_;
diff --git a/third_party/blink/renderer/core/html/resources/selectmenu.css b/third_party/blink/renderer/core/html/resources/selectmenu.css
index 815ceb9a..cfa65b2f 100644
--- a/third_party/blink/renderer/core/html/resources/selectmenu.css
+++ b/third_party/blink/renderer/core/html/resources/selectmenu.css
@@ -7,22 +7,58 @@
  * (HTMLSelectMenuElement enabled).
  */
 
- @namespace "http://www.w3.org/1999/xhtml";
+@namespace "http://www.w3.org/1999/xhtml";
 
 selectmenu {
   display: inline-block;
   user-select: none;
+  font-family: sans-serif;
+  font-size: .875em;
 }
 
 selectmenu::-internal-selectmenu-button {
   display: inline-flex;
   align-items: center;
-  background-color: -internal-light-dark(#ffffff, #3B3B3B);
-  padding: 0 0 0 3px;
-  border: 1px solid -internal-light-dark(#767676, #858585);
-  border-radius: 2px;
   cursor: default;
   appearance: none;
+  background-color: Field;
+  color: ButtonText;
+  border: 1px solid ButtonBorder;
+  border-radius: 0.25em;
+  padding: 0.25em;
+}
+
+/* TODO(masonf) We need an internal pseudo for the selected value part */
+selectmenu::part(selected-value) {
+  color: HighlightText;
+}
+
+selectmenu option {
+  font-size: .875em;
+  padding: 0.25em;
+}
+
+selectmenu option:hover {
+  cursor: default;
+  user-select: none;
+  background-color: SelectedItem;
+  color: SelectedItemText;
+}
+
+selectmenu optgroup {
+  padding-bottom: 0.75em;
+}
+
+selectmenu optgroup:last-child {
+  padding-bottom: 0;
+}
+
+selectmenu optgroup > option {
+  padding-left: 0.75em;
+}
+
+selectmenu optgroup > option {
+  padding-left: 0.75em;
 }
 
 selectmenu::-internal-selectmenu-button-icon {
@@ -48,15 +84,14 @@
   opacity: 0.7;
 }
 
-selectmenu option:hover {
-  background-color: lightgray;
-  cursor: default;
-  user-select: none;
-}
-
 selectmenu option:disabled {
   background-color: initial;
-  color: -internal-light-dark(rgba(16, 16, 16, 0.3), rgba(255, 255, 255, 0.3));
+  color: GrayText;
+}
+
+/* remove highlight on disabled options, making them visually un-selectable  */
+selectmenu option:disabled:hover {
+  background-color: transparent;
 }
 
 selectmenu option:checked:disabled {
@@ -64,12 +99,13 @@
 }
 
 selectmenu::-internal-selectmenu-listbox {
-  border: 1px solid rgba(0, 0, 0, 0.15);
-  border-radius: 4px;
   box-shadow: 0px 12.8px 28.8px rgba(0, 0, 0, 0.13), 0px 0px 9.2px rgba(0, 0, 0, 0.11);
   box-sizing: border-box;
   overflow: auto;
-  padding: 4px;
+  background-color: Field;
+  border: 1px solid rgba(0, 0, 0, 0.15);
+  border-radius: 0.25em;
+  padding: 0.25em 0;
 }
 
 /* TODO(github.com/openui/open-ui/issues/645): We need a better way to correctly
diff --git a/third_party/blink/renderer/core/layout/geometry/logical_size.h b/third_party/blink/renderer/core/layout/geometry/logical_size.h
index ef65748..aaa4bbc 100644
--- a/third_party/blink/renderer/core/layout/geometry/logical_size.h
+++ b/third_party/blink/renderer/core/layout/geometry/logical_size.h
@@ -56,6 +56,10 @@
   }
 };
 
+inline LogicalSize operator-(const LogicalSize& a, const NGBoxStrut& b) {
+  return {a.inline_size - b.InlineSum(), a.block_size - b.BlockSum()};
+}
+
 inline LogicalSize& operator-=(LogicalSize& a, const NGBoxStrut& b) {
   a.inline_size -= b.InlineSum();
   a.block_size -= b.BlockSum();
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 86b4a436..b8f3389 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -738,8 +738,6 @@
       Parent()->StyleRef().IsDisplayFlexibleOrGridBox())
     ClearOverrideSize();
 
-  UpdateBackgroundAttachmentFixedStatusAfterStyleChange();
-
   if (old_style) {
     // Regular column content (i.e. non-spanners) have a hook into the flow
     // thread machinery before (StyleWillChange()) and after (here in
@@ -822,16 +820,6 @@
   DCHECK(!IsInline() || IsAtomicInlineLevel());
 }
 
-void LayoutBox::UpdateBackgroundAttachmentFixedStatusAfterStyleChange() {
-  NOT_DESTROYED();
-  if (!GetFrameView())
-    return;
-
-  SetIsBackgroundAttachmentFixedObject(
-      !BackgroundTransfersToView() &&
-      StyleRef().HasFixedAttachmentBackgroundImage());
-}
-
 void LayoutBox::UpdateShapeOutsideInfoAfterStyleChange(
     const ComputedStyle& style,
     const ComputedStyle* old_style) {
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index e00c57b..3f3af6d 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -1992,8 +1992,6 @@
 
   void LocationChanged();
 
-  void UpdateBackgroundAttachmentFixedStatusAfterStyleChange();
-
   void InflateVisualRectForFilter(TransformState&) const;
   void InflateVisualRectForFilterUnderContainer(
       TransformState&,
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
index 6c031af..dd8791c 100644
--- a/third_party/blink/renderer/core/layout/layout_box_model_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -350,6 +350,10 @@
     else
       element->RemoveAnchorScrollData();
   }
+
+  SetIsBackgroundAttachmentFixedObject(
+      !BackgroundTransfersToView() &&
+      StyleRef().HasFixedAttachmentBackgroundImage());
 }
 
 void LayoutBoxModelObject::CreateLayerAfterStyleChange() {
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h
index fd7b2ec..4813dc0 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h
@@ -60,7 +60,8 @@
       GridTrackSizingDirection track_direction) const {
     // TODO(ethavar): Baseline alignment for subgrids is dependent on
     // accumulating the baseline in `ComputeSubgridContributionSize`.
-    if (has_subgridded_columns || has_subgridded_rows) {
+    if (has_subgridded_columns || has_subgridded_rows ||
+        is_subgridded_to_parent_grid) {
       return false;
     }
     return (track_direction == kForColumns)
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
index f80d616cb..d4eaf32 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
@@ -403,16 +403,22 @@
 
 MinMaxSizesResult NGGridLayoutAlgorithm::ComputeMinMaxSizes(
     const MinMaxSizesFloatInput&) {
-  DCHECK(!ConstraintSpace().GridLayoutSubtree());
-
   const auto& node = Node();
   const LayoutUnit override_intrinsic_inline_size =
       node.OverrideIntrinsicContentInlineSize();
 
-  if (override_intrinsic_inline_size != kIndefiniteSize) {
-    const LayoutUnit size =
-        BorderScrollbarPadding().InlineSum() + override_intrinsic_inline_size;
+  auto FixedMinMaxSizes = [&](LayoutUnit size) -> MinMaxSizesResult {
+    size += BorderScrollbarPadding().InlineSum();
     return {{size, size}, /* depends_on_block_constraints */ false};
+  };
+
+  if (override_intrinsic_inline_size != kIndefiniteSize) {
+    return FixedMinMaxSizes(override_intrinsic_inline_size);
+  }
+
+  if (const auto* layout_subtree = ConstraintSpace().GridLayoutSubtree()) {
+    return FixedMinMaxSizes(
+        layout_subtree->LayoutData().Columns().ComputeSetSpanSize());
   }
 
   // If we have inline size containment ignore all children.
@@ -481,6 +487,10 @@
   return subgridded_area_in_parent;
 }
 
+bool HasIndefiniteInlineSize(const NGConstraintSpace& constraint_space) {
+  return constraint_space.AvailableSize().inline_size == kIndefiniteSize;
+}
+
 }  // namespace
 
 wtf_size_t NGGridLayoutAlgorithm::BuildGridSizingSubtree(
@@ -602,10 +612,13 @@
 
     NGSubgriddedItemData subgrid_data(grid_item, layout_data);
 
-    NGConstraintSpace unused_space;
-    NGFragmentGeometry unused_fragment_geometry;
-    const auto subgrid_algorithm = CreateSubgridLayoutAlgorithm(
-        subgrid_data, &unused_space, &unused_fragment_geometry);
+    const auto space = CreateConstraintSpaceForSubgridAlgorithm(subgrid_data);
+    const auto fragment_geometry = CalculateInitialFragmentGeometry(
+        space, subgrid_data->node, /* break_token */ nullptr,
+        /* is_intrinsic */ HasIndefiniteInlineSize(space));
+
+    const NGGridLayoutAlgorithm subgrid_algorithm(
+        {subgrid_data->node, fragment_geometry, space});
 
     subtree_size += subgrid_algorithm.BuildGridSizingSubtree(
         sizing_tree, /* oof_children */ nullptr, subgrid_data,
@@ -858,9 +871,6 @@
   }
 
   if (!is_standalone_grid) {
-    DCHECK_NE(grid_available_size_.block_size, kIndefiniteSize)
-        << "The available block size of a subgrid should be resolved by its "
-           "parent grid's sizing algorithm.";
     return;
   }
 
@@ -1031,46 +1041,50 @@
 
   const auto& node = grid_item->node;
   const auto& item_style = node.Style();
-  const auto& layout_data = sizing_subtree.LayoutData();
 
   const bool is_for_columns = track_direction == kForColumns;
   const bool is_parallel_with_track_direction =
       is_for_columns == grid_item->is_parallel_with_root_grid;
 
+  const auto subgridded_item =
+      grid_item->is_subgridded_to_parent_grid
+          ? sizing_subtree.LookupSubgriddedItemData(*grid_item)
+          : NGSubgriddedItemData(*grid_item, sizing_subtree.LayoutData());
+
   // TODO(ikilpatrick): We'll need to record if any child used an indefinite
   // size for its contribution, such that we can then do the 2nd pass on the
   // track-sizing algorithm.
-  const auto space = CreateConstraintSpaceForMeasure(*grid_item, sizing_subtree,
-                                                     track_direction);
-  const auto margins = ComputeMarginsFor(space, item_style, ConstraintSpace());
+  const auto space =
+      grid_item->IsSubgrid()
+          ? CreateConstraintSpaceForSubgridAlgorithm(subgridded_item)
+          : CreateConstraintSpaceForMeasure(subgridded_item, track_direction);
 
   LayoutUnit baseline_shim;
-  auto CalculateBaselineShim = [&](const LayoutUnit baseline) -> void {
-    const LayoutUnit track_baseline =
-        Baseline(layout_data, *grid_item, track_direction);
+  auto CalculateBaselineShim = [&](LayoutUnit baseline) -> void {
+    const auto track_baseline =
+        Baseline(sizing_subtree.LayoutData(), *grid_item, track_direction);
+
     if (track_baseline == LayoutUnit::Min())
       return;
 
-    // Determine the delta between the baselines.
-    baseline_shim = track_baseline - baseline;
-
-    // Subtract out the start margin so it doesn't get added a second time at
-    // the end of |NGGridLayoutAlgorithm::ContributionSizeForGridItem|.
-    baseline_shim -=
+    const auto item_margins =
         ComputeMarginsFor(space, item_style,
-                          grid_item->BaselineWritingDirection(track_direction))
-            .block_start;
+                          grid_item->BaselineWritingDirection(track_direction));
+
+    // Determine the delta between the baselines; subtract out the start margin
+    // so it doesn't get added a second time at the end of this method.
+    baseline_shim = track_baseline - baseline - item_margins.block_start;
   };
 
   auto SubgridContributionSize = [&](bool is_min_content) -> LayoutUnit {
     DCHECK(grid_item->IsSubgrid());
 
     const auto fragment_geometry = CalculateInitialFragmentGeometry(
-        space, grid_item->node, /* break_token */ nullptr,
-        /* is_intrinsic */ !space.IsFixedInlineSize());
+        space, node, /* break_token */ nullptr,
+        /* is_intrinsic */ HasIndefiniteInlineSize(space));
 
-    const auto subgrid_algorithm =
-        NGGridLayoutAlgorithm({grid_item->node, fragment_geometry, space});
+    const NGGridLayoutAlgorithm subgrid_algorithm(
+        {node, fragment_geometry, space});
 
     return subgrid_algorithm.ComputeSubgridContributionSize(
         sizing_subtree.SubgridSizingSubtree(*grid_item),
@@ -1102,7 +1116,7 @@
       grid_item->is_sizing_dependent_on_block_size = true;
     }
 
-    const LayoutUnit content_size =
+    const auto content_size =
         is_min_content ? result.sizes.min_size : result.sizes.max_size;
 
     if (grid_item->IsBaselineAlignedForDirection(track_direction)) {
@@ -1143,7 +1157,7 @@
       // If we are orthogonal grid item, resolving against an indefinite size,
       // set our inline size to our max-content contribution size.
       const auto fallback_space = CreateConstraintSpaceForMeasure(
-          *grid_item, sizing_subtree, track_direction,
+          subgridded_item, track_direction,
           /* opt_fixed_block_size */ MaxContentSize());
 
       result = LayoutGridItemForMeasure(*grid_item, fallback_space,
@@ -1164,8 +1178,17 @@
     return baseline_fragment.BlockSize() + baseline_shim;
   };
 
-  const LayoutUnit margin_sum =
-      is_for_columns ? margins.InlineSum() : margins.BlockSum();
+  const auto& [begin_set_index, end_set_index] =
+      subgridded_item->SetIndices(track_direction);
+  const auto& track_collection =
+      is_for_columns ? subgridded_item.ParentLayoutData().Columns()
+                     : subgridded_item.ParentLayoutData().Rows();
+
+  const auto margins = ComputeMarginsFor(space, item_style, ConstraintSpace());
+  const auto margin_sum =
+      (is_for_columns ? margins.InlineSum() : margins.BlockSum()) +
+      track_collection.StartExtraMargin(begin_set_index) +
+      track_collection.EndExtraMargin(end_set_index);
 
   LayoutUnit contribution;
   switch (contribution_type) {
@@ -1192,7 +1215,7 @@
         case Length::kFillAvailable:
         case Length::kPercent:
         case Length::kCalculated: {
-          const NGBoxStrut border_padding =
+          const auto border_padding =
               ComputeBorders(space, node) + ComputePadding(space, item_style);
 
           // All of the above lengths are considered 'auto' if we are querying a
@@ -1242,13 +1265,9 @@
                              ? MinContentSize()
                              : BlockContributionSize();
 
-          const auto& set_indices = grid_item->SetIndices(track_direction);
-          const auto& track_collection =
-              is_for_columns ? layout_data.Columns() : layout_data.Rows();
-
           auto spanned_tracks_definite_max_size =
-              track_collection.ComputeSetSpanSize(set_indices.begin,
-                                                  set_indices.end);
+              track_collection.ComputeSetSpanSize(begin_set_index,
+                                                  end_set_index);
 
           if (spanned_tracks_definite_max_size != kIndefiniteSize) {
             // Further clamp the minimum size to less than or equal to the
@@ -1683,10 +1702,13 @@
     DCHECK(next_subgrid_subtree);
     NGSubgriddedItemData subgrid_data(grid_item, layout_data);
 
-    NGConstraintSpace unused_space;
-    NGFragmentGeometry unused_fragment_geometry;
-    const auto subgrid_algorithm = CreateSubgridLayoutAlgorithm(
-        subgrid_data, &unused_space, &unused_fragment_geometry);
+    const auto space = CreateConstraintSpaceForSubgridAlgorithm(subgrid_data);
+    const auto fragment_geometry = CalculateInitialFragmentGeometry(
+        space, subgrid_data->node, /* break_token */ nullptr,
+        /* is_intrinsic */ HasIndefiniteInlineSize(space));
+
+    const NGGridLayoutAlgorithm subgrid_algorithm(
+        {subgrid_data->node, fragment_geometry, space});
 
     subgrid_algorithm.InitializeTrackSizes(
         next_subgrid_subtree, subgrid_data,
@@ -1871,10 +1893,13 @@
     DCHECK(next_subgrid_subtree);
     NGSubgriddedItemData subgrid_data(grid_item, layout_data);
 
-    NGConstraintSpace unused_space;
-    NGFragmentGeometry unused_fragment_geometry;
-    const auto subgrid_algorithm = CreateSubgridLayoutAlgorithm(
-        subgrid_data, &unused_space, &unused_fragment_geometry);
+    const auto space = CreateConstraintSpaceForSubgridAlgorithm(subgrid_data);
+    const auto fragment_geometry = CalculateInitialFragmentGeometry(
+        space, subgrid_data->node, /* break_token */ nullptr,
+        /* is_intrinsic */ HasIndefiniteInlineSize(space));
+
+    const NGGridLayoutAlgorithm subgrid_algorithm(
+        {subgrid_data->node, fragment_geometry, space});
 
     subgrid_algorithm.CompleteTrackSizingAlgorithm(
         next_subgrid_subtree, subgrid_data,
@@ -2987,9 +3012,8 @@
 NGConstraintSpace NGGridLayoutAlgorithm::CreateConstraintSpace(
     NGCacheSlot cache_slot,
     const GridItemData& grid_item,
-    const NGGridLayoutData& layout_data,
     const LogicalSize& containing_grid_area_size,
-    absl::optional<LayoutUnit> opt_fixed_block_size,
+    const LogicalSize& fixed_available_size,
     NGGridLayoutSubtree&& opt_layout_subtree,
     bool min_block_size_should_encompass_intrinsic_size,
     absl::optional<LayoutUnit> opt_fragment_relative_block_offset) const {
@@ -3002,24 +3026,23 @@
   builder.SetCacheSlot(cache_slot);
   builder.SetIsPaintedAtomically(true);
 
-  if (opt_fixed_block_size) {
-    builder.SetAvailableSize(
-        {containing_grid_area_size.inline_size, *opt_fixed_block_size});
-    builder.SetIsFixedBlockSize(true);
-  } else {
-    builder.SetAvailableSize(containing_grid_area_size);
-  }
-
-  if (grid_item.IsSubgrid()) {
-    if (opt_layout_subtree) {
-      builder.SetGridLayoutSubtree(std::move(opt_layout_subtree));
-    }
-    if (containing_grid_area_size.inline_size != kIndefiniteSize) {
+  {
+    auto available_size = containing_grid_area_size;
+    if (fixed_available_size.inline_size != kIndefiniteSize) {
+      available_size.inline_size = fixed_available_size.inline_size;
       builder.SetIsFixedInlineSize(true);
     }
-    if (containing_grid_area_size.block_size != kIndefiniteSize) {
+
+    if (fixed_available_size.block_size != kIndefiniteSize) {
+      available_size.block_size = fixed_available_size.block_size;
       builder.SetIsFixedBlockSize(true);
     }
+    builder.SetAvailableSize(available_size);
+  }
+
+  if (opt_layout_subtree) {
+    DCHECK(grid_item.IsSubgrid() && cache_slot == NGCacheSlot::kLayout);
+    builder.SetGridLayoutSubtree(std::move(opt_layout_subtree));
   }
 
   builder.SetPercentageResolutionSize(containing_grid_area_size);
@@ -3048,72 +3071,84 @@
     bool min_block_size_should_encompass_intrinsic_size,
     absl::optional<LayoutUnit> opt_fragment_relative_block_offset) const {
   DCHECK(containing_grid_area);
+  DCHECK(!grid_item.IsSubgrid() || opt_layout_subtree);
 
-  containing_grid_area->size.inline_size =
+  containing_grid_area->size = {
       ComputeGridItemAvailableSize(grid_item, layout_data.Columns(),
-                                   &containing_grid_area->offset.inline_offset);
-
-  containing_grid_area->size.block_size =
+                                   &containing_grid_area->offset.inline_offset),
       ComputeGridItemAvailableSize(grid_item, layout_data.Rows(),
-                                   &containing_grid_area->offset.block_offset);
+                                   &containing_grid_area->offset.block_offset)};
 
-  auto available_size = containing_grid_area->size;
-  if (available_size.block_size != kIndefiniteSize) {
-    available_size.block_size -= unavailable_block_size;
-    DCHECK_GE(available_size.block_size, LayoutUnit());
+  auto containing_grid_area_size = containing_grid_area->size;
+
+  if (containing_grid_area_size.block_size != kIndefiniteSize) {
+    containing_grid_area_size.block_size -= unavailable_block_size;
+    DCHECK_GE(containing_grid_area_size.block_size, LayoutUnit());
   }
 
-  return CreateConstraintSpace(
-      NGCacheSlot::kLayout, grid_item, layout_data, available_size,
-      /* opt_fixed_block_size */ absl::nullopt, std::move(opt_layout_subtree),
-      min_block_size_should_encompass_intrinsic_size,
-      opt_fragment_relative_block_offset);
+  LogicalSize fixed_available_size(kIndefiniteSize, kIndefiniteSize);
+
+  if (grid_item.IsSubgrid()) {
+    const auto [fixed_inline_size, fixed_block_size] = ShrinkLogicalSize(
+        containing_grid_area_size,
+        ComputeMarginsFor(grid_item.node.Style(),
+                          containing_grid_area_size.inline_size,
+                          ConstraintSpace().GetWritingDirection()));
+
+    fixed_available_size = {
+        grid_item.has_subgridded_columns ? fixed_inline_size : kIndefiniteSize,
+        grid_item.has_subgridded_rows ? fixed_block_size : kIndefiniteSize};
+  }
+
+  return CreateConstraintSpace(NGCacheSlot::kLayout, grid_item,
+                               containing_grid_area_size, fixed_available_size,
+                               std::move(opt_layout_subtree),
+                               min_block_size_should_encompass_intrinsic_size,
+                               opt_fragment_relative_block_offset);
 }
 
 NGConstraintSpace NGGridLayoutAlgorithm::CreateConstraintSpaceForMeasure(
-    const GridItemData& grid_item,
-    const NGGridSizingSubtree& sizing_subtree,
+    const NGSubgriddedItemData& subgridded_item,
     GridTrackSizingDirection track_direction,
     absl::optional<LayoutUnit> opt_fixed_block_size) const {
-  const auto subgridded_item =
-      grid_item.is_subgridded_to_parent_grid
-          ? sizing_subtree.LookupSubgriddedItemData(grid_item)
-          : NGSubgriddedItemData(grid_item, sizing_subtree.LayoutData());
+  DCHECK(!subgridded_item.IsSubgrid());
 
   LogicalSize containing_grid_area_size(kIndefiniteSize, kIndefiniteSize);
-  auto& layout_data = subgridded_item.ParentLayoutData();
 
   if (track_direction == kForColumns) {
-    containing_grid_area_size.block_size =
-        ComputeGridItemAvailableSize(*subgridded_item, layout_data.Rows());
+    containing_grid_area_size.block_size = ComputeGridItemAvailableSize(
+        *subgridded_item, subgridded_item.ParentLayoutData().Rows());
   } else {
-    containing_grid_area_size.inline_size =
-        ComputeGridItemAvailableSize(*subgridded_item, layout_data.Columns());
+    containing_grid_area_size.inline_size = ComputeGridItemAvailableSize(
+        *subgridded_item, subgridded_item.ParentLayoutData().Columns());
   }
 
+  const LogicalSize fixed_available_size(
+      kIndefiniteSize, opt_fixed_block_size.value_or(kIndefiniteSize));
+
   return CreateConstraintSpace(NGCacheSlot::kMeasure, *subgridded_item,
-                               layout_data, containing_grid_area_size,
-                               opt_fixed_block_size);
+                               containing_grid_area_size, fixed_available_size);
 }
 
-NGGridLayoutAlgorithm NGGridLayoutAlgorithm::CreateSubgridLayoutAlgorithm(
-    const NGSubgriddedItemData& subgrid_data,
-    NGConstraintSpace* constraint_space,
-    NGFragmentGeometry* fragment_geometry) const {
-  DCHECK(constraint_space && fragment_geometry);
+NGConstraintSpace
+NGGridLayoutAlgorithm::CreateConstraintSpaceForSubgridAlgorithm(
+    const NGSubgriddedItemData& subgrid_data) const {
   DCHECK(subgrid_data.IsSubgrid());
 
-  LogicalRect unused_containing_grid_area;
-  *constraint_space = CreateConstraintSpaceForLayout(
-      *subgrid_data, subgrid_data.ParentLayoutData(),
-      &unused_containing_grid_area);
+  const auto& layout_data = subgrid_data.ParentLayoutData();
 
-  *fragment_geometry = CalculateInitialFragmentGeometry(
-      *constraint_space, subgrid_data->node, /* break_token */ nullptr,
-      /* is_intrinsic */ !constraint_space->IsFixedInlineSize());
+  const LogicalSize containing_grid_area_size(
+      ComputeGridItemAvailableSize(*subgrid_data, layout_data.Columns()),
+      ComputeGridItemAvailableSize(*subgrid_data, layout_data.Rows()));
 
-  return NGGridLayoutAlgorithm(
-      {subgrid_data->node, *fragment_geometry, *constraint_space});
+  const auto fixed_available_size = ShrinkLogicalSize(
+      containing_grid_area_size,
+      ComputeMarginsFor(subgrid_data->node.Style(),
+                        containing_grid_area_size.inline_size,
+                        ConstraintSpace().GetWritingDirection()));
+
+  return CreateConstraintSpace(NGCacheSlot::kMeasure, *subgrid_data,
+                               containing_grid_area_size, fixed_available_size);
 }
 
 namespace {
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
index 5babf21..e8cdbbc9 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
@@ -203,9 +203,8 @@
   NGConstraintSpace CreateConstraintSpace(
       NGCacheSlot cache_slot,
       const GridItemData& grid_item,
-      const NGGridLayoutData& layout_data,
       const LogicalSize& containing_grid_area_size,
-      absl::optional<LayoutUnit> opt_fixed_block_size,
+      const LogicalSize& fixed_available_size,
       NGGridLayoutSubtree&& opt_layout_subtree = NGGridLayoutSubtree(),
       bool min_block_size_should_encompass_intrinsic_size = false,
       absl::optional<LayoutUnit> opt_fragment_relative_block_offset =
@@ -222,15 +221,12 @@
           absl::nullopt) const;
 
   NGConstraintSpace CreateConstraintSpaceForMeasure(
-      const GridItemData& grid_item,
-      const NGGridSizingSubtree& sizing_subtree,
+      const NGSubgriddedItemData& subgridded_item,
       GridTrackSizingDirection track_direction,
       absl::optional<LayoutUnit> opt_fixed_block_size = absl::nullopt) const;
 
-  NGGridLayoutAlgorithm CreateSubgridLayoutAlgorithm(
-      const NGSubgriddedItemData& subgrid_data,
-      NGConstraintSpace* constraint_space,
-      NGFragmentGeometry* fragment_geometry) const;
+  NGConstraintSpace CreateConstraintSpaceForSubgridAlgorithm(
+      const NGSubgriddedItemData& subgrid_data) const;
 
   // Layout the |grid_items|, and add them to the builder.
   //
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc
index dd8d688..440feca2 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.cc
@@ -465,6 +465,11 @@
     const NGGridLayoutTrackCollection& other) const {
   return gutter_size_ == other.gutter_size_ &&
          track_direction_ == other.track_direction_ &&
+         accumulated_gutter_size_delta_ ==
+             other.accumulated_gutter_size_delta_ &&
+         accumulated_start_extra_margin_ ==
+             other.accumulated_start_extra_margin_ &&
+         accumulated_end_extra_margin_ == other.accumulated_end_extra_margin_ &&
          baselines_.has_value() == other.baselines_.has_value() &&
          (!baselines_ || (baselines_->major == other.baselines_->major &&
                           baselines_->minor == other.baselines_->minor)) &&
@@ -534,15 +539,36 @@
   return sets_geometry_[set_index + 1].track_count;
 }
 
+LayoutUnit NGGridLayoutTrackCollection::StartExtraMargin(
+    wtf_size_t set_index) const {
+  return set_index ? accumulated_gutter_size_delta_ / 2
+                   : accumulated_start_extra_margin_;
+}
+
+LayoutUnit NGGridLayoutTrackCollection::EndExtraMargin(
+    wtf_size_t set_index) const {
+  return (set_index < sets_geometry_.size() - 1)
+             ? accumulated_gutter_size_delta_ / 2
+             : accumulated_end_extra_margin_;
+}
+
 LayoutUnit NGGridLayoutTrackCollection::MajorBaseline(
     wtf_size_t set_index) const {
-  DCHECK(baselines_ && set_index < baselines_->major.size());
+  if (!baselines_) {
+    return LayoutUnit::Min();
+  }
+
+  DCHECK_LT(set_index, baselines_->major.size());
   return baselines_->major[set_index];
 }
 
 LayoutUnit NGGridLayoutTrackCollection::MinorBaseline(
     wtf_size_t set_index) const {
-  DCHECK(baselines_ && set_index < baselines_->minor.size());
+  if (!baselines_) {
+    return LayoutUnit::Min();
+  }
+
+  DCHECK_LT(set_index, baselines_->minor.size());
   return baselines_->minor[set_index];
 }
 
@@ -654,6 +680,19 @@
                        : subgrid_margin.block_end +
                              subgrid_border_scrollbar_padding.block_end;
 
+    // Accumulate the extra margin from the spanned sets in the parent track
+    // collection and this subgrid's margins and gutter size delta.
+    subgrid_track_collection.accumulated_gutter_size_delta_ =
+        subgrid_gutter_size_delta + accumulated_gutter_size_delta_;
+
+    subgrid_track_collection.accumulated_start_extra_margin_ =
+        subgrid_margin_start + subgrid_border_scrollbar_padding_start +
+        StartExtraMargin(begin_set_index);
+
+    subgrid_track_collection.accumulated_end_extra_margin_ =
+        subgrid_margin_border_scrollbar_padding_end +
+        EndExtraMargin(end_set_index);
+
     auto& subgrid_sets_geometry = subgrid_track_collection.sets_geometry_;
 
     subgrid_sets_geometry.ReserveInitialCapacity(set_span_size + 1);
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h
index 1051044..d87e7c10 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h
@@ -182,6 +182,10 @@
   LayoutUnit GetSetOffset(wtf_size_t set_index) const;
   wtf_size_t GetSetTrackCount(wtf_size_t set_index) const;
 
+  // Returns the accumulated extra margin at the start/end of the specified set.
+  LayoutUnit StartExtraMargin(wtf_size_t set_index) const;
+  LayoutUnit EndExtraMargin(wtf_size_t set_index) const;
+
   bool HasBaselines() const { return baselines_.has_value(); }
   LayoutUnit MajorBaseline(wtf_size_t set_index) const;
   LayoutUnit MinorBaseline(wtf_size_t set_index) const;
@@ -259,6 +263,10 @@
   //  (start: 3, end: 5) -> indefinite as:
   //      start <= last_indefinite_index[end]
   Vector<wtf_size_t, 16> last_indefinite_index_;
+
+  LayoutUnit accumulated_gutter_size_delta_;
+  LayoutUnit accumulated_start_extra_margin_;
+  LayoutUnit accumulated_end_extra_margin_;
 };
 
 // |NGGridRangeBuilder::EnsureTrackCoverage| may introduce a range start and/or
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
index 2f1a1705..e9eeae82 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
@@ -351,9 +351,19 @@
   DCHECK(!node.IsMonolithic() || space.IsAnonymous());
   // If we turn off fragmentation on a non-monolithic node, we need to treat the
   // resulting fragment as monolithic. This matters when it comes to determining
-  // the containing block of out-of-flow positioned descendants.
+  // the containing block of out-of-flow positioned descendants. In order to
+  // match the behavior in OOF layout, however, the fragment should only become
+  // monolithic when fragmentation is forced off at the first fragment. If we
+  // reach the end of the visible area after the containing block has inserted a
+  // break, it should not be set as monolithic. (How can we be monolithic, if we
+  // create more than one fragment, anyway?) An OOF fragment will always become
+  // a direct child of the fragmentainer if the containing block generates more
+  // than one fragment. The monolithicness flag is ultimately checked by
+  // pre-paint, in order to know where in the tree to look for the OOF fragment
+  // (direct fragmentainer child vs. child of the actual containing block).
   builder->SetIsMonolithic(!space.IsAnonymous() &&
-                           space.IsBlockFragmentationForcedOff());
+                           space.IsBlockFragmentationForcedOff() &&
+                           !IsBreakInside(previous_break_token));
 
   if (space.HasBlockFragmentation())
     builder->SetHasBlockFragmentation();
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.cc b/third_party/blink/renderer/core/loader/base_fetch_context.cc
index 80ca9c1..c4b0222 100644
--- a/third_party/blink/renderer/core/loader/base_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -273,9 +273,9 @@
                              network::mojom::blink::WebClientHintsType::
                                  kResourceWidth_DEPRECATED,
                              hints_preferences)) {
-      if (image_info->resource_width.is_set) {
+      if (image_info->resource_width) {
         float physical_width =
-            image_info->resource_width.width * image_info->dpr;
+            image_info->resource_width.value() * image_info->dpr;
         request.SetHttpHeaderField(
             network::GetClientHintToNameMap()
                 .at(network::mojom::blink::WebClientHintsType::
@@ -289,9 +289,9 @@
             policy, resource_origin, is_1p_origin,
             network::mojom::blink::WebClientHintsType::kResourceWidth,
             hints_preferences)) {
-      if (image_info->resource_width.is_set) {
+      if (image_info->resource_width) {
         float physical_width =
-            image_info->resource_width.width * image_info->dpr;
+            image_info->resource_width.value() * image_info->dpr;
         request.SetHttpHeaderField(
             network::GetClientHintToNameMap()
                 .at(network::mojom::blink::WebClientHintsType::kResourceWidth)
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.h b/third_party/blink/renderer/core/loader/base_fetch_context.h
index 0c33f0f..1479573d 100644
--- a/third_party/blink/renderer/core/loader/base_fetch_context.h
+++ b/third_party/blink/renderer/core/loader/base_fetch_context.h
@@ -35,7 +35,7 @@
 // frame
 struct ClientHintImageInfo {
   float dpr;
-  FetchParameters::ResourceWidth resource_width;
+  absl::optional<float> resource_width;
   absl::optional<int> viewport_width;
   absl::optional<int> viewport_height;
 };
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index cfe2b4c..eacd633 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -430,7 +430,7 @@
 }
 
 void FrameFetchContext::AddClientHintsIfNecessary(
-    const FetchParameters::ResourceWidth& resource_width,
+    const absl::optional<float> resource_width,
     ResourceRequest& request) {
   // If the feature is enabled, then client hints are allowed only on secure
   // URLs.
@@ -517,7 +517,7 @@
 
 void FrameFetchContext::PopulateResourceRequest(
     ResourceType type,
-    const FetchParameters::ResourceWidth& resource_width,
+    const absl::optional<float> resource_width,
     ResourceRequest& request,
     const ResourceLoaderOptions& options) {
   if (!GetResourceFetcherProperties().IsDetached())
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.h b/third_party/blink/renderer/core/loader/frame_fetch_context.h
index d207e50..dae88ddd 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.h
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.h
@@ -107,7 +107,7 @@
   bool AllowImage(bool images_enabled, const KURL&) const override;
 
   void PopulateResourceRequest(ResourceType,
-                               const FetchParameters::ResourceWidth&,
+                               const absl::optional<float> resource_width,
                                ResourceRequest&,
                                const ResourceLoaderOptions&) override;
 
@@ -115,7 +115,7 @@
 
   // Exposed for testing.
   void ModifyRequestForCSP(ResourceRequest&);
-  void AddClientHintsIfNecessary(const FetchParameters::ResourceWidth&,
+  void AddClientHintsIfNecessary(const absl::optional<float> resource_width,
                                  ResourceRequest&);
 
   void AddReducedAcceptLanguageIfNecessary(ResourceRequest&);
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
index 1c5c0e5..d9f792049 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
@@ -609,10 +609,9 @@
                     float width = 0) {
     SCOPED_TRACE(testing::Message() << header_name);
 
-    FetchParameters::ResourceWidth resource_width;
+    absl::optional<float> resource_width;
     if (width > 0) {
-      resource_width.width = width;
-      resource_width.is_set = true;
+      resource_width = width;
     }
 
     const KURL input_url(input);
@@ -638,11 +637,10 @@
   }
 
   String GetHeaderValue(const char* input, const char* header_name) {
-    FetchParameters::ResourceWidth resource_width;
     const KURL input_url(input);
     ResourceRequest resource_request(input_url);
-    GetFetchContext()->AddClientHintsIfNecessary(resource_width,
-                                                 resource_request);
+    GetFetchContext()->AddClientHintsIfNecessary(
+        absl::nullopt /* resource_width */, resource_request);
     return resource_request.HttpHeaderField(header_name);
   }
 
@@ -1460,7 +1458,6 @@
   const KURL url("https://www.example.com/");
   ResourceRequest request(url);
 
-  FetchParameters::ResourceWidth resource_width;
   ResourceLoaderOptions options(nullptr /* world */);
 
   document->GetFrame()->GetClientHintsPreferences().SetShouldSend(
@@ -1482,8 +1479,8 @@
 
   dummy_page_holder = nullptr;
 
-  GetFetchContext()->PopulateResourceRequest(ResourceType::kRaw, resource_width,
-                                             request, options);
+  GetFetchContext()->PopulateResourceRequest(
+      ResourceType::kRaw, absl::nullopt /* resource_width */, request, options);
   // Should not crash.
 }
 
@@ -1599,7 +1596,6 @@
 
  protected:
   void SetupForAcceptLanguageTest(bool is_detached, ResourceRequest& request) {
-    FetchParameters::ResourceWidth resource_width;
     ResourceLoaderOptions options(/*world=*/nullptr);
 
     document->GetFrame()->SetReducedAcceptLanguage("en-GB");
@@ -1608,7 +1604,8 @@
       dummy_page_holder = nullptr;
 
     GetFetchContext()->PopulateResourceRequest(
-        ResourceType::kRaw, resource_width, request, options);
+        ResourceType::kRaw, absl::nullopt /* resource_width */, request,
+        options);
   }
 
  private:
diff --git a/third_party/blink/renderer/core/loader/worker_fetch_context.cc b/third_party/blink/renderer/core/loader/worker_fetch_context.cc
index 33a1606..3211006 100644
--- a/third_party/blink/renderer/core/loader/worker_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/worker_fetch_context.cc
@@ -233,7 +233,7 @@
 
 void WorkerFetchContext::PopulateResourceRequest(
     ResourceType type,
-    const FetchParameters::ResourceWidth& resource_width,
+    const absl::optional<float> resource_width,
     ResourceRequest& out_request,
     const ResourceLoaderOptions& options) {
   if (!GetResourceFetcherProperties().IsDetached())
diff --git a/third_party/blink/renderer/core/loader/worker_fetch_context.h b/third_party/blink/renderer/core/loader/worker_fetch_context.h
index f3b8873..098cd9c7 100644
--- a/third_party/blink/renderer/core/loader/worker_fetch_context.h
+++ b/third_party/blink/renderer/core/loader/worker_fetch_context.h
@@ -84,7 +84,7 @@
   void AddResourceTiming(mojom::blink::ResourceTimingInfoPtr,
                          const AtomicString& initiator_type) override;
   void PopulateResourceRequest(ResourceType,
-                               const FetchParameters::ResourceWidth&,
+                               const absl::optional<float> resource_width,
                                ResourceRequest&,
                                const ResourceLoaderOptions&) override;
 
diff --git a/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc b/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
index cb215f7..252562a 100644
--- a/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
@@ -399,7 +399,13 @@
     if (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()) {
       return GetScrollNode(scrollable_area)->main_thread_scrolling_reasons;
     }
-    return scrollable_area.GetNonCompositedMainThreadScrollingReasons();
+    return scrollable_area.GetNonCompositedMainThreadScrollingReasons() |
+           scrollable_area.GetLayoutBox()
+               ->FirstFragment()
+               .PaintProperties()
+               ->ScrollTranslation()
+               ->ScrollNode()
+               ->GetMainThreadScrollingReasons();
   }
 
   void TestNonCompositedReasons(const AtomicString& style_class,
@@ -480,10 +486,18 @@
        CantPaintScrollingBackgroundTest) {
   TestNonCompositedReasons(
       "cant-paint-scrolling-background",
-      RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()
-          ? cc::MainThreadScrollingReason::kNotOpaqueForTextAndLCDText
-          : cc::MainThreadScrollingReason::
-                kCantPaintScrollingBackgroundAndLCDText);
+      cc::MainThreadScrollingReason::kBackgroundNeedsRepaintOnScroll |
+          (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()
+               ? cc::MainThreadScrollingReason::kNotOpaqueForTextAndLCDText
+               : cc::MainThreadScrollingReason::
+                     kCantPaintScrollingBackgroundAndLCDText));
+}
+
+TEST_P(NonCompositedMainThreadScrollingReasonsTest,
+       BackgroundNeedsRepaintOnScroll) {
+  TestNonCompositedReasons(
+      "needs-repaint-on-scroll",
+      cc::MainThreadScrollingReason::kBackgroundNeedsRepaintOnScroll);
 }
 
 TEST_P(NonCompositedMainThreadScrollingReasonsTest, ClipTest) {
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc b/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
index 42107b4..e2b702a 100644
--- a/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
@@ -2487,11 +2487,7 @@
   auto* scrollable_area = ScrollableAreaByDOMElementId("textinput");
   const auto* scroll_node = ScrollNodeForScrollableArea(scrollable_area);
   ASSERT_TRUE(scroll_node);
-  ASSERT_EQ(RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()
-                ? cc::MainThreadScrollingReason::kNotOpaqueForTextAndLCDText
-                // No main thread scrolling reasons for non-composited
-                // scrollable input/select.
-                : cc::MainThreadScrollingReason::kNotScrollingOnMain,
+  EXPECT_EQ(cc::MainThreadScrollingReason::kPreferNonCompositedScrolling,
             scroll_node->main_thread_scrolling_reasons);
   EXPECT_FALSE(scroll_node->is_composited);
 }
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index da59c962..6fd92559 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -538,41 +538,47 @@
   auto* box = GetLayoutBox();
   auto* frame_view = box->GetFrameView();
   frame_view->InvalidateBackgroundAttachmentFixedDescendantsOnScroll(*box);
-
-  if (!box->BackgroundNeedsFullPaintInvalidation()) {
-    auto background_paint_location = box->GetBackgroundPaintLocation();
-    bool background_paint_in_border_box =
-        background_paint_location & kBackgroundPaintInBorderBoxSpace;
-    bool background_paint_in_scrolling_contents =
-        background_paint_location & kBackgroundPaintInContentsSpace;
-
-    // Invalidate background on scroll if needed.
-    // Fixed attachment background has been dealt with in
-    // frame_view->InvalidateBackgroundAttachmentFixedDescendantsOnScroll().
-    const auto& background_layers = box->StyleRef().BackgroundLayers();
-    if (background_layers.AnyLayerHasLocalAttachmentImage() &&
-        background_paint_in_border_box) {
-      // Local-attachment background image scrolls, so needs invalidation if it
-      // paints in non-scrolling space.
-      box->SetBackgroundNeedsFullPaintInvalidation();
-    } else if (background_layers.AnyLayerHasDefaultAttachmentImage() &&
-               background_paint_in_scrolling_contents) {
-      // Normal attachment background image doesn't scroll, so needs
-      // invalidation if it paints in scrolling contents.
-      box->SetBackgroundNeedsFullPaintInvalidation();
-    } else if (background_layers.AnyLayerHasLocalAttachment() &&
-               background_layers.AnyLayerUsesContentBox() &&
-               background_paint_in_border_box &&
-               (box->PaddingLeft() || box->PaddingTop() ||
-                box->PaddingRight() || box->PaddingBottom())) {
-      // Local attachment content box background needs invalidation if there is
-      // padding because the content area can change on scroll (e.g. the top
-      // padding can disappear when the box scrolls to the bottom).
-      box->SetBackgroundNeedsFullPaintInvalidation();
-    }
+  if (!box->BackgroundNeedsFullPaintInvalidation() &&
+      BackgroundNeedsRepaintOnScroll()) {
+    box->SetBackgroundNeedsFullPaintInvalidation();
   }
 }
 
+// See the comment in .h about background-attachment:fixed.
+bool PaintLayerScrollableArea::BackgroundNeedsRepaintOnScroll() const {
+  const auto* box = GetLayoutBox();
+  auto background_paint_location = box->GetBackgroundPaintLocation();
+  bool background_paint_in_border_box =
+      background_paint_location & kBackgroundPaintInBorderBoxSpace;
+  bool background_paint_in_scrolling_contents =
+      background_paint_location & kBackgroundPaintInContentsSpace;
+
+  const auto& background_layers = box->StyleRef().BackgroundLayers();
+  if (background_layers.AnyLayerHasLocalAttachmentImage() &&
+      background_paint_in_border_box) {
+    // Local-attachment background image scrolls, so needs invalidation if it
+    // paints in non-scrolling space.
+    return true;
+  }
+  if (background_layers.AnyLayerHasDefaultAttachmentImage() &&
+      background_paint_in_scrolling_contents) {
+    // Normal attachment background image doesn't scroll, so needs
+    // invalidation if it paints in scrolling contents.
+    return true;
+  }
+  if (background_layers.AnyLayerHasLocalAttachment() &&
+      background_layers.AnyLayerUsesContentBox() &&
+      background_paint_in_border_box &&
+      (box->PaddingLeft() || box->PaddingTop() || box->PaddingRight() ||
+       box->PaddingBottom())) {
+    // Local attachment content box background needs invalidation if there is
+    // padding because the content area can change on scroll (e.g. the top
+    // padding can disappear when the box scrolls to the bottom).
+    return true;
+  }
+  return false;
+}
+
 gfx::Vector2d PaintLayerScrollableArea::ScrollOffsetInt() const {
   return gfx::ToFlooredVector2d(scroll_offset_);
 }
@@ -2423,6 +2429,9 @@
 }
 
 bool PaintLayerScrollableArea::PrefersNonCompositedScrolling() const {
+  if (RuntimeEnabledFeatures::PreferNonCompositedScrollingEnabled()) {
+    return true;
+  }
   if (Node* node = GetLayoutBox()->GetNode()) {
     if (IsA<HTMLSelectElement>(node)) {
       return true;
@@ -2474,10 +2483,9 @@
   if (force_prefer_compositing_to_lcd_text) {
     return true;
   }
-  if (RuntimeEnabledFeatures::PreferNonCompositedScrollingEnabled()) {
-    return false;
-  }
   if (PrefersNonCompositedScrolling()) {
+    non_composited_main_thread_scrolling_reasons_ =
+        cc::MainThreadScrollingReason::kPreferNonCompositedScrolling;
     return false;
   }
 
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
index 9f95065..c2a21bb 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
@@ -515,6 +515,11 @@
     return non_composited_main_thread_scrolling_reasons_;
   }
 
+  // This function doesn't check background-attachment:fixed backgrounds
+  // because it's not enough to invalidate all affected fixed backgrounds.
+  // See LocalFrameView::InvalidateBackgroundAttachmentFixedDescendantsOnScroll.
+  bool BackgroundNeedsRepaintOnScroll() const;
+
   ScrollbarTheme& GetPageScrollbarTheme() const override;
 
   // Return the thickness of the existing scrollbar; or, if there is no
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
index 0187818..83f1a8d 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
@@ -788,11 +788,6 @@
 
 TEST_P(MAYBE_PaintLayerScrollableAreaTest,
        ScrollWithLocalAttachmentBackgroundInScrollingContents) {
-  if (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()) {
-    // TODO(crbug.com/1414885): Fix this test.
-    return;
-  }
-
   SetBodyInnerHTML(R"HTML(
     <style>
       #scroller {
@@ -814,11 +809,8 @@
             scroller->ComputeBackgroundPaintLocationIfComposited());
   EXPECT_EQ(kBackgroundPaintInContentsSpace,
             scroller->GetBackgroundPaintLocation());
-  if (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()) {
-    EXPECT_FALSE(UsesCompositedScrolling(scroller));
-  } else {
-    EXPECT_TRUE(UsesCompositedScrolling(scroller));
-  }
+  EXPECT_FALSE(scrollable_area->BackgroundNeedsRepaintOnScroll());
+  EXPECT_TRUE(UsesCompositedScrolling(scroller));
 
   // Programmatically changing the scroll offset.
   scrollable_area->SetScrollOffset(ScrollOffset(0, 1),
@@ -882,6 +874,7 @@
             scroller->ComputeBackgroundPaintLocationIfComposited());
   EXPECT_EQ(kBackgroundPaintInBothSpaces,
             scroller->GetBackgroundPaintLocation());
+  EXPECT_TRUE(scrollable_area->BackgroundNeedsRepaintOnScroll());
 
   // Programmatically changing the scroll offset.
   scrollable_area->SetScrollOffset(ScrollOffset(0, 1),
@@ -1054,6 +1047,47 @@
   EXPECT_FALSE(GetLayoutView().NeedsPaintPropertyUpdate());
 }
 
+TEST_P(MAYBE_PaintLayerScrollableAreaTest,
+       ViewScrollWithScrollAttachmentBackground) {
+  SetPreferCompositingToLCDText(true);
+  SetBodyInnerHTML(R"HTML(
+    <style>html { background: linear-gradient(black, white) scroll; }</style>
+    <div style="height: 3000px"></div>
+  )HTML");
+
+  // background-attachment: scroll on the view is equivalent to local.
+  EXPECT_EQ(kBackgroundPaintInContentsSpace,
+            GetLayoutView().GetBackgroundPaintLocation());
+  auto* view_scrollable_area = GetLayoutView().GetScrollableArea();
+  EXPECT_FALSE(view_scrollable_area->BackgroundNeedsRepaintOnScroll());
+  view_scrollable_area->SetScrollOffset(
+      ScrollOffset(0, 1), mojom::blink::ScrollType::kProgrammatic);
+  EXPECT_FALSE(GetLayoutView().ShouldDoFullPaintInvalidation());
+  EXPECT_FALSE(GetLayoutView().BackgroundNeedsFullPaintInvalidation());
+  EXPECT_TRUE(GetLayoutView().NeedsPaintPropertyUpdate());
+  UpdateAllLifecyclePhasesForTest();
+}
+
+TEST_P(MAYBE_PaintLayerScrollableAreaTest,
+       ViewScrollWithLocalAttachmentBackground) {
+  SetPreferCompositingToLCDText(true);
+  SetBodyInnerHTML(R"HTML(
+    <style>html { background: linear-gradient(black, white) local; }</style>
+    <div style="height: 3000px"></div>
+  )HTML");
+
+  EXPECT_EQ(kBackgroundPaintInContentsSpace,
+            GetLayoutView().GetBackgroundPaintLocation());
+  auto* view_scrollable_area = GetLayoutView().GetScrollableArea();
+  EXPECT_FALSE(view_scrollable_area->BackgroundNeedsRepaintOnScroll());
+  view_scrollable_area->SetScrollOffset(
+      ScrollOffset(0, 1), mojom::blink::ScrollType::kProgrammatic);
+  EXPECT_FALSE(GetLayoutView().ShouldDoFullPaintInvalidation());
+  EXPECT_FALSE(GetLayoutView().BackgroundNeedsFullPaintInvalidation());
+  EXPECT_TRUE(GetLayoutView().NeedsPaintPropertyUpdate());
+  UpdateAllLifecyclePhasesForTest();
+}
+
 TEST_P(MAYBE_PaintLayerScrollableAreaTest, HitTestOverlayScrollbars) {
   SetBodyInnerHTML(R"HTML(
     <style>
@@ -1600,11 +1634,6 @@
 }
 
 TEST_P(MAYBE_PaintLayerScrollableAreaTest, UsedColorSchemeRootScrollbarsDark) {
-  if (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled()) {
-    // TODO(crbug.com/1414885): Fix this test.
-    return;
-  }
-
   USE_NON_OVERLAY_SCROLLBARS();
 
   SetHtmlInnerHTML(R"HTML(
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 923fb908..92796a1 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -2300,11 +2300,15 @@
   DCHECK(IsA<LayoutBox>(object_));
   auto* scrollable_area = To<LayoutBox>(object_).GetScrollableArea();
   DCHECK(scrollable_area);
-  if (!full_context_.scroll_unification_enabled) {
-    return full_context_.global_main_thread_scrolling_reasons;
+  MainThreadScrollingReasons reasons =
+      full_context_.global_main_thread_scrolling_reasons;
+  if (full_context_.scroll_unification_enabled) {
+    reasons |= scrollable_area->GetNonCompositedMainThreadScrollingReasons();
   }
-  return full_context_.global_main_thread_scrolling_reasons |
-         scrollable_area->GetNonCompositedMainThreadScrollingReasons();
+  if (scrollable_area->BackgroundNeedsRepaintOnScroll()) {
+    reasons |= cc::MainThreadScrollingReason::kBackgroundNeedsRepaintOnScroll;
+  }
+  return reasons;
 }
 
 void FragmentPaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation() {
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
index 551de73..4bb6d9e 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
@@ -3,11 +3,14 @@
 // found in the LICENSE file.
 
 #include "cc/input/scroll_snap_data.h"
+#include "third_party/blink/renderer/core/animation/animation_clock.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
 #include "third_party/blink/renderer/core/html/forms/html_select_element.h"
 #include "third_party/blink/renderer/core/html/html_iframe_element.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h"
 #include "third_party/blink/renderer/core/page/focus_controller.h"
+#include "third_party/blink/renderer/core/page/page_animator.h"
 #include "third_party/blink/renderer/core/paint/paint_property_tree_builder_test.h"
 #include "third_party/blink/renderer/core/paint/paint_property_tree_printer.h"
 #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
@@ -16,7 +19,14 @@
 namespace blink {
 
 // Tests covering incremental updates of paint property trees.
-class PaintPropertyTreeUpdateTest : public PaintPropertyTreeBuilderTest {};
+class PaintPropertyTreeUpdateTest : public PaintPropertyTreeBuilderTest {
+ public:
+  void SimulateFrame() {
+    // Advance time by 100 ms.
+    auto new_time = GetAnimationClock().CurrentTime() + base::Milliseconds(100);
+    GetPage().Animator().ServiceScriptedAnimations(new_time);
+  }
+};
 
 INSTANTIATE_TEST_SUITE_P(All,
                          PaintPropertyTreeUpdateTest,
@@ -2110,4 +2120,36 @@
   GetDocument().ElementFromPoint(1, 1);
   EXPECT_NEAR(0.8, div_properties->Effect()->Opacity(), 0.001);
 }
+
+TEST_P(PaintPropertyTreeUpdateTest, AnchorPositioningScrollUpdate) {
+  ScopedCSSAnchorPositioningForTest enabled(true);
+
+  SetBodyInnerHTML(R"HTML(
+    <div id="spacer" style="height: 1000px"></div>
+    <div id="anchor" style="
+        anchor-name: --a; width: 100px; height: 100px"></div>
+    <div id="target" style="
+        position: fixed; anchor-scroll: --a;
+        width: 100px; height: 100px; bottom: anchor(--a top)"></div>
+  )HTML");
+
+  // Make sure the scrolling coordinator is active.
+  ASSERT_TRUE(GetFrame().GetPage()->GetScrollingCoordinator());
+
+  GetFrame().DomWindow()->scrollBy(0, 300);
+
+  // anchor-scroll update requires animation frame.
+  SimulateFrame();
+  UpdateAllLifecyclePhasesExceptPaint();
+
+  // The anchor-scroll translation should be updated on main thread.
+  EXPECT_EQ(PaintPropertiesForElement("target")
+                ->AnchorScrollTranslation()
+                ->Get2dTranslation(),
+            gfx::Vector2dF(0, -300));
+
+  // Anchor positioning scroll update should not require main thread commits.
+  EXPECT_FALSE(GetFrame().View()->GetPaintArtifactCompositor()->NeedsUpdate());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
index 25a7934..2ad38389 100644
--- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
+++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -455,19 +455,10 @@
   // If we're in a fragmentation context, the parent fragment of OOFs is the
   // fragmentainer, unless the object is monolithic, in which case nothing
   // contained by the object participates in the current block fragmentation
-  // context. The monolithic-check here is somewhat special, to match the
-  // behavior in OOF layout. We need to check that we're monolithic AND the
-  // first fragment of the node in order to act as an OOF container. A non-first
-  // fragment may be set as monolithic if overflow is clipped and we've reached
-  // the end right there. But that doesn't affect how OOF layout behaves. In
-  // such cases, where there's more than one fragment involved, an OOF fragment
-  // will become a direct child of a fragmentainer, just as if there were no
-  // monolithicness involved at all.
-  //
-  // If we're not participating in block fragmentation, the containing fragment
-  // of an OOF fragment is always simply the parent.
+  // context. If we're not participating in block fragmentation, the containing
+  // fragment of an OOF fragment is always simply the parent.
   if (!context.current_container.IsInFragmentationContext() ||
-      (fragment && fragment->IsMonolithic() && fragment->IsFirstForNode())) {
+      (fragment && fragment->IsMonolithic())) {
     // Anonymous blocks are not allowed to be containing blocks, so we should
     // skip over any such elements.
     if (!fragment || !fragment->IsAnonymousBlock()) {
diff --git a/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc b/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc
index 782e756..247f8800 100644
--- a/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc
+++ b/third_party/blink/renderer/core/paint/timing/paint_timing_detector.cc
@@ -107,8 +107,7 @@
   float_t document_dpr = document.DevicePixelRatio();
 
   // Get the size attribute calculated width, if any
-  FetchParameters::ResourceWidth sizes_width =
-      image_element->GetResourceWidth();
+  absl::optional<float> sizes_width = image_element->GetResourceWidth();
   // Report offset in pixels between intrinsic and layout dimensions
   const float_t kDPRCap = 2.0;
   float_t capped_dpr = std::min(document_dpr, kDPRCap);
@@ -136,9 +135,9 @@
   }
 
   // Report offset in pixels between layout width and sizes result
-  if (sizes_width.is_set) {
+  if (sizes_width) {
     int sizes_miss =
-        base::saturated_cast<int>(sizes_width.width - layout_width);
+        base::saturated_cast<int>(sizes_width.value() - layout_width);
 
     base::UmaHistogramBoolean("Renderer.Images.HasSizesAttributeMiss",
                               sizes_miss > 0);
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_fluent.cc b/third_party/blink/renderer/core/scroll/scrollbar_theme_fluent.cc
index f5792db..cfd4748 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme_fluent.cc
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_fluent.cc
@@ -9,13 +9,6 @@
 #include "third_party/blink/renderer/platform/web_test_support.h"
 #include "ui/gfx/geometry/rect.h"
 
-namespace {
-// Make scrollbar parts compatible with the existing Windows scrollbar to
-// reuse scrollbar-related web tests.
-constexpr int kScrollbarTrackThicknessForWebTests = 15;
-constexpr int kScrollbarThumbThicknessForWebTests = 7;
-}  // namespace
-
 namespace blink {
 
 ScrollbarThemeFluent& ScrollbarThemeFluent::GetInstance() {
@@ -25,21 +18,18 @@
 
 ScrollbarThemeFluent::ScrollbarThemeFluent() {
   WebThemeEngine* theme_engine = WebThemeEngineHelper::GetNativeThemeEngine();
+  scrollbar_thumb_thickness_ =
+      theme_engine->GetSize(WebThemeEngine::kPartScrollbarVerticalThumb)
+          .width();
+  scrollbar_track_thickness_ =
+      theme_engine->GetSize(WebThemeEngine::kPartScrollbarVerticalTrack)
+          .width();
+  // Web tests expect buttons to be squares with the length of the track.
   scrollbar_button_length_ =
       WebTestSupport::IsRunningWebTest()
-          ? kScrollbarTrackThicknessForWebTests
+          ? scrollbar_track_thickness_
           : theme_engine->GetSize(WebThemeEngine::kPartScrollbarUpArrow)
                 .height();
-  scrollbar_thumb_thickness_ =
-      WebTestSupport::IsRunningWebTest()
-          ? kScrollbarThumbThicknessForWebTests
-          : theme_engine->GetSize(WebThemeEngine::kPartScrollbarVerticalThumb)
-                .width();
-  scrollbar_track_thickness_ =
-      WebTestSupport::IsRunningWebTest()
-          ? kScrollbarTrackThicknessForWebTests
-          : theme_engine->GetSize(WebThemeEngine::kPartScrollbarVerticalTrack)
-                .width();
 }
 
 int ScrollbarThemeFluent::ScrollbarThickness(float scale_from_dip,
diff --git a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
index c024cf7..f2b78ed 100644
--- a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
+++ b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
@@ -97,17 +97,6 @@
       type_name: "bool",
       inherited: true,
     },
-    // Whether we're inside (or at) a block fragmentation context that may
-    // switch between legacy and NG layout, depending on the contents.
-    // This can be removed when we have got rid of the legacy engine.
-    // See crbug.com/1229581
-    {
-      name: "InsideFragmentationContextWithNondeterministicEngine",
-      field_template: "primitive",
-      default_value: "false",
-      type_name: "bool",
-      inherited: true,
-    },
     // Style has content property with attr() values.
     {
       name: "HasAttrContent",
diff --git a/third_party/blink/renderer/core/testing/data/two_scrollable_area.html b/third_party/blink/renderer/core/testing/data/two_scrollable_area.html
index f874476..9677515 100644
--- a/third_party/blink/renderer/core/testing/data/two_scrollable_area.html
+++ b/third_party/blink/renderer/core/testing/data/two_scrollable_area.html
@@ -28,6 +28,11 @@
   background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUg), white local
 }
 
+.needs-repaint-on-scroll {
+  background: linear-gradient(black, white) local, yellow;
+  border: 10px dashed black;
+}
+
 .border-radius {
   border: 2px solid;
   border-radius: 20px;
diff --git a/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc b/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc
index d313c84..471f374 100644
--- a/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc
+++ b/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc
@@ -5,7 +5,6 @@
 #include "third_party/blink/renderer/modules/eyedropper/eye_dropper.h"
 
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
-#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
@@ -84,20 +83,18 @@
     return ScriptPromise();
   }
 
-  signal_ = nullptr;
   std::unique_ptr<ScopedAbortState> end_chooser_abort_state = nullptr;
   std::unique_ptr<ScopedAbortState> response_handler_abort_state = nullptr;
-  if (options->hasSignal()) {
-    signal_ = options->signal();
-    if (signal_->aborted()) {
-      return ScriptPromise::Reject(script_state, signal_->reason(script_state));
+  if (auto* signal = options->getSignalOr(nullptr)) {
+    if (signal->aborted()) {
+      return ScriptPromise::Reject(script_state, signal->reason(script_state));
     }
-    auto* handle = signal_->AddAlgorithm(
-        MakeGarbageCollected<OpenAbortAlgorithm>(this, signal_));
+    auto* handle = signal->AddAlgorithm(
+        MakeGarbageCollected<OpenAbortAlgorithm>(this, signal));
     end_chooser_abort_state =
-        std::make_unique<ScopedAbortState>(signal_, handle);
+        std::make_unique<ScopedAbortState>(signal, handle);
     response_handler_abort_state =
-        std::make_unique<ScopedAbortState>(signal_, handle);
+        std::make_unique<ScopedAbortState>(signal, handle);
   }
 
   resolver_ = MakeGarbageCollected<ScriptPromiseResolver>(
@@ -119,26 +116,12 @@
 }
 
 void EyeDropper::AbortCallback(AbortSignal* signal) {
-  if (!base::FeatureList::IsEnabled(features::kAbortSignalHandleBasedRemoval)) {
-    // There is no way to remove abort signal callbacks, so we need to
-    // perform null-check for `resolver_` to see if the promise has already
-    // been resolved.
-    // TODO(https://crbug.com/1296280): It should be possible to remove abort
-    // callbacks. This object can be reused for multiple eyedropper operations,
-    // and it might be possible for multiple abort signals to be mixed up.
-
-    // There is no RemoveAlgorithm() method on AbortSignal so compare the signal
-    // bound to this callback to the one last passed to open().
-    if (signal_ != signal)
-      return;
-  }
-
   if (resolver_) {
     ScriptState* script_state = resolver_->GetScriptState();
     if (IsInParallelAlgorithmRunnable(resolver_->GetExecutionContext(),
                                       script_state)) {
       ScriptState::Scope script_state_scope(script_state);
-      resolver_->Reject(signal_->reason(script_state));
+      resolver_->Reject(signal->reason(script_state));
     }
   }
 
@@ -196,7 +179,6 @@
 void EyeDropper::Trace(Visitor* visitor) const {
   visitor->Trace(eye_dropper_chooser_);
   visitor->Trace(resolver_);
-  visitor->Trace(signal_);
   ScriptWrappable::Trace(visitor);
 }
 
diff --git a/third_party/blink/renderer/modules/eyedropper/eye_dropper.h b/third_party/blink/renderer/modules/eyedropper/eye_dropper.h
index 436ad4d3..0d9784ad 100644
--- a/third_party/blink/renderer/modules/eyedropper/eye_dropper.h
+++ b/third_party/blink/renderer/modules/eyedropper/eye_dropper.h
@@ -59,7 +59,6 @@
 
   HeapMojoRemote<mojom::blink::EyeDropperChooser> eye_dropper_chooser_;
   Member<ScriptPromiseResolver> resolver_;
-  Member<AbortSignal> signal_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/idle/idle_detector.cc b/third_party/blink/renderer/modules/idle/idle_detector.cc
index 0cfe740..415c006e 100644
--- a/third_party/blink/renderer/modules/idle/idle_detector.cc
+++ b/third_party/blink/renderer/modules/idle/idle_detector.cc
@@ -9,7 +9,6 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "mojo/public/cpp/bindings/remote.h"
-#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/idle/idle_manager.mojom-blink.h"
 #include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
@@ -49,21 +48,19 @@
 
 class IdleDetector::StartAbortAlgorithm final : public AbortSignal::Algorithm {
  public:
-  StartAbortAlgorithm(IdleDetector* idle_detector, AbortSignal* signal)
-      : idle_detector_(idle_detector), abort_signal_(signal) {}
+  explicit StartAbortAlgorithm(IdleDetector* idle_detector)
+      : idle_detector_(idle_detector) {}
   ~StartAbortAlgorithm() override = default;
 
-  void Run() override { idle_detector_->Abort(abort_signal_); }
+  void Run() override { idle_detector_->Abort(); }
 
   void Trace(Visitor* visitor) const override {
     visitor->Trace(idle_detector_);
-    visitor->Trace(abort_signal_);
     Algorithm::Trace(visitor);
   }
 
  private:
   Member<IdleDetector> idle_detector_;
-  Member<AbortSignal> abort_signal_;
 };
 
 IdleDetector* IdleDetector::Create(ScriptState* script_state) {
@@ -155,8 +152,8 @@
     // If there was a previous algorithm, it should have been removed when we
     // reached the "stopped" state.
     DCHECK(!abort_handle_);
-    abort_handle_ = signal_->AddAlgorithm(
-        MakeGarbageCollected<StartAbortAlgorithm>(this, signal_));
+    abort_handle_ =
+        signal_->AddAlgorithm(MakeGarbageCollected<StartAbortAlgorithm>(this));
   }
 
   mojo::PendingRemote<mojom::blink::IdleMonitor> remote;
@@ -181,14 +178,7 @@
   timer_.SetTaskRunnerForTesting(task_runner_, tick_clock);
 }
 
-void IdleDetector::Abort(AbortSignal* signal) {
-  if (!base::FeatureList::IsEnabled(features::kAbortSignalHandleBasedRemoval)) {
-    // There is no RemoveAlgorithm() method on AbortSignal so compare the signal
-    // bound to this callback to the one last passed to start().
-    if (signal_ != signal)
-      return;
-  }
-
+void IdleDetector::Abort() {
   if (resolver_) {
     ScriptState* script_state = resolver_->GetScriptState();
     if (IsInParallelAlgorithmRunnable(resolver_->GetExecutionContext(),
diff --git a/third_party/blink/renderer/modules/idle/idle_detector.h b/third_party/blink/renderer/modules/idle/idle_detector.h
index 34a9f6e..450694c 100644
--- a/third_party/blink/renderer/modules/idle/idle_detector.h
+++ b/third_party/blink/renderer/modules/idle/idle_detector.h
@@ -71,7 +71,7 @@
               bool is_overridden_by_devtools) override;
 
   void DispatchUserIdleEvent(TimerBase*);
-  void Abort(AbortSignal*);
+  void Abort();
   void OnMonitorDisconnected();
   void OnAddMonitor(ScriptPromiseResolver*,
                     mojom::blink::IdleManagerError,
diff --git a/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc b/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc
index 5408acb..7525179 100644
--- a/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc
@@ -77,7 +77,7 @@
 static const MediaRecorderTestParams kMediaRecorderTestParams[] = {
     {true, false, "video/webm", "vp8", true},
     {true, false, "video/webm", "vp9", true},
-    {true, false, "video/webm", "av1", true},
+    {true, false, "video/webm", "av1", false},
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
     {true, false, "video/x-matroska", "avc1", false},
 #endif
@@ -380,7 +380,7 @@
     OnVideoFrameForTesting(video_frame);
     run_loop.Run();
   }
-  Mock::VerifyAndClearExpectations(this);
+  Mock::VerifyAndClearExpectations(recorder);
 
   {
     const size_t kEncodedSizeThreshold = 12;
@@ -396,8 +396,7 @@
     OnVideoFrameForTesting(video_frame);
     run_loop.Run();
   }
-  Mock::VerifyAndClearExpectations(this);
-
+  Mock::VerifyAndClearExpectations(recorder);
   {
     const scoped_refptr<media::VideoFrame> alpha_frame =
         media::VideoFrame::CreateTransparentFrame(gfx::Size(160, 80));
@@ -418,11 +417,10 @@
           .Times(1)
           .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
     }
-
     OnVideoFrameForTesting(alpha_frame);
     run_loop.Run();
   }
-
+  Mock::VerifyAndClearExpectations(recorder);
   media_recorder_handler_->Stop();
 }
 
@@ -470,7 +468,7 @@
       OnAudioBusForTesting(*audio_bus1);
     run_loop.Run();
   }
-  Mock::VerifyAndClearExpectations(this);
+  Mock::VerifyAndClearExpectations(recorder);
 
   {
     base::RunLoop run_loop;
@@ -486,6 +484,7 @@
       OnAudioBusForTesting(*audio_bus2);
     run_loop.Run();
   }
+  Mock::VerifyAndClearExpectations(recorder);
 
   media_recorder_handler_->Stop();
 }
@@ -537,6 +536,7 @@
     OnVideoFrameForTesting(video_frame);
     run_loop.Run();
   }
+  Mock::VerifyAndClearExpectations(recorder);
 
   // Make sure the |media_recorder_handler_| gets destroyed and removing sinks
   // before the MediaStreamVideoTrack dtor, avoiding a DCHECK on a non-empty
@@ -598,6 +598,8 @@
   OnEncodedVideoForTesting(params, "vp9 frame", "", base::TimeTicks::Now(),
                            true);
 
+  Mock::VerifyAndClearExpectations(recorder);
+
   // Make sure the |media_recorder_handler_| gets destroyed and removing sinks
   // before the MediaStreamVideoTrack dtor, avoiding a DCHECK on a non-empty
   // callback list.
@@ -632,6 +634,8 @@
   OnEncodedVideoForTesting(params, "vp9 frame", "", base::TimeTicks::Now(),
                            true);
 
+  Mock::VerifyAndClearExpectations(recorder);
+
   // Make sure the |media_recorder_handler_| gets destroyed and removing sinks
   // before the MediaStreamVideoTrack dtor, avoiding a DCHECK on a non-empty
   // callback list.
@@ -685,6 +689,7 @@
   EXPECT_CALL(*recorder, WriteData).Times(AtLeast(1));
   media_recorder_handler_->Stop();
   media_recorder_handler_ = nullptr;
+  Mock::VerifyAndClearExpectations(recorder);
 }
 
 TEST_F(MediaRecorderHandlerAudioVideoTest, EmitsCachedVideoDataOnStop) {
@@ -704,6 +709,7 @@
   EXPECT_CALL(*recorder, WriteData).Times(AtLeast(1));
   media_recorder_handler_->Stop();
   media_recorder_handler_ = nullptr;
+  Mock::VerifyAndClearExpectations(recorder);
 }
 
 TEST_F(MediaRecorderHandlerAudioVideoTest,
@@ -726,6 +732,7 @@
   EXPECT_CALL(*recorder, WriteData).Times(AtLeast(1));
   media_recorder_handler_->Stop();
   media_recorder_handler_ = nullptr;
+  Mock::VerifyAndClearExpectations(recorder);
 }
 
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
@@ -862,7 +869,7 @@
     run_loop.Run();
   }
   EXPECT_EQ(media_recorder_handler_->ActualMimeType(), GetParam().mime_type);
-  Mock::VerifyAndClearExpectations(this);
+  Mock::VerifyAndClearExpectations(recorder);
 
   media_recorder_handler_->Stop();
 }
@@ -906,6 +913,7 @@
                              .WithData(std::string("vp8 frame"))
                              .BuildRefPtr());
   platform_->RunUntilIdle();
+  Mock::VerifyAndClearExpectations(recorder);
 }
 
 INSTANTIATE_TEST_SUITE_P(All,
diff --git a/third_party/blink/renderer/modules/nfc/ndef_reader.cc b/third_party/blink/renderer/modules/nfc/ndef_reader.cc
index 19c25738..c19db379 100644
--- a/third_party/blink/renderer/modules/nfc/ndef_reader.cc
+++ b/third_party/blink/renderer/modules/nfc/ndef_reader.cc
@@ -7,7 +7,6 @@
 #include <memory>
 
 #include "services/device/public/mojom/nfc.mojom-blink.h"
-#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
@@ -102,41 +101,37 @@
 
 class NDEFReader::WriteAbortAlgorithm final : public AbortSignal::Algorithm {
  public:
-  WriteAbortAlgorithm(NDEFReader* ndef_reader, AbortSignal* signal)
-      : ndef_reader_(ndef_reader), abort_signal_(signal) {}
+  explicit WriteAbortAlgorithm(NDEFReader* ndef_reader)
+      : ndef_reader_(ndef_reader) {}
   ~WriteAbortAlgorithm() override = default;
 
-  void Run() override { ndef_reader_->WriteAbort(abort_signal_); }
+  void Run() override { ndef_reader_->WriteAbort(); }
 
   void Trace(Visitor* visitor) const override {
     visitor->Trace(ndef_reader_);
-    visitor->Trace(abort_signal_);
     Algorithm::Trace(visitor);
   }
 
  private:
   Member<NDEFReader> ndef_reader_;
-  Member<AbortSignal> abort_signal_;
 };
 
 class NDEFReader::MakeReadOnlyAbortAlgorithm final
     : public AbortSignal::Algorithm {
  public:
-  MakeReadOnlyAbortAlgorithm(NDEFReader* ndef_reader, AbortSignal* signal)
-      : ndef_reader_(ndef_reader), abort_signal_(signal) {}
+  explicit MakeReadOnlyAbortAlgorithm(NDEFReader* ndef_reader)
+      : ndef_reader_(ndef_reader) {}
   ~MakeReadOnlyAbortAlgorithm() override = default;
 
-  void Run() override { ndef_reader_->MakeReadOnlyAbort(abort_signal_); }
+  void Run() override { ndef_reader_->MakeReadOnlyAbort(); }
 
   void Trace(Visitor* visitor) const override {
     visitor->Trace(ndef_reader_);
-    visitor->Trace(abort_signal_);
     Algorithm::Trace(visitor);
   }
 
  private:
   Member<NDEFReader> ndef_reader_;
-  Member<AbortSignal> abort_signal_;
 };
 
 // static
@@ -291,13 +286,6 @@
 }
 
 void NDEFReader::ReadAbort(AbortSignal* signal) {
-  if (!base::FeatureList::IsEnabled(features::kAbortSignalHandleBasedRemoval)) {
-    // There is no RemoveAlgorithm() method on AbortSignal so compare the signal
-    // bound to this callback to the one last passed to scan().
-    if (scan_signal_ != signal)
-      return;
-  }
-
   nfc_proxy_->StopReading(this);
   scan_abort_handle_.Clear();
 
@@ -332,17 +320,14 @@
     return ScriptPromise();
   }
 
-  write_signal_ = options->getSignalOr(nullptr);
   std::unique_ptr<ScopedAbortState> scoped_abort_state = nullptr;
-  if (write_signal_) {
-    if (write_signal_->aborted()) {
-      return ScriptPromise::Reject(script_state,
-                                   write_signal_->reason(script_state));
+  if (auto* signal = options->getSignalOr(nullptr)) {
+    if (signal->aborted()) {
+      return ScriptPromise::Reject(script_state, signal->reason(script_state));
     }
-    auto* handle = write_signal_->AddAlgorithm(
-        MakeGarbageCollected<WriteAbortAlgorithm>(this, write_signal_));
-    scoped_abort_state =
-        std::make_unique<ScopedAbortState>(write_signal_, handle);
+    auto* handle =
+        signal->AddAlgorithm(MakeGarbageCollected<WriteAbortAlgorithm>(this));
+    scoped_abort_state = std::make_unique<ScopedAbortState>(signal, handle);
   }
 
   // Step 11.2: Run "create NDEF message", if this throws an exception,
@@ -398,8 +383,10 @@
     return;
   }
 
-  if (write_signal_ && write_signal_->aborted()) {
-    resolver->Reject(write_signal_->reason(script_state));
+  AbortSignal* signal =
+      scoped_abort_state ? scoped_abort_state->Signal() : nullptr;
+  if (signal && signal->aborted()) {
+    resolver->Reject(signal->reason(script_state));
     return;
   }
 
@@ -441,14 +428,7 @@
   }
 }
 
-void NDEFReader::WriteAbort(AbortSignal* signal) {
-  if (!base::FeatureList::IsEnabled(features::kAbortSignalHandleBasedRemoval)) {
-    // There is no RemoveAlgorithm() method on AbortSignal so compare the signal
-    // bound to this callback to the one last passed to write().
-    if (write_signal_ != signal)
-      return;
-  }
-
+void NDEFReader::WriteAbort() {
   // WriteOnRequestCompleted() should always be called whether the push
   // operation is cancelled successfully or not.
   nfc_proxy_->CancelPush();
@@ -465,18 +445,14 @@
     return ScriptPromise();
   }
 
-  make_read_only_signal_ = options->getSignalOr(nullptr);
   std::unique_ptr<ScopedAbortState> scoped_abort_state = nullptr;
-  if (make_read_only_signal_) {
-    if (make_read_only_signal_->aborted()) {
-      return ScriptPromise::Reject(
-          script_state, make_read_only_signal_->reason(script_state));
+  if (auto* signal = options->getSignalOr(nullptr)) {
+    if (signal->aborted()) {
+      return ScriptPromise::Reject(script_state, signal->reason(script_state));
     }
-    auto* handle = make_read_only_signal_->AddAlgorithm(
-        MakeGarbageCollected<MakeReadOnlyAbortAlgorithm>(
-            this, make_read_only_signal_));
-    scoped_abort_state =
-        std::make_unique<ScopedAbortState>(make_read_only_signal_, handle);
+    auto* handle = signal->AddAlgorithm(
+        MakeGarbageCollected<MakeReadOnlyAbortAlgorithm>(this));
+    scoped_abort_state = std::make_unique<ScopedAbortState>(signal, handle);
   }
 
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(
@@ -520,8 +496,10 @@
     return;
   }
 
-  if (make_read_only_signal_ && make_read_only_signal_->aborted()) {
-    resolver->Reject(make_read_only_signal_->reason(script_state));
+  AbortSignal* signal =
+      scoped_abort_state ? scoped_abort_state->Signal() : nullptr;
+  if (signal && signal->aborted()) {
+    resolver->Reject(signal->reason(script_state));
     return;
   }
 
@@ -561,14 +539,7 @@
   }
 }
 
-void NDEFReader::MakeReadOnlyAbort(AbortSignal* signal) {
-  if (!base::FeatureList::IsEnabled(features::kAbortSignalHandleBasedRemoval)) {
-    // There is no RemoveAlgorithm() method on AbortSignal so compare the signal
-    // bound to this callback to the one last passed to makeReadOnly().
-    if (make_read_only_signal_ != signal)
-      return;
-  }
-
+void NDEFReader::MakeReadOnlyAbort() {
   // MakeReadOnlyOnRequestCompleted() should always be called whether the
   // makeReadOnly operation is cancelled successfully or not.
   nfc_proxy_->CancelMakeReadOnly();
@@ -581,9 +552,7 @@
   visitor->Trace(scan_signal_);
   visitor->Trace(scan_abort_handle_);
   visitor->Trace(write_requests_);
-  visitor->Trace(write_signal_);
   visitor->Trace(make_read_only_requests_);
-  visitor->Trace(make_read_only_signal_);
   EventTargetWithInlineData::Trace(visitor);
   ActiveScriptWrappable::Trace(visitor);
   ExecutionContextLifecycleObserver::Trace(visitor);
diff --git a/third_party/blink/renderer/modules/nfc/ndef_reader.h b/third_party/blink/renderer/modules/nfc/ndef_reader.h
index 5a24205f..0110b4f1 100644
--- a/third_party/blink/renderer/modules/nfc/ndef_reader.h
+++ b/third_party/blink/renderer/modules/nfc/ndef_reader.h
@@ -91,13 +91,13 @@
   void ReadAbort(AbortSignal* signal);
   void ReadOnRequestCompleted(device::mojom::blink::NDEFErrorPtr error);
 
-  void WriteAbort(AbortSignal* signal);
+  void WriteAbort();
   void WriteOnRequestCompleted(
       ScriptPromiseResolver* resolver,
       std::unique_ptr<ScopedAbortState> scoped_abort_state,
       device::mojom::blink::NDEFErrorPtr error);
 
-  void MakeReadOnlyAbort(AbortSignal* signal);
+  void MakeReadOnlyAbort();
   void MakeReadOnlyOnRequestCompleted(
       ScriptPromiseResolver* resolver,
       std::unique_ptr<ScopedAbortState> scoped_abort_state,
@@ -140,13 +140,11 @@
   // in that case the callback passed to Push() won't be called and
   // mojo::WrapCallbackWithDefaultInvokeIfNotRun() is forbidden in Blink.
   HeapHashSet<Member<ScriptPromiseResolver>> write_requests_;
-  Member<AbortSignal> write_signal_;
 
   // |make_read_only_requests_| are kept here to handle Mojo connection failures
   // because in that case the callback passed to MakeReadOnly() won't be called
   // and mojo::WrapCallbackWithDefaultInvokeIfNotRun() is forbidden in Blink.
   HeapHashSet<Member<ScriptPromiseResolver>> make_read_only_requests_;
-  Member<AbortSignal> make_read_only_signal_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/scheduler/dom_task.cc b/third_party/blink/renderer/modules/scheduler/dom_task.cc
index c246a22..570ae9c 100644
--- a/third_party/blink/renderer/modules/scheduler/dom_task.cc
+++ b/third_party/blink/renderer/modules/scheduler/dom_task.cc
@@ -35,19 +35,6 @@
 
 namespace blink {
 
-#define QUEUEING_TIME_PER_PRIORITY_METRIC_NAME \
-  "DOMScheduler.QueueingDurationPerPriority"
-
-#define PRIORITY_CHANGED_HISTOGRAM_NAME \
-  "DOMSchedler.TaskSignalPriorityWasChanged"
-
-// Same as UMA_HISTOGRAM_TIMES but for a broader view of this metric we end
-// at 1 minute instead of 10 seconds.
-#define QUEUEING_TIME_HISTOGRAM(name, sample)                                 \
-  UMA_HISTOGRAM_CUSTOM_TIMES(QUEUEING_TIME_PER_PRIORITY_METRIC_NAME name,     \
-                             sample, base::Milliseconds(1), base::Minutes(1), \
-                             50)
-
 namespace {
 
 void GenericTaskData(perfetto::TracedDictionary& dict,
@@ -103,9 +90,6 @@
       resolver_(resolver),
       signal_(signal),
       task_queue_(task_queue),
-      // TODO(crbug.com/1291798): Expose queuing time from
-      // base::sequence_manager so we don't have to recalculate it here.
-      queue_time_(delay.is_zero() ? base::TimeTicks::Now() : base::TimeTicks()),
       delay_(delay),
       task_id_for_tracing_(NextIdForTracing()) {
   CHECK(task_queue_);
@@ -177,7 +161,6 @@
     return;
   }
 
-  RecordTaskStartMetrics();
   InvokeInternal(script_state);
   callback_.Release();
 }
@@ -256,30 +239,4 @@
           .ToLocalChecked());
 }
 
-void DOMTask::RecordTaskStartMetrics() {
-  auto status =
-      (signal_ && IsA<DOMTaskSignal>(signal_.Get()))
-          ? To<DOMTaskSignal>(signal_.Get())->GetPriorityChangeStatus()
-          : DOMTaskSignal::PriorityChangeStatus::kNoPriorityChange;
-  UMA_HISTOGRAM_ENUMERATION(PRIORITY_CHANGED_HISTOGRAM_NAME, status);
-
-  if (queue_time_ > base::TimeTicks()) {
-    base::TimeDelta queue_duration = base::TimeTicks::Now() - queue_time_;
-    DCHECK_GT(queue_duration, base::TimeDelta());
-    if (status == DOMTaskSignal::PriorityChangeStatus::kNoPriorityChange) {
-      switch (task_queue_->GetPriority()) {
-        case WebSchedulingPriority::kUserBlockingPriority:
-          QUEUEING_TIME_HISTOGRAM(".UserBlocking", queue_duration);
-          break;
-        case WebSchedulingPriority::kUserVisiblePriority:
-          QUEUEING_TIME_HISTOGRAM(".UserVisable", queue_duration);
-          break;
-        case WebSchedulingPriority::kBackgroundPriority:
-          QUEUEING_TIME_HISTOGRAM(".Background", queue_duration);
-          break;
-      }
-    }
-  }
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/scheduler/dom_task.h b/third_party/blink/renderer/modules/scheduler/dom_task.h
index 8af32b5..0564b19 100644
--- a/third_party/blink/renderer/modules/scheduler/dom_task.h
+++ b/third_party/blink/renderer/modules/scheduler/dom_task.h
@@ -47,7 +47,6 @@
   // catching any errors and retrieving the result.
   void InvokeInternal(ScriptState*);
   void OnAbort();
-  void RecordTaskStartMetrics();
 
   TaskHandle task_handle_;
   Member<V8SchedulerPostTaskCallback> callback_;
@@ -59,7 +58,6 @@
   // the associated WebSchedulingTaskQueue stays alive until after this task
   // runs, which is necessary to ensure throttling works correctly.
   Member<DOMScheduler::DOMTaskQueue> task_queue_;
-  const base::TimeTicks queue_time_;
   const base::TimeDelta delay_;
   const uint64_t task_id_for_tracing_;
   absl::optional<scheduler::TaskAttributionId> parent_task_id_;
diff --git a/third_party/blink/renderer/modules/scheduler/dom_task_signal.cc b/third_party/blink/renderer/modules/scheduler/dom_task_signal.cc
index ca0e0c3..3557f1e 100644
--- a/third_party/blink/renderer/modules/scheduler/dom_task_signal.cc
+++ b/third_party/blink/renderer/modules/scheduler/dom_task_signal.cc
@@ -128,7 +128,6 @@
   is_priority_changing_ = true;
   const AtomicString previous_priority = priority_;
   priority_ = priority;
-  priority_change_status_ = PriorityChangeStatus::kPriorityHasChanged;
 
   for (AlgorithmHandle* handle : priority_change_algorithms_) {
     handle->GetAlgorithm()->Run();
diff --git a/third_party/blink/renderer/modules/scheduler/dom_task_signal.h b/third_party/blink/renderer/modules/scheduler/dom_task_signal.h
index 391d7c8..648b9dd 100644
--- a/third_party/blink/renderer/modules/scheduler/dom_task_signal.h
+++ b/third_party/blink/renderer/modules/scheduler/dom_task_signal.h
@@ -24,15 +24,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  // These values are persisted to logs. Entries should not be renumbered and
-  // numeric values should never be reused.
-  enum class PriorityChangeStatus {
-    kNoPriorityChange = 0,
-    kPriorityHasChanged = 1,
-
-    kMaxValue = kPriorityHasChanged
-  };
-
   static DOMTaskSignal* CreateFixedPriorityTaskSignal(
       ScriptState*,
       const AtomicString& priority);
@@ -63,10 +54,6 @@
   void Trace(Visitor*) const override;
   bool HasPendingActivity() const override;
 
-  PriorityChangeStatus GetPriorityChangeStatus() const {
-    return priority_change_status_;
-  }
-
   bool HasFixedPriority() const;
 
  private:
@@ -77,13 +64,8 @@
   void OnSignalSettled(AbortSignalCompositionType) override;
 
   AtomicString priority_;
-
-  PriorityChangeStatus priority_change_status_ =
-      PriorityChangeStatus::kNoPriorityChange;
-
   HeapLinkedHashSet<WeakMember<AlgorithmHandle>> priority_change_algorithms_;
   Member<AbortSignalCompositionManager> priority_composition_manager_;
-
   bool is_priority_changing_ = false;
 };
 
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
index 0758b93..2a3a065 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
@@ -66,9 +66,9 @@
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/skia/include/core/SkAlphaType.h"
 #include "third_party/skia/include/core/SkData.h"
-#include "third_party/skia/include/core/SkEncodedImageFormat.h"
 #include "third_party/skia/include/core/SkImage.h"
 #include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/encode/SkPngEncoder.h"
 
 namespace blink {
 
@@ -185,7 +185,7 @@
   DCHECK(
       base::FeatureList::IsEnabled(features::kCanvasCompressHibernatedImage));
   sk_sp<SkData> encoded =
-      params->image->encodeToData(SkEncodedImageFormat::kPNG, 100);
+      SkPngEncoder::Encode(nullptr, params->image.get(), {});
 
   size_t original_memory_size = ImageMemorySize(*params->image);
   int compression_ratio_percentage = static_cast<int>(
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index f4fa6835..4eca8ca 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -209,9 +209,6 @@
   if (scroll_translation.HasDirectCompositingReasons()) {
     return true;
   }
-  if (RuntimeEnabledFeatures::PreferNonCompositedScrollingEnabled()) {
-    return false;
-  }
   // Don't automatically composite non-user-scrollable scrollers.
   if (!scroll_translation.ScrollNode()->UserScrollableHorizontal() &&
       !scroll_translation.ScrollNode()->UserScrollableVertical()) {
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
index 40be47a..ea896d6 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -621,15 +621,15 @@
   compositor_node.is_composited =
       client_.NeedsCompositedScrolling(scroll_translation_node);
   if (RuntimeEnabledFeatures::CompositeScrollAfterPaintEnabled() &&
-      !RuntimeEnabledFeatures::PreferNonCompositedScrollingEnabled() &&
-      !compositor_node.is_composited &&
-      compositor_node.main_thread_scrolling_reasons ==
-          cc::MainThreadScrollingReason::kNotScrollingOnMain) {
+      !compositor_node.is_composited) {
     // TODO(crbug.com/1414885): We can't distinguish kNotOpaqueForTextAndLCDText
     // and kCantPaintScrollingBackgroundAndLCDText here. We should probably
     // merge the two reasons for CompositeScrollAfterPaint.
-    compositor_node.main_thread_scrolling_reasons =
-        cc::MainThreadScrollingReason::kNotOpaqueForTextAndLCDText;
+    compositor_node.main_thread_scrolling_reasons |=
+        scroll_node.GetCompositedScrollingPreference() ==
+                CompositedScrollingPreference::kNotPreferred
+            ? cc::MainThreadScrollingReason::kPreferNonCompositedScrolling
+            : cc::MainThreadScrollingReason::kNotOpaqueForTextAndLCDText;
   }
 
   scroll_node.SetCcNodeId(new_sequence_number_, id);
diff --git a/third_party/blink/renderer/platform/graphics/compositing_reasons.h b/third_party/blink/renderer/platform/graphics/compositing_reasons.h
index befeb85..14f883e 100644
--- a/third_party/blink/renderer/platform/graphics/compositing_reasons.h
+++ b/third_party/blink/renderer/platform/graphics/compositing_reasons.h
@@ -168,7 +168,8 @@
         // Normally a sticky element inherits the expanded contents cull rect of
         // the scroll container, but it needs expansion by itself if there is
         // additional clip between the sticky element and its scroll container.
-        kStickyPosition,
+        // Similar for anchor positioned elements.
+        kStickyPosition | kAnchorScroll,
   };
 };
 
diff --git a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.cc b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.cc
index b57605e..eec2c2ad 100644
--- a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.cc
@@ -102,7 +102,9 @@
     return gfx::Transform();
 
   if (source.Parent() && &destination == &source.Parent()->Unalias()) {
-    extra_result.has_sticky = source.RequiresCompositingForStickyPosition();
+    extra_result.has_sticky_or_anchor_scroll =
+        source.RequiresCompositingForStickyPosition() ||
+        source.RequiresCompositingForAnchorScroll();
     if (source.IsIdentityOr2dTranslation() && source.Origin().IsOrigin()) {
       // The result will be translate(origin)*matrix*translate(-origin) which
       // equals to matrix if the origin is zero or if the matrix is just
@@ -121,7 +123,8 @@
   const auto& source_cache = source.GetTransformCache();
   const auto& destination_cache = destination.GetTransformCache();
 
-  extra_result.has_sticky |= source_cache.has_sticky();
+  extra_result.has_sticky_or_anchor_scroll |=
+      source_cache.has_sticky_or_anchor_scroll();
 
   // Case 1a (fast path of case 1b): check if source and destination are under
   // the same 2d translation root.
@@ -254,10 +257,11 @@
   }
 
   if (for_compositing_overlap == ForCompositingOverlap::kYes &&
-      (extra_result.has_animation || extra_result.has_sticky)) {
-    // Assume during the animation or the sticky translation can map
-    // |rect_to_map| to anywhere during animation or composited scroll.
-    // Ancestor clips will still apply.
+      (extra_result.has_animation ||
+       extra_result.has_sticky_or_anchor_scroll)) {
+    // Assume during the animation, the sticky translation or the anchor-scroll
+    // translation can map |rect_to_map| to anywhere during animation or
+    // composited scroll. Ancestor clips will still apply.
     // TODO(crbug.com/1026653): Use animation bounds instead of infinite rect.
     // TODO(crbug.com/1117658): Use sticky bounds instead of infinite rect.
     rect_to_map = InfiniteLooseFloatClipRect();
@@ -428,8 +432,10 @@
       return FloatClipRect(gfx::RectF());
 
     if (for_compositing_overlap == ForCompositingOverlap::kYes &&
-        (extra_result.has_animation || extra_result.has_sticky))
+        (extra_result.has_animation ||
+         extra_result.has_sticky_or_anchor_scroll)) {
       continue;
+    }
 
     // This is where we generate the roundedness and tightness of clip rect
     // from clip and transform properties, and propagate them to |clip|.
@@ -441,9 +447,9 @@
       clip.Intersect(mapped_rect);
       // Inclusive intersected clips are not cached at present.
       node->GetClipCache().SetCachedClip(
-          GeometryMapperClipCache::ClipCacheEntry{clip_and_transform, clip,
-                                                  extra_result.has_animation,
-                                                  extra_result.has_sticky});
+          GeometryMapperClipCache::ClipCacheEntry{
+              clip_and_transform, clip, extra_result.has_animation,
+              extra_result.has_sticky_or_anchor_scroll});
     }
   }
   // Clips that are inclusive intersected or expanded for animation are not
diff --git a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h
index eaf8b2d..efcb671 100644
--- a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h
+++ b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h
@@ -186,7 +186,7 @@
  private:
   struct ExtraProjectionResult {
     bool has_animation = false;
-    bool has_sticky = false;
+    bool has_sticky_or_anchor_scroll = false;
     STACK_ALLOCATED();
   };
 
diff --git a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.cc b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.cc
index d1a7048..7495587b 100644
--- a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.cc
@@ -44,8 +44,9 @@
   const GeometryMapperTransformCache& parent =
       node.UnaliasedParent()->GetTransformCache();
 
-  has_sticky_ =
-      node.RequiresCompositingForStickyPosition() || parent.has_sticky_;
+  has_sticky_or_anchor_scroll_ = node.RequiresCompositingForStickyPosition() ||
+                                 node.RequiresCompositingForAnchorScroll() ||
+                                 parent.has_sticky_or_anchor_scroll_;
 
   is_backface_hidden_ =
       node.IsBackfaceHiddenInternal(parent.is_backface_hidden_);
diff --git a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.h b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.h
index d1a82957..370b7621 100644
--- a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.h
+++ b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.h
@@ -115,7 +115,9 @@
            plane_root_transform_->has_animation;
   }
 
-  bool has_sticky() const { return has_sticky_; }
+  bool has_sticky_or_anchor_scroll() const {
+    return has_sticky_or_anchor_scroll_;
+  }
 
   bool is_backface_hidden() const { return is_backface_hidden_; }
 
@@ -222,8 +224,8 @@
   const TransformPaintPropertyNode* nearest_directly_composited_ancestor_ =
       nullptr;
 
-  // Whether or not there is a sticky translation to the root.
-  bool has_sticky_ = false;
+  // Whether or not there is a sticky or anchor-scroll translation to the root.
+  bool has_sticky_or_anchor_scroll_ = false;
 
   bool is_backface_hidden_ = false;
 
diff --git a/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc b/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc
index ff7fe6e..896e3eb 100644
--- a/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc
@@ -44,8 +44,10 @@
                : PaintPropertyChangeType::kChangedOnlyCompositedValues;
   }
 
-  if (direct_compositing_reasons & CompositingReason::kStickyPosition) {
-    // The compositor handles sticky offset changes automatically.
+  if ((direct_compositing_reasons & CompositingReason::kStickyPosition) ||
+      (direct_compositing_reasons & CompositingReason::kAnchorScroll)) {
+    // The compositor handles sticky offset changes and anchor-scroll offset
+    // changes automatically.
     DCHECK(transform_and_origin.matrix.Preserves2dAxisAlignment());
     DCHECK(other.matrix.Preserves2dAxisAlignment());
     return PaintPropertyChangeType::kChangedOnlyCompositedValues;
diff --git a/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h b/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h
index a2a609c..98d2f4d 100644
--- a/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h
+++ b/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h
@@ -317,6 +317,10 @@
     return DirectCompositingReasons() & CompositingReason::kStickyPosition;
   }
 
+  bool RequiresCompositingForAnchorScroll() const {
+    return DirectCompositingReasons() & CompositingReason::kAnchorScroll;
+  }
+
   CompositingReasons DirectCompositingReasonsForDebugging() const {
     return DirectCompositingReasons();
   }
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_context.cc b/third_party/blink/renderer/platform/loader/fetch/fetch_context.cc
index 80f200b5..002566e 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_context.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_context.cc
@@ -54,7 +54,7 @@
 
 void FetchContext::PopulateResourceRequest(
     ResourceType,
-    const FetchParameters::ResourceWidth&,
+    const absl::optional<float> resource_width,
     ResourceRequest&,
     const ResourceLoaderOptions&) {}
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
index 1a549c594..fe36f68 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
@@ -142,10 +142,11 @@
   // Populates the ResourceRequest using the given values and information
   // stored in the FetchContext implementation. Used by ResourceFetcher to
   // prepare a ResourceRequest instance at the start of resource loading.
-  virtual void PopulateResourceRequest(ResourceType,
-                                       const FetchParameters::ResourceWidth&,
-                                       ResourceRequest&,
-                                       const ResourceLoaderOptions&);
+  virtual void PopulateResourceRequest(
+      ResourceType,
+      const absl::optional<float> resource_width,
+      ResourceRequest&,
+      const ResourceLoaderOptions&);
 
   // Called when the underlying context is detached. Note that some
   // FetchContexts continue working after detached (e.g., for fetch() operations
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc b/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc
index 360c46eb..c2255fd 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.cc
@@ -45,10 +45,7 @@
                                  ResourceLoaderOptions options)
     : resource_request_(std::move(resource_request)),
       decoder_options_(TextResourceDecoderOptions::kPlainTextContent),
-      options_(std::move(options)),
-      speculative_preload_type_(SpeculativePreloadType::kNotSpeculative),
-      defer_(kNoDefer),
-      image_request_behavior_(ImageRequestBehavior::kNone) {}
+      options_(std::move(options)) {}
 
 FetchParameters::FetchParameters(FetchParameters&&) = default;
 
@@ -89,11 +86,14 @@
     resource_request_.SetHTTPOrigin(origin);
 }
 
-void FetchParameters::SetResourceWidth(ResourceWidth resource_width) {
-  if (resource_width.is_set) {
-    resource_width_.width = resource_width.width;
-    resource_width_.is_set = true;
-  }
+void FetchParameters::SetResourceWidth(
+    const absl::optional<float> resource_width) {
+  resource_width_ = resource_width;
+}
+
+void FetchParameters::SetResourceHeight(
+    const absl::optional<float> resource_height) {
+  resource_height_ = resource_height;
 }
 
 void FetchParameters::SetSpeculativePreloadType(
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h b/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h
index c6dfa97..d9d1a988 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h
@@ -68,14 +68,6 @@
                        // ResourceFetcher::non_blocking_loaders_.
   };
 
-  struct ResourceWidth {
-    DISALLOW_NEW();
-    float width;
-    bool is_set;
-
-    ResourceWidth() : width(0), is_set(false) {}
-  };
-
   static FetchParameters CreateForTest(ResourceRequest);
 
   FetchParameters(ResourceRequest, ResourceLoaderOptions);
@@ -124,8 +116,11 @@
   DeferOption Defer() const { return defer_; }
   void SetDefer(DeferOption defer) { defer_ = defer; }
 
-  ResourceWidth GetResourceWidth() const { return resource_width_; }
-  void SetResourceWidth(ResourceWidth);
+  absl::optional<float> GetResourceWidth() const { return resource_width_; }
+  void SetResourceWidth(const absl::optional<float> resource_width);
+
+  absl::optional<float> GetResourceHeight() const { return resource_height_; }
+  void SetResourceHeight(const absl::optional<float> resource_height);
 
   bool IsSpeculativePreload() const {
     return speculative_preload_type_ != SpeculativePreloadType::kNotSpeculative;
@@ -224,10 +219,12 @@
   // in ResourceFetcher::PrepareRequest() before actual use.
   TextResourceDecoderOptions decoder_options_;
   ResourceLoaderOptions options_;
-  SpeculativePreloadType speculative_preload_type_;
-  DeferOption defer_;
-  ResourceWidth resource_width_;
-  ImageRequestBehavior image_request_behavior_;
+  SpeculativePreloadType speculative_preload_type_ =
+      SpeculativePreloadType::kNotSpeculative;
+  DeferOption defer_ = DeferOption::kNoDefer;
+  absl::optional<float> resource_width_;
+  absl::optional<float> resource_height_;
+  ImageRequestBehavior image_request_behavior_ = ImageRequestBehavior::kNone;
   mojom::blink::ScriptType script_type_ = mojom::blink::ScriptType::kClassic;
   bool is_stale_revalidation_ = false;
   bool is_from_origin_dirty_style_sheet_ = false;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index 7c7e303..2f6da90 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -454,7 +454,9 @@
     FetchParameters::SpeculativePreloadType speculative_preload_type,
     RenderBlockingBehavior render_blocking_behavior,
     mojom::blink::ScriptType script_type,
-    bool is_link_preload) {
+    bool is_link_preload,
+    const absl::optional<float> resource_width,
+    const absl::optional<float> resource_height) {
   DCHECK(!resource_request.PriorityHasBeenSet() ||
          type == ResourceType::kImage);
   ResourceLoadPriority priority = TypeToPriority(type);
@@ -530,6 +532,10 @@
       priority, type, resource_request, defer_option, render_blocking_behavior,
       is_link_preload);
 
+  priority = AdjustImagePriority(priority, type, resource_request,
+                                 speculative_preload_type, is_link_preload,
+                                 resource_width, resource_height);
+
   if (properties_->IsSubframeDeprioritizationEnabled()) {
     if (properties_->IsOutermostMainFrame()) {
       UMA_HISTOGRAM_ENUMERATION(
@@ -555,6 +561,52 @@
   return priority;
 }
 
+// Boost the priority for the first N not-small images from the preload scanner
+ResourceLoadPriority ResourceFetcher::AdjustImagePriority(
+    ResourceLoadPriority priority_so_far,
+    ResourceType type,
+    const ResourceRequestHead& resource_request,
+    FetchParameters::SpeculativePreloadType speculative_preload_type,
+    bool is_link_preload,
+    const absl::optional<float> resource_width,
+    const absl::optional<float> resource_height) {
+  ResourceLoadPriority new_priority = priority_so_far;
+
+  if (speculative_preload_type ==
+          FetchParameters::SpeculativePreloadType::kInDocument &&
+      type == ResourceType::kImage && !is_link_preload &&
+      boosted_image_count_ < boosted_image_target_) {
+    // If the width or height is available, determine if it is a "small" image
+    // where "small" is any image that covers less than 10,000px^2.
+    // If a size can not be determined then it defaults to "not small"
+    // and gets the relevant priority boost.
+    bool is_small_image = false;
+    if (resource_width && resource_height) {
+      float image_area = resource_width.value() * resource_height.value();
+      if (image_area <= small_image_max_size_) {
+        is_small_image = true;
+      }
+    } else if (resource_width && resource_width == 0) {
+      is_small_image = true;
+    } else if (resource_height && resource_height == 0) {
+      is_small_image = true;
+    }
+    // Count all candidate images
+    if (!is_small_image) {
+      ++boosted_image_count_;
+
+      // only boost the priority if one wasn't explicitly set
+      if (new_priority < ResourceLoadPriority::kMedium &&
+          resource_request.GetFetchPriorityHint() ==
+              mojom::blink::FetchPriorityHint::kAuto) {
+        new_priority = ResourceLoadPriority::kMedium;
+      }
+    }
+  }
+
+  return new_priority;
+}
+
 // This method simply takes in information about a ResourceRequest, and returns
 // if the resource should be loaded in parallel (incremental) or sequentially
 // for protocols that support multiplexing and HTTP extensible priorities
@@ -614,6 +666,15 @@
       image_fetched_(false) {
   InstanceCounters::IncrementCounter(InstanceCounters::kResourceFetcherCounter);
 
+  // Determine the number of images that should get a boosted priority and the
+  // pixel area threshold for determining "small" images.
+  // TODO(http://crbug.com/1431169): Change these to constexpr after the
+  // experiments determine appropriate values.
+  if (base::FeatureList::IsEnabled(features::kBoostImagePriority)) {
+    boosted_image_target_ = features::kBoostImagePriorityImageCount.Get();
+    small_image_max_size_ = features::kBoostImagePriorityImageSize.Get();
+  }
+
   if (IsMainThread()) {
     MainThreadFetchersSet().insert(this);
     MemoryPressureListenerRegistry::Instance().RegisterClient(this);
@@ -992,7 +1053,8 @@
         resource_type, params.GetResourceRequest(),
         ResourcePriority::kNotVisible, params.Defer(),
         params.GetSpeculativePreloadType(), params.GetRenderBlockingBehavior(),
-        params.GetScriptType(), params.IsLinkPreload());
+        params.GetScriptType(), params.IsLinkPreload(),
+        params.GetResourceWidth(), params.GetResourceHeight());
   }
 
   DCHECK_NE(computed_load_priority, ResourceLoadPriority::kUnresolved);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
index 619dcf3..014bf28 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
@@ -313,11 +313,13 @@
       FetchParameters::SpeculativePreloadType speculative_preload_type,
       RenderBlockingBehavior render_blocking_behavior,
       mojom::blink::ScriptType script_type,
-      bool is_link_preload) {
-    return ComputeLoadPriority(type, request, visibility_statue, defer_option,
-                               speculative_preload_type,
-                               render_blocking_behavior, script_type,
-                               is_link_preload);
+      bool is_link_preload,
+      const absl::optional<float> resource_width = absl::nullopt,
+      const absl::optional<float> resource_height = absl::nullopt) {
+    return ComputeLoadPriority(
+        type, request, visibility_statue, defer_option,
+        speculative_preload_type, render_blocking_behavior, script_type,
+        is_link_preload, resource_width, resource_height);
   }
 
   bool ShouldLoadIncrementalForTesting(ResourceType type) {
@@ -384,7 +386,17 @@
           FetchParameters::SpeculativePreloadType::kNotSpeculative,
       RenderBlockingBehavior = RenderBlockingBehavior::kNonBlocking,
       mojom::blink::ScriptType script_type = mojom::blink::ScriptType::kClassic,
-      bool is_link_preload = false);
+      bool is_link_preload = false,
+      const absl::optional<float> resource_width = absl::nullopt,
+      const absl::optional<float> resource_height = absl::nullopt);
+  ResourceLoadPriority AdjustImagePriority(
+      ResourceLoadPriority priority_so_far,
+      ResourceType type,
+      const ResourceRequestHead& resource_request,
+      FetchParameters::SpeculativePreloadType speculative_preload_type,
+      bool is_link_preload,
+      const absl::optional<float> resource_width,
+      const absl::optional<float> resource_height);
   bool ShouldLoadIncremental(ResourceType type) const;
 
   // |virtual_time_pauser| is an output parameter. PrepareRequest may
@@ -612,6 +624,17 @@
   std::unique_ptr<ukm::MojoUkmRecorder> ukm_recorder_;
 
   SubresourceLoadMetrics subresource_load_metrics_;
+
+  // Number of of not-small images that get a priority boost.
+  // TODO(http://crbug.com/1431169): change this to a const after experiments
+  // determine an approopriate value.
+  uint32_t boosted_image_target_ = 0;
+
+  // Number of images that have had their priority boosted by heuristics.
+  uint32_t boosted_image_count_ = 0;
+
+  // Area (in pixels) below which an image is considered "small"
+  uint32_t small_image_max_size_ = 0;
 };
 
 class ResourceCacheValidationSuppressor {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
index 6d94f1fb8..29183ff 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
@@ -1391,6 +1391,124 @@
   }
 }
 
+TEST_F(ResourceFetcherTest, BoostImagePriority) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(features::kBoostImagePriority);
+  auto& properties = *MakeGarbageCollected<TestResourceFetcherProperties>();
+  auto* fetcher = CreateFetcher(properties);
+  ResourceRequest request(KURL("https://www.example.com/"));
+
+  // A "small" image should not get a priority boost or count against the
+  // 5-image limit.
+  {
+    properties.SetIsOutermostMainFrame(true);
+    properties.SetIsSubframeDeprioritizationEnabled(false);
+    const auto priority = fetcher->ComputeLoadPriorityForTesting(
+        ResourceType::kImage, request, ResourcePriority::kNotVisible,
+        FetchParameters::DeferOption::kNoDefer,
+        FetchParameters::SpeculativePreloadType::kInDocument,
+        RenderBlockingBehavior::kNonBlocking,
+        mojom::blink::ScriptType::kClassic, false /* is_link_preload */,
+        10 /* resource_width*/, 10 /* resource_height*/);
+    EXPECT_EQ(priority, ResourceLoadPriority::kLow);
+  }
+
+  // Test an image with just one of width or height set to zero but the other
+  // dimension not specified to make sure it is also treated as "small"
+  {
+    properties.SetIsOutermostMainFrame(true);
+    properties.SetIsSubframeDeprioritizationEnabled(false);
+    const auto priority = fetcher->ComputeLoadPriorityForTesting(
+        ResourceType::kImage, request, ResourcePriority::kNotVisible,
+        FetchParameters::DeferOption::kNoDefer,
+        FetchParameters::SpeculativePreloadType::kInDocument,
+        RenderBlockingBehavior::kNonBlocking,
+        mojom::blink::ScriptType::kClassic, false /* is_link_preload */,
+        0 /* resource_width*/, absl::nullopt /* resource_height*/);
+    EXPECT_EQ(priority, ResourceLoadPriority::kLow);
+  }
+  {
+    properties.SetIsOutermostMainFrame(true);
+    properties.SetIsSubframeDeprioritizationEnabled(false);
+    const auto priority = fetcher->ComputeLoadPriorityForTesting(
+        ResourceType::kImage, request, ResourcePriority::kNotVisible,
+        FetchParameters::DeferOption::kNoDefer,
+        FetchParameters::SpeculativePreloadType::kInDocument,
+        RenderBlockingBehavior::kNonBlocking,
+        mojom::blink::ScriptType::kClassic, false /* is_link_preload */,
+        absl::nullopt /* resource_width*/, 0 /* resource_height*/);
+    EXPECT_EQ(priority, ResourceLoadPriority::kLow);
+  }
+
+  // The next 5 images that are not-small should be boosted to Medium priority.
+  // Test both an explicit size over 10,000px^2 as well as no size specified
+  // which defaults to not-small.
+  // #1 - 200x200 = 40000px^2.
+  {
+    properties.SetIsOutermostMainFrame(true);
+    properties.SetIsSubframeDeprioritizationEnabled(false);
+    const auto priority = fetcher->ComputeLoadPriorityForTesting(
+        ResourceType::kImage, request, ResourcePriority::kNotVisible,
+        FetchParameters::DeferOption::kNoDefer,
+        FetchParameters::SpeculativePreloadType::kInDocument,
+        RenderBlockingBehavior::kNonBlocking,
+        mojom::blink::ScriptType::kClassic, false /* is_link_preload */,
+        200 /* resource_width*/, 200 /* resource_height*/);
+    EXPECT_EQ(priority, ResourceLoadPriority::kMedium);
+  }
+  // #2 - non-zero width but no height.
+  {
+    properties.SetIsOutermostMainFrame(true);
+    properties.SetIsSubframeDeprioritizationEnabled(false);
+    const auto priority = fetcher->ComputeLoadPriorityForTesting(
+        ResourceType::kImage, request, ResourcePriority::kNotVisible,
+        FetchParameters::DeferOption::kNoDefer,
+        FetchParameters::SpeculativePreloadType::kInDocument,
+        RenderBlockingBehavior::kNonBlocking,
+        mojom::blink::ScriptType::kClassic, false /* is_link_preload */,
+        200 /* resource_width*/, absl::nullopt /* resource_height*/);
+    EXPECT_EQ(priority, ResourceLoadPriority::kMedium);
+  }
+  // #3 - non-zero height but no width.
+  {
+    properties.SetIsOutermostMainFrame(true);
+    properties.SetIsSubframeDeprioritizationEnabled(false);
+    const auto priority = fetcher->ComputeLoadPriorityForTesting(
+        ResourceType::kImage, request, ResourcePriority::kNotVisible,
+        FetchParameters::DeferOption::kNoDefer,
+        FetchParameters::SpeculativePreloadType::kInDocument,
+        RenderBlockingBehavior::kNonBlocking,
+        mojom::blink::ScriptType::kClassic, false /* is_link_preload */,
+        absl::nullopt /* resource_width*/, 200 /* resource_height*/);
+    EXPECT_EQ(priority, ResourceLoadPriority::kMedium);
+  }
+  // #4-5 - neither height nor width.
+  for (int i = 4; i <= 5; i++) {
+    properties.SetIsOutermostMainFrame(true);
+    properties.SetIsSubframeDeprioritizationEnabled(false);
+    const auto priority = fetcher->ComputeLoadPriorityForTesting(
+        ResourceType::kImage, request, ResourcePriority::kNotVisible,
+        FetchParameters::DeferOption::kNoDefer,
+        FetchParameters::SpeculativePreloadType::kInDocument,
+        RenderBlockingBehavior::kNonBlocking,
+        mojom::blink::ScriptType::kClassic, false /* is_link_preload */);
+    EXPECT_EQ(priority, ResourceLoadPriority::kMedium);
+  }
+
+  // After the 5th non-small image, images should get the default Low priority.
+  {
+    properties.SetIsOutermostMainFrame(true);
+    properties.SetIsSubframeDeprioritizationEnabled(false);
+    const auto priority = fetcher->ComputeLoadPriorityForTesting(
+        ResourceType::kImage, request, ResourcePriority::kNotVisible,
+        FetchParameters::DeferOption::kNoDefer,
+        FetchParameters::SpeculativePreloadType::kInDocument,
+        RenderBlockingBehavior::kNonBlocking,
+        mojom::blink::ScriptType::kClassic, false /* is_link_preload */);
+    EXPECT_EQ(priority, ResourceLoadPriority::kLow);
+  }
+}
+
 TEST_F(ResourceFetcherTest, Detach) {
   DetachableResourceFetcherProperties& properties =
       MakeGarbageCollected<TestResourceFetcherProperties>()->MakeDetachable();
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
index bb552c29..a0918f6 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
@@ -105,6 +105,10 @@
                                kTightLimitForRendererSideResourceSchedulerName,
                                kTightLimitForRendererSideResourceScheduler);
 
+  if (base::FeatureList::IsEnabled(features::kBoostImagePriority)) {
+    tight_medium_limit_ = features::kBoostImagePriorityTightMediumLimit.Get();
+  }
+
   scheduler_observer_handle_ = frame_or_worker_scheduler->AddLifecycleObserver(
       FrameScheduler::ObserverType::kLoader,
       WTF::BindRepeating(&ResourceLoadScheduler::OnLifecycleStateChanged,
@@ -158,7 +162,7 @@
   // Check if the request can be throttled.
   ClientIdWithPriority request_info(*id, priority, intra_priority);
   if (!IsClientDelayable(option)) {
-    Run(*id, client, /*throttleable=*/false);
+    Run(*id, client, /*throttleable=*/false, priority);
     return;
   }
 
@@ -213,6 +217,7 @@
 
     running_requests_.erase(id);
     running_throttleable_requests_.erase(id);
+    running_medium_requests_.erase(id);
 
     if (option == ReleaseOption::kReleaseAndSchedule)
       MaybeRun();
@@ -236,10 +241,13 @@
   return false;
 }
 
-void ResourceLoadScheduler::SetOutstandingLimitForTesting(size_t tight_limit,
-                                                          size_t normal_limit) {
+void ResourceLoadScheduler::SetOutstandingLimitForTesting(
+    size_t tight_limit,
+    size_t normal_limit,
+    size_t tight_medium_limit) {
   tight_outstanding_limit_ = tight_limit;
   normal_outstanding_limit_ = normal_limit;
+  tight_medium_limit_ = tight_medium_limit;
   MaybeRun();
 }
 
@@ -300,14 +308,16 @@
       stoppable_it != stoppable_queue.end() &&
       (!IsClientDelayable(ThrottleOption::kStoppable) ||
        IsRunningThrottleableRequestsLessThanOutStandingLimit(
-           GetOutstandingLimit(stoppable_it->priority)));
+           GetOutstandingLimit(stoppable_it->priority),
+           stoppable_it->priority));
 
   auto throttleable_it = throttleable_queue.begin();
   bool has_runnable_throttleable_request =
       throttleable_it != throttleable_queue.end() &&
       (!IsClientDelayable(ThrottleOption::kThrottleable) ||
        IsRunningThrottleableRequestsLessThanOutStandingLimit(
-           GetOutstandingLimit(throttleable_it->priority)));
+           GetOutstandingLimit(throttleable_it->priority),
+           throttleable_it->priority));
 
   if (!has_runnable_throttleable_request && !has_runnable_stoppable_request)
     return false;
@@ -354,18 +364,23 @@
 
     ResourceLoadSchedulerClient* client = found->value->client;
     ThrottleOption option = found->value->option;
+    ResourceLoadPriority priority = found->value->priority;
     pending_request_map_.erase(found);
-    Run(id, client, option == ThrottleOption::kThrottleable);
+    Run(id, client, option == ThrottleOption::kThrottleable, priority);
   }
 }
 
 void ResourceLoadScheduler::Run(ResourceLoadScheduler::ClientId id,
                                 ResourceLoadSchedulerClient* client,
-                                bool throttleable) {
+                                bool throttleable,
+                                ResourceLoadPriority priority) {
   // Assuming the request connection is not multiplexed.
   running_requests_.insert(id, IsMultiplexedConnection(false));
   if (throttleable)
     running_throttleable_requests_.insert(id);
+  if (priority == ResourceLoadPriority::kMedium) {
+    running_medium_requests_.insert(id);
+  }
   client->Run();
 }
 
@@ -430,7 +445,14 @@
 
 bool ResourceLoadScheduler::
     IsRunningThrottleableRequestsLessThanOutStandingLimit(
-        size_t out_standing_limit) {
+        size_t out_standing_limit,
+        ResourceLoadPriority priority) {
+  // Allow for a minimum number of medium-priority requests to be in-flight
+  // independent of the overall number of pending requests.
+  if (priority == ResourceLoadPriority::kMedium &&
+      running_medium_requests_.size() < tight_medium_limit_) {
+    return true;
+  }
   if (CanRequestForMultiplexedConnectionsInTight()) {
     DCHECK_EQ(policy_, ThrottlingPolicy::kTight);
     return (running_throttleable_requests_.size() -
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h
index 5d453a908..6b84178 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h
@@ -223,7 +223,9 @@
   void SetOutstandingLimitForTesting(size_t limit) {
     SetOutstandingLimitForTesting(limit, limit);
   }
-  void SetOutstandingLimitForTesting(size_t tight_limit, size_t normal_limit);
+  void SetOutstandingLimitForTesting(size_t tight_limit,
+                                     size_t normal_limit,
+                                     size_t tight_medium_limit = 0);
 
   // FrameOrWorkerScheduler lifecycle observer callback.
   void OnLifecycleStateChanged(scheduler::SchedulingLifecycleState);
@@ -315,14 +317,18 @@
   void MaybeRun();
 
   // Grants a client to run,
-  void Run(ClientId, ResourceLoadSchedulerClient*, bool throttleable);
+  void Run(ClientId,
+           ResourceLoadSchedulerClient*,
+           bool throttleable,
+           ResourceLoadPriority priority);
 
   size_t GetOutstandingLimit(ResourceLoadPriority priority) const;
 
   void ShowConsoleMessageIfNeeded();
 
   bool IsRunningThrottleableRequestsLessThanOutStandingLimit(
-      size_t out_standing_limit);
+      size_t out_standing_limit,
+      ResourceLoadPriority priority);
 
   bool CanRequestForMultiplexedConnectionsInTight() const;
 
@@ -340,6 +346,7 @@
 
   // Used when |policy_| is |kTight|.
   size_t tight_outstanding_limit_ = kOutstandingUnlimited;
+  size_t tight_medium_limit_ = 0u;
 
   // Used when |policy_| is |kNormal|.
   size_t normal_outstanding_limit_ = kOutstandingUnlimited;
@@ -358,6 +365,7 @@
   HashMap<ClientId, IsMultiplexedConnection> running_requests_;
 
   HashSet<ClientId> running_throttleable_requests_;
+  HashSet<ClientId> running_medium_requests_;
 
   // Holds a flag to omit repeating console messages.
   bool is_console_info_shown_ = false;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler_test.cc
index 960252f99..ee26ff9 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler_test.cc
@@ -374,12 +374,16 @@
 }
 
 TEST_F(ResourceLoadSchedulerTest, PriorityIsConsidered) {
-  // Push three requests.
+  // This tests the request limiting logic in the scheduler for
+  // the tight-mode and regular-mode limits as well as the
+  // special-casing for medium-priority requests.
+
+  // Allow 1 overall request as well as 1 special-case medium request
+  // while blocking anly low-priority requests (starts in tight mode)
+  Scheduler()->SetOutstandingLimitForTesting(
+      0 /* tight_limit */, 1 /* normal_limit */, 1 /* tight_medium_limit */);
+
   MockClient* client1 = MakeGarbageCollected<MockClient>();
-
-  // Allows one kHigh priority request by limits below.
-  Scheduler()->SetOutstandingLimitForTesting(0, 1);
-
   ResourceLoadScheduler::ClientId id1 = ResourceLoadScheduler::kInvalidClientId;
   Scheduler()->Request(client1, ThrottleOption::kThrottleable,
                        ResourceLoadPriority::kLowest, 10 /* intra_priority */,
@@ -407,33 +411,66 @@
                        &id4);
   EXPECT_NE(ResourceLoadScheduler::kInvalidClientId, id4);
 
-  EXPECT_FALSE(client1->WasRun());
-  EXPECT_FALSE(client2->WasRun());
-  EXPECT_FALSE(client3->WasRun());
-  EXPECT_TRUE(client4->WasRun());
+  MockClient* client5 = MakeGarbageCollected<MockClient>();
+  ResourceLoadScheduler::ClientId id5 = ResourceLoadScheduler::kInvalidClientId;
+  Scheduler()->Request(client5, ThrottleOption::kThrottleable,
+                       ResourceLoadPriority::kMedium, 0 /* intra_priority */,
+                       &id5);
+  EXPECT_NE(ResourceLoadScheduler::kInvalidClientId, id5);
 
+  MockClient* client6 = MakeGarbageCollected<MockClient>();
+  ResourceLoadScheduler::ClientId id6 = ResourceLoadScheduler::kInvalidClientId;
+  Scheduler()->Request(client6, ThrottleOption::kThrottleable,
+                       ResourceLoadPriority::kMedium, 0 /* intra_priority */,
+                       &id6);
+  EXPECT_NE(ResourceLoadScheduler::kInvalidClientId, id6);
+
+  // Expect that all 3 kLow requests are held, the one kHigh request
+  // is sent by the normal limit and one of the kMedium requests
+  // was sent using the medium-specific limit.
+  EXPECT_FALSE(client1->WasRun()); /* kLowest */
+  EXPECT_FALSE(client2->WasRun()); /* kLow intra=1 */
+  EXPECT_FALSE(client3->WasRun()); /* kLow intra=3 */
+  EXPECT_TRUE(client4->WasRun());  /* kHigh - Newly run */
+  EXPECT_TRUE(client5->WasRun());  /* kMedium - Newly run */
+  EXPECT_FALSE(client6->WasRun()); /* kMedium */
+
+  // Calling Release() on kMedium schedules another one.
+  EXPECT_TRUE(ReleaseAndSchedule(id5));
+  EXPECT_FALSE(client1->WasRun()); /* kLowest */
+  EXPECT_FALSE(client2->WasRun()); /* kLow intra=1 */
+  EXPECT_FALSE(client3->WasRun()); /* kLow intra=3 */
+  // 4 and 5 were already run and checked
+  EXPECT_TRUE(client6->WasRun()); /* kMedium - Newly run */
+
+  // Calling Release() on the last kMedium does not schedule non-medium.
+  EXPECT_TRUE(ReleaseAndSchedule(id6));
+  EXPECT_FALSE(client1->WasRun()); /* kLowest */
+  EXPECT_FALSE(client2->WasRun()); /* kLow intra=1 */
+  EXPECT_FALSE(client3->WasRun()); /* kLow intra=3 */
+  // 4-6 have already run and been run and validated
+
+  // Increasing the limit to 2 should allow another low-priority request
+  // through, in order of priority (client 3 with the highest intra-priority).
   Scheduler()->SetOutstandingLimitForTesting(2);
+  EXPECT_FALSE(client1->WasRun()); /* kLowest */
+  EXPECT_FALSE(client2->WasRun()); /* kLow intra=1 */
+  EXPECT_TRUE(client3->WasRun());  /* kLow intra=3 - Newly run */
 
-  EXPECT_FALSE(client1->WasRun());
-  EXPECT_FALSE(client2->WasRun());
-  EXPECT_TRUE(client3->WasRun());
-  EXPECT_TRUE(client4->WasRun());
-
+  // Increasing the limit to 3 should allow another low-priority request
+  // through, in order of priority (client 2).
   Scheduler()->SetOutstandingLimitForTesting(3);
+  EXPECT_FALSE(client1->WasRun()); /* kLowest */
+  EXPECT_TRUE(client2->WasRun());  /* kLow intra=1 - Newly run */
+  // 3-6 have already run and been run and validated
 
-  EXPECT_FALSE(client1->WasRun());
-  EXPECT_TRUE(client2->WasRun());
-  EXPECT_TRUE(client3->WasRun());
-  EXPECT_TRUE(client4->WasRun());
-
+  // Increasing the limit to 4 should allow the final (lowest-priority)
+  // request through.
   Scheduler()->SetOutstandingLimitForTesting(4);
-
   EXPECT_TRUE(client1->WasRun());
-  EXPECT_TRUE(client2->WasRun());
-  EXPECT_TRUE(client3->WasRun());
-  EXPECT_TRUE(client4->WasRun());
 
   // Release the rest.
+  EXPECT_TRUE(Release(id4));
   EXPECT_TRUE(Release(id3));
   EXPECT_TRUE(Release(id2));
   EXPECT_TRUE(Release(id1));
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 6d8eca7..4b3204f 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1180,6 +1180,10 @@
       depends_on: ["CSSTextWrap"],
     },
     {
+      name: "CSSZoom",
+      status: "stable",
+    },
+    {
       name: "Database",
       public: true,
       status: "stable",
@@ -2015,7 +2019,7 @@
     },
     {
       name: "LayoutNGSubgrid",
-      status: "test",
+      status: "experimental",
       base_feature: "none",
     },
     {
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 674c3a4..33bcbbb 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3667,18 +3667,11 @@
 crbug.com/764235 external/wpt/css/css-grid/alignment/grid-baseline-justify-001.html [ Failure ]
 
 # [css-subgrid]
-crbug.com/618969 external/wpt/css/css-grid/subgrid/auto-track-sizing-001.html [ Failure ]
-crbug.com/618969 external/wpt/css/css-grid/subgrid/auto-track-sizing-002.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/baseline-001.html [ Failure ]
-crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-001.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-002.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-003.html [ Failure ]
-crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-004.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-007.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-008.html [ Failure ]
-crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-larger-001.html [ Failure ]
-crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-larger-002.html [ Failure ]
-crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-smaller-001.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/item-percentage-height-001.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/line-names-007.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/line-names-012.html [ Failure ]
@@ -5989,7 +5982,7 @@
 
 # Sheriff 2022-08-01
 # TODO(crbug.com/1225773): Re-enable this test
-crbug.com/1225773 [ Linux ] external/wpt/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-event-during-parse.html [ Crash Failure Pass Timeout ]
+crbug.com/1225773 external/wpt/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-event-during-parse.html [ Failure ]
 
 # Flaky timeouts on WebKit Linux MSAN
 crbug.com/1218100 [ Linux ] external/wpt/IndexedDB/idb-partitioned-coverage.tentative.sub.html [ Pass Timeout ]
@@ -6884,4 +6877,3 @@
 
 # Sheriff 2023-04-13
 crbug.com/1432763 [ Linux ] external/wpt/fetch/metadata/generated/element-picture.https.sub.html [ Pass Timeout ]
-crbug.com/1432812 [ Win11 ] fast/backgrounds/repeat/negative-offset-repeat-transformed.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 8e338f1..4565bbf 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1772,17 +1772,6 @@
     "expires": "Jul 1, 2023"
   },
   {
-    "prefix": "abort-signal-remove",
-    "platforms": ["Linux", "Mac", "Win"],
-    "bases": [
-      "external/wpt/eyedropper",
-      "external/wpt/idle-detection",
-      "external/wpt/web-nfc"
-    ],
-    "args": ["--disable-features=AbortSignalHandleBasedRemoval"],
-    "expires": "Jul 1, 2023"
-  },
-  {
     "prefix": "split-user-media-queues",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [
@@ -1930,5 +1919,16 @@
       "--enable-features=KeepAliveInBrowserMigration"
     ],
     "expires": "Dec 1, 2023"
+  },
+  {
+    "prefix": "boost-image-priority",
+    "platforms": ["Linux"],
+    "bases": [
+      "http/tests/devtools/network/resource-priority.js",
+      "http/tests/inspector-protocol/network/is-same-site.js",
+      "http/tests/priority-hints/image-initial-load.html"
+    ],
+    "args": ["--enable-features=BoostImagePriority"],
+    "expires": "Dec 1, 2023"
   }
 ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 5c481b4..3c53433 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -75232,6 +75232,19 @@
        {}
       ]
      ],
+     "anchor-scroll-composited-scrolling-006.html": [
+      "6b5f268f5548b3e6db472d4939f7076bed09a64d",
+      [
+       null,
+       [
+        [
+         "/css/css-anchor-position/reference/anchor-scroll-composited-scrolling-006-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "anchor-scroll-fixedpos.tentative.html": [
       "ee7d22608b65570fe075e02542dbd877cd38cd82",
       [
@@ -76143,6 +76156,19 @@
        {}
       ]
      ],
+     "background-attachment-fixed-inline-scrolled.html": [
+      "746997d6057ba1d2c109dafdfe7730ef149cd21e",
+      [
+       null,
+       [
+        [
+         "/css/css-backgrounds/background-attachment-fixed-inline-scrolled-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "background-attachment-fixed-inside-transform-1.html": [
       "9dae31aaccd1d281d05e43c3160000a53914d279",
       [
@@ -92796,6 +92822,19 @@
        {}
       ]
      ],
+     "overflow-clip-017.html": [
+      "1ab3cdd194f21f90699fe7f27c34a5614228ebb7",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square.xht",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "overflowed-block-with-no-room-after-000.html": [
       "084e16fb38de072fb83f92ba01302a2e404cdd97",
       [
@@ -95273,7 +95312,7 @@
       ]
      ],
      "import-conditional-001.html": [
-      "9bdbbcb5a32b638d2275cd86f0b9f2bbd026ebdc",
+      "a841f265457a3f7bba741143d586e98f8e0354ef",
       [
        null,
        [
@@ -134347,7 +134386,7 @@
        ]
       ],
       "auto-track-sizing-001.html": [
-       "0fdb9b0b7e2ed8855b02dcfb9baceeb61b7d05d3",
+       "4a946e6feb4dbf4c9c348896ad69a2c81232c17c",
        [
         null,
         [
@@ -256817,7 +256856,7 @@
         ]
        ],
        "selectmenu-option-arbitrary-content-displayed.tentative.html": [
-        "0fad1a1918f45b8144ec5aa50a7479aa45c0351e",
+        "05bc651cb7cb3468e4c8e8e5fdda7e47aaaed874",
         [
          null,
          [
@@ -269721,11 +269760,11 @@
   "support": {
    ".cache": {
     "gitignore2.json": [
-     "69e91ed3b330540edeb28086254e0a6c6c8ad264",
+     "488bd7eeae420c32e8296a7d42be8941f8183fdb",
      []
     ],
     "mtime.json": [
-     "5b19a37bc61f87adc6e3eccc2ab8529226b4d5c8",
+     "cc687d3d96b8b3ea03a7d46086785167ef2951ed",
      []
     ]
    },
@@ -285440,6 +285479,10 @@
       []
      ],
      "reference": {
+      "anchor-scroll-composited-scrolling-006-ref.html": [
+       "92fe187117ed3f55379797da7987e5272bd71301",
+       []
+      ],
       "anchor-scroll-fixedpos-ref.html": [
        "e73354df72dac33f7a94eaef445e80ec61e3976a",
        []
@@ -285837,6 +285880,10 @@
       "d1af9d7d555fc3e7f66841da6d1814f3ba484d71",
       []
      ],
+     "background-attachment-fixed-inline-scrolled-ref.html": [
+      "1767c84a5f011cbe120cf1b46af2d5639ea00e28",
+      []
+     ],
      "background-attachment-fixed-inside-transform-1-ref.html": [
       "8d4c3f785c8e84ffa121128cda96269574e27e73",
       []
@@ -304555,7 +304602,7 @@
        []
       ],
       "auto-track-sizing-001-ref.html": [
-       "800f87e5d00a767f1cb5e5816ffd46110fbd4e80",
+       "81c6d184021cac8e7a0df0402a42a082c675e62a",
        []
       ],
       "auto-track-sizing-001.html.ini": [
@@ -304883,7 +304930,7 @@
        []
       ],
       "subgrid-baseline-001.html.ini": [
-       "485cf09ea623fae040d850c84cb09c8271940650",
+       "f4293eb2d8ab90dd2ba320cdc343be0eea607bdf",
        []
       ],
       "subgrid-baseline-002-ref.html": [
@@ -326535,7 +326582,7 @@
        []
       ],
       "kind-of-widget-fallback-input-search-border-left-color-001.html.ini": [
-       "f044a6ba3bada9fd4bfc94ce390a6e43c830a805",
+       "bf0310aa0e5e64d939d6e2ec0c29af224aae68ba",
        []
       ],
       "kind-of-widget-fallback-input-search-border-left-style-001.html.ini": [
@@ -361566,7 +361613,7 @@
         []
        ],
        "selectmenu-option-arbitrary-content-displayed-ref.tentative.html": [
-        "3933b93894b33762bbaa9e0dd722da6c3d6c7499",
+        "171829d90f3f28a5ee5e5229086d18fd50b61289",
         []
        ],
        "selectmenu-option-arbitrary-content-displayed.tentative.html.ini": [
@@ -361611,7 +361658,7 @@
          []
         ],
         "fake-selectmenu.js": [
-         "cf3864a29409699fd338ec722e3b05f3cd533dac",
+         "84fe52856177fe6092e9fc69ae8128c3ba2a37d6",
          []
         ],
         "selectmenu_button_icon.svg": [
@@ -366220,10 +366267,6 @@
         ]
        },
        "unhandled-promise-rejections": {
-        "promise-rejection-event-during-parse-expected.txt": [
-         "b9aa87218420bb6d494f65d6fac6df23fdb794ae",
-         []
-        ],
         "promise-rejection-event-during-parse.html.ini": [
          "96bb0c55f0b571acc8f408956166cbbf28a94a82",
          []
@@ -386035,7 +386078,7 @@
      []
     ],
     "trust-token-parameter-validation.tentative.https.html.ini": [
-     "82e8dd212694d1d293051215511c862794022b23",
+     "d96d473c2600d84f4f05c2eac9111968c98ed27f",
      []
     ]
    },
@@ -396289,7 +396332,7 @@
      []
     ],
     "idlharness.https.window.js.ini": [
-     "7e642447165b2f7cde0ebd1c232b50836fcfa283",
+     "74fe81ac4f0c24f8ed9d8200b7d7f74cfba25e36",
      []
     ],
     "layers": {
@@ -613189,14 +613232,14 @@
      ]
     },
     "trust-token-parameter-validation-xhr.tentative.https.html": [
-     "73af4634b6d0326711275293e70e9b28ce618ec0",
+     "883c438fa93be67e44c2da172fca00a45a8d3ddc",
      [
       null,
       {}
      ]
     ],
     "trust-token-parameter-validation.tentative.https.html": [
-     "e2ab079434bd6e6eda9274ba9e0064683056367a",
+     "cf24b232e834383655e3d54b0a81fad3810454fc",
      [
       null,
       {}
@@ -629844,7 +629887,7 @@
      ]
     ],
     "videoFrame-serialization.crossAgentCluster.https.html": [
-     "cb02ad4bcc3a23c33e091b887bc069fcfe6ed170",
+     "8fe7cf44cc686e041fc1fdc677c060905e7d76d0",
      [
       null,
       {}
@@ -647750,7 +647793,7 @@
      ]
     ],
     "streams-echo.https.any.js": [
-     "18ebe123a417a919530dcbf31a441b141848cbd4",
+     "3b402d00e08aa0b7b746248835faed37b9b99578",
      [
       "webtransport/streams-echo.https.any.html",
       {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-composited-scrolling-006.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-composited-scrolling-006.html
new file mode 100644
index 0000000..6b5f268
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-scroll-composited-scrolling-006.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>Tests anchor-scroll element paint order in composited scrolling</title>
+<link rel="help" href="https://drafts4.csswg.org/css-anchor-position-1/#scroll">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<link rel="match" href="reference/anchor-scroll-composited-scrolling-006-ref.html">
+<style>
+body {
+  margin: 0;
+}
+#scroller {
+  width: 200px;
+  height: 100px;
+  overflow: scroll;
+  will-change: scroll-position;
+}
+#spacer {
+  height: 400px;
+}
+#anchor {
+  width: 100px;
+  height: 100px;
+  anchor-name: --a;
+}
+#target {
+  position: absolute;
+  width: 100px;
+  height: 100px;
+  background: red;
+  left: 0;
+  bottom: anchor(--a top);
+  anchor-scroll: --a;
+}
+#overlap {
+  position: absolute;
+  width: 100px;
+  height: 100px;
+  top: 150px;
+  left: 0;
+  z-index: 100;
+  background: green;
+}
+</style>
+
+<div id="overlap"></div>
+<div id="scroller">
+  <div id="spacer"></div>
+  <div id="anchor"></div>
+</div>
+<div id="target"></div>
+
+<script type="module">
+function raf() { return new Promise(resolve => requestAnimationFrame(resolve)); }
+
+await raf();
+await raf();
+scroller.scrollTop = 150;
+
+document.documentElement.classList.remove('reftest-wait');
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/reference/anchor-scroll-composited-scrolling-006-ref.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/reference/anchor-scroll-composited-scrolling-006-ref.html
new file mode 100644
index 0000000..92fe187
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/reference/anchor-scroll-composited-scrolling-006-ref.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<style>
+body {
+  margin: 0;
+}
+#scroller {
+  width: 200px;
+  height: 100px;
+  overflow: scroll;
+  will-change: scroll-position;
+}
+#spacer {
+  height: 400px;
+}
+#anchor {
+  width: 100px;
+  height: 100px;
+  anchor-name: --a;
+}
+#overlap {
+  position: absolute;
+  width: 100px;
+  height: 100px;
+  top: 150px;
+  left: 0;
+  z-index: 100;
+  background: green;
+}
+</style>
+
+<div id="overlap"></div>
+<div id="scroller">
+  <div id="spacer"></div>
+  <div id="anchor"></div>
+</div>
+
+<script>
+scroller.scrollTop = 150;
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-attachment-fixed-inline-scrolled-ref.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-attachment-fixed-inline-scrolled-ref.html
new file mode 100644
index 0000000..1767c84
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-attachment-fixed-inline-scrolled-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<style>
+body {
+  /* suppress scrollbars */
+  overflow: hidden;
+}
+#target {
+  background-attachment: fixed;
+  background-image: linear-gradient(green 50%, yellow 50%);
+  font-size: 130px;
+  line-height: 100px;
+}
+</style>
+<span id="target">
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+</span>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-attachment-fixed-inline-scrolled.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-attachment-fixed-inline-scrolled.html
new file mode 100644
index 0000000..746997d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-attachment-fixed-inline-scrolled.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://www.w3.org/TR/css-backgrounds-3/#background-attachment">
+<link rel="match" href="background-attachment-fixed-inline-scrolled-ref.html">
+<meta name="assert" content="Background with background-attachment-fixed on an inline element should be fixed to the viewport">
+<style>
+body {
+  /* suppress scrollbars */
+  overflow: hidden;
+}
+#target {
+  background-attachment: fixed;
+  background-image: linear-gradient(green 50%, yellow 50%);
+  font-size: 130px;
+  line-height: 100px;
+}
+</style>
+<span id="target">
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+</span>
+<script>
+requestAnimationFrame(() => {
+  requestAnimationFrame(() => {
+    scrollTo(0, 300);
+    document.documentElement.classList.remove("reftest-wait");
+  });
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/overflow-clip-017.html b/third_party/blink/web_tests/external/wpt/css/css-break/overflow-clip-017.html
new file mode 100644
index 0000000..1ab3cdd1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/overflow-clip-017.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1432946">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="columns:2; gap:0; column-fill:auto; width:100px; height:100px; background:red;">
+  <div style="height:70px; background:green;"></div>
+  <div style="float:left; break-inside:avoid; width:100%; height:40px; background:green;"></div>
+  <div style="position:relative; display:flow-root; overflow-y:clip; width:100%; height:90px; background:red;">
+    <div style="height:30px; background:green;"></div>
+    <div style="height:10px;"></div>
+    <div style="position:absolute; margin-top:-30px; width:100%;">
+      <div style="height:20px; background:red;"></div>
+      <div style="height:60px; background:green;"></div>
+      <div style="height:20px; background:red;"></div>
+    </div>
+    <div style="height:1000px;"></div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditional-001.html b/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditional-001.html
index 9bdbbcb5..a841f26 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditional-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-cascade/import-conditional-001.html
@@ -16,8 +16,10 @@
   @import "support/test-red.css"
     (max-width: 1px), nonsense;
   div {
+    box-sizing: border-box;
     width: 100px;
     height: 100px;
+    padding: 5px; /* Avoids text antialiasing issues */
     background: red;
   }
   </style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/auto-track-sizing-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/auto-track-sizing-001-ref.html
index 800f87e..81c6d18 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/auto-track-sizing-001-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/auto-track-sizing-001-ref.html
@@ -50,13 +50,13 @@
 </article>
 
 <article class="grid" style="grid-template-columns: auto 100px auto">
-  <div class="subgrid" style="grid-column:2 span 2">
+  <div class="subgrid" style="grid-column:2 / span 2">
     The cat can not be separated from milk
   </div>
 </article>
 
 <article class="grid" style="grid-template-columns: auto 100px auto">
-  <div class="subgrid" style="grid-column:1 span 3">
+  <div class="subgrid" style="grid-column:1 / span 3">
     The cat can not be separated from milk
   </div>
 </article>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/auto-track-sizing-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/auto-track-sizing-001.html
index 0fdb9b0..4a946e6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/auto-track-sizing-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/auto-track-sizing-001.html
@@ -53,13 +53,13 @@
 </article>
 
 <article class="grid" style="grid-template-columns: auto 100px auto">
-  <div class="subgrid" style="grid-column:2 span 2">
+  <div class="subgrid" style="grid-column:2 / span 2">
     The cat can not be separated from milk
   </div>
 </article>
 
 <article class="grid" style="grid-template-columns: auto 100px auto">
-  <div class="subgrid" style="grid-column:1 span 3">
+  <div class="subgrid" style="grid-column:1 / span 3">
     The cat can not be separated from milk
   </div>
 </article>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-001.html.ini
index 485cf09..f4293eb2 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-001.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/subgrid-baseline-001.html.ini
@@ -1,4 +1,2 @@
 [subgrid-baseline-001.html]
-  expected:
-    if (product == "content_shell") and (os == "win") and (port == "win11"): CRASH
-    FAIL
+  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-left-color-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-left-color-001.html.ini
index f044a6b..bf0310aa 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-left-color-001.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-left-color-001.html.ini
@@ -1,3 +1,4 @@
 [kind-of-widget-fallback-input-search-border-left-color-001.html]
   expected:
+    if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
     if (product == "content_shell") and (os == "linux"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-option-arbitrary-content-displayed-ref.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-option-arbitrary-content-displayed-ref.tentative.html
index 3933b93..171829d 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-option-arbitrary-content-displayed-ref.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-option-arbitrary-content-displayed-ref.tentative.html
@@ -4,12 +4,7 @@
 <link rel="stylesheet" href="/fonts/ahem.css">
 
 <selectmenu id="selectMenu0">
-  <div popover slot="listbox" behavior="listbox">
-    <option>
-      option with image displayed
-      <img src="/images/green-256x256.png">
-    </option>
-  </div>
+  <option>option with image displayed</option>
 </selectmenu>
 <div id=fakelistbox>
   option with image displayed
@@ -17,15 +12,16 @@
 </div>
 
 <style>
-  html {
+  html,selectmenu {
     font-family: Ahem;
   }
   #fakelistbox {
     /* Per spec: */
     display: block;
     position: fixed;
-    top: 20px;
+    top: 30px;
     left: 0;
+    font-size: 0.765625em /* 0.875 * 0.875 */;
     /* Per settings in test file: */
     width: fit-content;
     height: fit-content;
@@ -43,6 +39,6 @@
     position: absolute;
     top: 0px;
     left: 0px;
-    height: 20px;
+    height: 30px;
   }
 </style>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-option-arbitrary-content-displayed.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-option-arbitrary-content-displayed.tentative.html
index 0fad1a1..05bc651 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-option-arbitrary-content-displayed.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-option-arbitrary-content-displayed.tentative.html
@@ -9,14 +9,14 @@
 <script src="/resources/testdriver-vendor.js"></script>
 
 <style>
-  html {
+  html,selectmenu {
     font-family: Ahem;
   }
   selectmenu {
     position: absolute;
     top: 0px;
     left: 0px;
-    height: 20px;
+    height: 30px;
   }
 
   [popover] {
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/support/fake-selectmenu.js b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/support/fake-selectmenu.js
index cf3864a..84fe528 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/support/fake-selectmenu.js
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/support/fake-selectmenu.js
@@ -10,17 +10,21 @@
     <style>
     .fake-selectmenu {
       display: inline-block;
+      user-select: none;
+      font-family: sans-serif;
+      font-size: .875em;
     }
 
     .fake-selectmenu-internal-selectmenu-button {
       display: inline-flex;
       align-items: center;
-      background-color: #ffffff;
-      padding: 0 0 0 3px;
-      border: 1px solid #767676;
-      border-radius: 2px;
       cursor: default;
       appearance: none;
+      background-color: Field;
+      color: ButtonText;
+      border: 1px solid ButtonBorder;
+      border-radius: 0.25em;
+      padding: 0.25em;
     }
 
     .fake-selectmenu-internal-selectmenu-button-icon {
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-event-during-parse-expected.txt b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-event-during-parse-expected.txt
deleted file mode 100644
index b9aa872..0000000
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-event-during-parse-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Promise rejection during initial parsing of document assert_array_equals: expected property 0 to be "readystatechange:interactive" but got "unhandledrejection" (expected array ["readystatechange:interactive", "unhandledrejection", "readystatechange:complete"] got ["unhandledrejection", "readystatechange:interactive", "readystatechange:complete"])
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/videoFrame-serialization.crossAgentCluster.https.html b/third_party/blink/web_tests/external/wpt/webcodecs/videoFrame-serialization.crossAgentCluster.https.html
index cb02ad4b..8fe7cf44 100644
--- a/third_party/blink/web_tests/external/wpt/webcodecs/videoFrame-serialization.crossAgentCluster.https.html
+++ b/third_party/blink/web_tests/external/wpt/webcodecs/videoFrame-serialization.crossAgentCluster.https.html
@@ -208,11 +208,11 @@
   });
 }
 
-function canSerializeVideoFrame(target, vf, transfer) {
+function canSerializeVideoFrame(target, vf) {
   return canPostVideoFrame(target, vf, false);
 };
 
-function canTransferVideoFrame(target, vf, transfer) {
+function canTransferVideoFrame(target, vf) {
   return canPostVideoFrame(target, vf, true);
 };
 
diff --git a/third_party/blink/web_tests/external/wpt/webtransport/streams-echo.https.any.js b/third_party/blink/web_tests/external/wpt/webtransport/streams-echo.https.any.js
index 18ebe12..3b402d0 100644
--- a/third_party/blink/web_tests/external/wpt/webtransport/streams-echo.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webtransport/streams-echo.https.any.js
@@ -213,3 +213,21 @@
   assert_equals(len, 3*bytes.length);
 }, 'Transfer large chunks of data on a unidirectional stream');
 
+promise_test(async t => {
+  // Establish a WebTransport session.
+  const wt = new WebTransport(webtransport_url('echo.py'));
+  await wt.ready;
+
+  // Create a bidirectional stream.
+  const bidi_stream = await wt.createBidirectionalStream();
+
+  // Close the writable end with no data at all.
+  const writer = bidi_stream.writable.getWriter();
+  writer.close();
+
+  // Read the data on the readable end.
+  const chunks = await read_stream(bidi_stream.readable);
+  assert_equals(chunks.length, 0);
+
+  await bidi_stream.readable.closed;
+}, 'Closing the stream with no data still resolves the read request');
diff --git a/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window.js.ini b/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window.js.ini
index 7e64244..74fe81a 100644
--- a/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window.js.ini
+++ b/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window.js.ini
@@ -34,59 +34,11 @@
   [XRPermissionStatus interface: existence and properties of interface prototype object's @@unscopables property]
     expected: FAIL
 
-  [XRPose interface: attribute angularVelocity]
-    expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
-
-  [XRPose interface: attribute linearVelocity]
-    expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
-
-  [XRSession interface: attribute frameRate]
-    expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
-
   [XRSession interface: attribute isSystemKeyboardSupported]
-    expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): PASS
-      FAIL
-
-  [XRSession interface: attribute onframeratechange]
-    expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
-
-  [XRSession interface: attribute supportedFrameRates]
-    expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
-
-  [XRSession interface: calling updateTargetFrameRate(float) on xrSession with too few arguments must throw TypeError]
-    expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
-
-  [XRSession interface: operation updateTargetFrameRate(float)]
-    expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
-
-  [XRSession interface: xrSession must inherit property "frameRate" with the proper type]
-    expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
+    expected: FAIL
 
   [XRSession interface: xrSession must inherit property "isSystemKeyboardSupported" with the proper type]
-    expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): PASS
-      FAIL
-
-  [XRSession interface: xrSession must inherit property "onframeratechange" with the proper type]
-    expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
-
-  [XRSession interface: xrSession must inherit property "supportedFrameRates" with the proper type]
-    expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
-
-  [XRSession interface: xrSession must inherit property "updateTargetFrameRate(float)" with the proper type]
-    expected:
-      if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL
+    expected: FAIL
 
   [XRWebGLLayer interface: attribute fixedFoveation]
     expected: FAIL
diff --git a/third_party/blink/web_tests/fast/backgrounds/repeat/negative-offset-repeat-transformed.html b/third_party/blink/web_tests/fast/backgrounds/repeat/negative-offset-repeat-transformed.html
index 6b85e18..9c457cb 100644
--- a/third_party/blink/web_tests/fast/backgrounds/repeat/negative-offset-repeat-transformed.html
+++ b/third_party/blink/web_tests/fast/backgrounds/repeat/negative-offset-repeat-transformed.html
@@ -1,6 +1,6 @@
 <!DOCTYPE HTML>
 <html>
-    <meta name="fuzzy" content="maxDifference=0-4;totalPixels=0-4">
+    <meta name="fuzzy" content="maxDifference=0-48;totalPixels=0-3381">
     <style type="text/css">
     body { overflow:hidden; }
 
@@ -85,7 +85,7 @@
     <div class="positive s300" style="background-repeat: repeat-x"></div>
     <div class="positive s250" style="background-repeat: repeat-x"></div>
     <div class="positive s200" style="background-repeat: repeat-x"></div>
-    
+
     <p style="position:absolute;height:5000px"></p>
     <table style="clear:both; transform: translate(650px, -150px) rotate(45deg); -webkit-transform-origin: 100% 0" border=5><tr><td>
     <div class="negative s300" style="background-repeat: no-repeat;"></div>
diff --git a/third_party/blink/web_tests/http/tests/images/document-policy-oversized-images.php b/third_party/blink/web_tests/http/tests/images/document-policy-oversized-images.php
index 471abd0a..e1e4167 100644
--- a/third_party/blink/web_tests/http/tests/images/document-policy-oversized-images.php
+++ b/third_party/blink/web_tests/http/tests/images/document-policy-oversized-images.php
@@ -2,6 +2,7 @@
 header("Document-Policy: oversized-images=2.0");
 ?>
 <!DOCTYPE html>
+<meta name="fuzzy" content="maxDifference=0-6;totalPixels=0-17">
 
 <head>
   <base href="resources/">
@@ -28,4 +29,4 @@
     <img src="green-256x256.jpg?id=7" style="height: 1cm; width: 1cm">
     <img src="green-256x256.jpg?id=8" style="height: 1cm; width: 1cm; border-radius: 5px; border: 1px solid blue;">
   </div>
-</body>
\ No newline at end of file
+</body>
diff --git a/third_party/blink/web_tests/http/tests/media/video-buffered-range-contains-currentTime.html b/third_party/blink/web_tests/http/tests/media/video-buffered-range-contains-currentTime.html
index 8bbcd66..a1f52a2 100644
--- a/third_party/blink/web_tests/http/tests/media/video-buffered-range-contains-currentTime.html
+++ b/third_party/blink/web_tests/http/tests/media/video-buffered-range-contains-currentTime.html
@@ -1,4 +1,5 @@
 <!DOCTYPE html>
+<meta name="fuzzy" content="maxDifference=0-38;totalPixels=0-152">
 <title>Test that the painted buffered range contains currentTime.</title>
 <script src="../../media-resources/media-file.js"></script>
 <video controls></video>
@@ -26,4 +27,4 @@
 var mediaFile = "../../../media/content/test.oga";
 var type = mimeTypeForExtension(mediaFile.split(".").pop());
 video.src = "http://127.0.0.1:8000/media/video-throttled-load.cgi?name=" + mediaFile + "&throttle=5000&nph=1&type=" + type;
-</script>
\ No newline at end of file
+</script>
diff --git a/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/dynamic-color-scheme-change-expected.png b/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/dynamic-color-scheme-change-expected.png
index aca56e0..ca1569de 100644
--- a/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/dynamic-color-scheme-change-expected.png
+++ b/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/dynamic-color-scheme-change-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/horizontal-scrollbar-basic-expected.png b/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/horizontal-scrollbar-basic-expected.png
index 0c1a9267..6fce538 100644
--- a/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/horizontal-scrollbar-basic-expected.png
+++ b/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/horizontal-scrollbar-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dsf-150/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png b/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dsf-150/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
index 6fa8da9..f8f197e9 100644
--- a/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dsf-150/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
+++ b/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dsf-150/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dsf-200/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png b/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dsf-200/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
index d7e4f4c..fef6e2c 100644
--- a/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dsf-200/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
+++ b/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar-dsf-200/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png b/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
index 97b4310..6f2e7da 100644
--- a/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
+++ b/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png b/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
index fe16af7..3a4d822 100644
--- a/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
+++ b/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar/main/basic-scrollbar-expected.png b/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar/main/basic-scrollbar-expected.png
index 079ae5409e..9c244f0 100644
--- a/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar/main/basic-scrollbar-expected.png
+++ b/third_party/blink/web_tests/platform/win10/virtual/fluent-non-overlay-scrollbar/main/basic-scrollbar-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/abort-signal-remove/README.md b/third_party/blink/web_tests/virtual/abort-signal-remove/README.md
deleted file mode 100644
index a36b139..0000000
--- a/third_party/blink/web_tests/virtual/abort-signal-remove/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-This suite runs external/wpt/eyedropper, external/wpt/idle-detection, and
-external/wpt/web-nfc tests with AbortSignalHandleBasedRemoval disabled to test
-the original code paths with the killswich.
diff --git a/third_party/blink/web_tests/virtual/boost-image-priority/README.md b/third_party/blink/web_tests/virtual/boost-image-priority/README.md
new file mode 100644
index 0000000..6eba7c8
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/boost-image-priority/README.md
@@ -0,0 +1,7 @@
+This virtual suite runs tests with a boosted image priority. The flag
+`BoostImagePriority` will be enabled which boosts the priority of the
+first 5 not-small images to Medium (instead of Low) and updates the
+load scheduler to always allow 1 Medium request to be in-flight in
+tight mode.
+
+Bug: crbug.com/1431169
diff --git a/third_party/blink/web_tests/virtual/boost-image-priority/http/tests/devtools/network/resource-priority-expected.txt b/third_party/blink/web_tests/virtual/boost-image-priority/http/tests/devtools/network/resource-priority-expected.txt
new file mode 100644
index 0000000..f8ad8409
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/boost-image-priority/http/tests/devtools/network/resource-priority-expected.txt
@@ -0,0 +1,41 @@
+Tests resource priorities.
+
+sendSyncScriptRequest
+Request: empty-script.js?sync priority: High
+sendAsyncScriptRequest
+Request: empty-script.js?async priority: Low
+sendModuleScriptRequest
+Request: module1.js priority: High
+Request: module2.js priority: High
+sendScriptRequestPrecededByImage
+Request: slow-script.pl?delay=500&sendScriptRequestPrecededByImage priority: High
+Request: abe.png?precedingScript priority: Medium
+Request: empty-script.js?precededByImage priority: Medium
+sendScriptRequestPrecededByPreloadedImage
+Request: abe.png?preloaded priority: Low
+Request: style.css?precededByPreloadedImage priority: VeryHigh
+sendStyleRequestPrecededByImage
+Request: slow-script.pl?delay=500&sendStyleRequestPrecededByImage priority: High
+Request: abe.png?precedingStyle priority: Medium
+Request: style.css?precededByImage priority: Medium
+sendStyleRequestPrecededByPreloadedImage
+Request: abe.png?preloaded priority: Low
+Request: empty-script.js?precededByPreloadedImage priority: High
+sendXHRSync
+Request: empty.html?xhr-sync priority: VeryHigh
+sendXHRAsync
+Request: empty.html?xhr-async priority: High
+sendImageRequest
+Request: abe.png?image priority: Low
+sendStyleRequest
+Request: style.css?style priority: VeryHigh
+createIFrame
+Request: empty.html?iframe priority: VeryHigh
+sendScriptsFromDocumentWriteAfterImage
+Request: slow-script.pl?delay=500&sendScriptsFromDocumentWriteAfterImage priority: High
+Request: abe.png?precedingDocWrite priority: Medium
+Request: docwrite.js priority: Medium
+Request: empty-script.js?docWritten-1 priority: High
+Request: empty-script.js?docWritten-2 priority: High
+Request: empty-script.js?docWritten-3 priority: High
+
diff --git a/third_party/blink/web_tests/virtual/boost-image-priority/http/tests/inspector-protocol/network/is-same-site-expected.txt b/third_party/blink/web_tests/virtual/boost-image-priority/http/tests/inspector-protocol/network/is-same-site-expected.txt
new file mode 100644
index 0000000..98e4243
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/boost-image-priority/http/tests/inspector-protocol/network/is-same-site-expected.txt
@@ -0,0 +1,132 @@
+Verifies that same site requests are marked as such
+requests[
+    [0] : {
+        headers : {
+            Referer : http://127.0.0.1:8000/inspector-protocol/network/resources/same-site-iframe.html
+            User-Agent : <string>
+            sec-ch-ua : "content_shell";v="999"
+            sec-ch-ua-mobile : ?0
+            sec-ch-ua-platform : "Unknown"
+        }
+        initialPriority : Medium
+        isSameSite : true
+        method : GET
+        mixedContentType : none
+        referrerPolicy : strict-origin-when-cross-origin
+        url : http://127.0.0.1:8000/inspector-protocol/network/resources/relative.png
+    }
+    [1] : {
+        headers : {
+            Referer : http://127.0.0.1:8000/inspector-protocol/network/resources/same-site-root.html
+            User-Agent : <string>
+            sec-ch-ua : "content_shell";v="999"
+            sec-ch-ua-mobile : ?0
+            sec-ch-ua-platform : "Unknown"
+        }
+        initialPriority : Medium
+        isSameSite : true
+        method : GET
+        mixedContentType : none
+        referrerPolicy : strict-origin-when-cross-origin
+        url : http://127.0.0.1:8000/inspector-protocol/network/resources/root-relative-image.png
+    }
+    [2] : {
+        headers : {
+            Referer : http://127.0.0.1:8000/inspector-protocol/network/resources/same-site-root.html
+            Upgrade-Insecure-Requests : 1
+            User-Agent : <string>
+            sec-ch-ua : "content_shell";v="999"
+            sec-ch-ua-mobile : ?0
+            sec-ch-ua-platform : "Unknown"
+        }
+        initialPriority : VeryHigh
+        isSameSite : true
+        method : GET
+        mixedContentType : none
+        referrerPolicy : strict-origin-when-cross-origin
+        url : http://127.0.0.1:8000/inspector-protocol/network/resources/same-site-iframe.html
+    }
+    [3] : {
+        headers : {
+            Upgrade-Insecure-Requests : 1
+            User-Agent : <string>
+            sec-ch-ua : "content_shell";v="999"
+            sec-ch-ua-mobile : ?0
+            sec-ch-ua-platform : "Unknown"
+        }
+        initialPriority : VeryHigh
+        isSameSite : true
+        method : GET
+        mixedContentType : none
+        referrerPolicy : strict-origin-when-cross-origin
+        url : http://127.0.0.1:8000/inspector-protocol/network/resources/same-site-root.html
+    }
+    [4] : {
+        headers : {
+            Referer : http://127.0.0.1:8000/inspector-protocol/network/resources/same-site-iframe.html
+            User-Agent : <string>
+            sec-ch-ua : "content_shell";v="999"
+            sec-ch-ua-mobile : ?0
+            sec-ch-ua-platform : "Unknown"
+        }
+        initialPriority : Medium
+        isSameSite : true
+        method : GET
+        mixedContentType : none
+        referrerPolicy : strict-origin-when-cross-origin
+        url : http://127.0.0.1:8000/root.png
+    }
+    [5] : {
+        headers : {
+            Referer : http://devtools.oopif.test:8000/
+            User-Agent : <string>
+            sec-ch-ua : "content_shell";v="999"
+            sec-ch-ua-mobile : ?0
+            sec-ch-ua-platform : "Unknown"
+        }
+        initialPriority : Medium
+        isSameSite : false
+        method : GET
+        mixedContentType : none
+        referrerPolicy : strict-origin-when-cross-origin
+        url : http://127.0.0.1:8000/root.png
+    }
+    [6] : {
+        headers : {
+            Referer : http://127.0.0.1:8000/
+            User-Agent : <string>
+        }
+        initialPriority : Medium
+        isSameSite : false
+        method : GET
+        mixedContentType : none
+        referrerPolicy : strict-origin-when-cross-origin
+        url : http://devtools.oopif.test:8000/external-image.png
+    }
+    [7] : {
+        headers : {
+            Referer : http://devtools.oopif.test:8000/inspector-protocol/network/resources/same-site-iframe.html
+            User-Agent : <string>
+        }
+        initialPriority : Medium
+        isSameSite : false
+        method : GET
+        mixedContentType : none
+        referrerPolicy : strict-origin-when-cross-origin
+        url : http://devtools.oopif.test:8000/inspector-protocol/network/resources/relative.png
+    }
+    [8] : {
+        headers : {
+            Referer : http://127.0.0.1:8000/
+            Upgrade-Insecure-Requests : 1
+            User-Agent : <string>
+        }
+        initialPriority : VeryHigh
+        isSameSite : false
+        method : GET
+        mixedContentType : none
+        referrerPolicy : strict-origin-when-cross-origin
+        url : http://devtools.oopif.test:8000/inspector-protocol/network/resources/same-site-iframe.html
+    }
+]
+
diff --git a/third_party/blink/web_tests/virtual/boost-image-priority/http/tests/priority-hints/image-initial-load-expected.txt b/third_party/blink/web_tests/virtual/boost-image-priority/http/tests/priority-hints/image-initial-load-expected.txt
new file mode 100644
index 0000000..09271a6
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/boost-image-priority/http/tests/priority-hints/image-initial-load-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS all images must be fetched by the preload scanner
+PASS high fetchpriority on <img> must translate to kHigh resource load priority
+PASS low fetchpriority on <img> must translate to kLow resource load priority
+FAIL auto fetchpriority on <img> must translate to kLow resource load priority assert_equals: expected 1 but got 2
+FAIL invalid fetchpriority on <img> must translate to kLow resource load priority assert_equals: expected 1 but got 2
+FAIL missing fetchpriority on <img> must translate to kLow resource load priority assert_equals: expected 1 but got 2
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/dynamic-color-scheme-change-expected.png b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/dynamic-color-scheme-change-expected.png
index dcc47b6..f2868d1e 100644
--- a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/dynamic-color-scheme-change-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/dynamic-color-scheme-change-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/horizontal-scrollbar-basic-expected.png b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/horizontal-scrollbar-basic-expected.png
index 00df7a5d..19cd2f45 100644
--- a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/horizontal-scrollbar-basic-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/horizontal-scrollbar-basic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-150/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-150/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
index 7d3167f..1161706 100644
--- a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-150/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-150/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-200/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-200/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
index 5ac8cb5..22cd2e8 100644
--- a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-200/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar-dsf-200/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
index a81bb66ca..d5998002 100644
--- a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
index 28b0daa6..7e2185e 100644
--- a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar/main/basic-scrollbar-expected.png b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar/main/basic-scrollbar-expected.png
index 5ae4da6a..9b8df611 100644
--- a/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar/main/basic-scrollbar-expected.png
+++ b/third_party/blink/web_tests/virtual/fluent-non-overlay-scrollbar/main/basic-scrollbar-expected.png
Binary files differ
diff --git a/third_party/d3/OWNERS b/third_party/d3/OWNERS
index 1bef084..31e881c2 100644
--- a/third_party/d3/OWNERS
+++ b/third_party/d3/OWNERS
@@ -1 +1,2 @@
 zentaro@chromium.org
+dpapad@chromium.org
diff --git a/third_party/d3/README.chromium b/third_party/d3/README.chromium
index 88104bc..b374d250 100644
--- a/third_party/d3/README.chromium
+++ b/third_party/d3/README.chromium
@@ -1,10 +1,10 @@
 Name: d3
 Short Name: d3
 URL: https://github.com/d3/d3
-Version: 5.16.0
-CPEPrefix: cpe:/a:d3.js_project:d3.js:5.16.0::~~~node.js~~
-Date: Mon Apr 20 1:58 PM 2020 EDT
-Revision: 7244e45e68af39c519f76667a03039d5b24dd453
+Version: 7.8.4
+CPEPrefix: cpe:/a:d3.js_project:d3.js:7.8.4::~~~node.js~~
+Date: Fri Mar 31 10:43 PM 2023 EDT
+Revision: 37b1960e0af52d12bc7bbea2ed932ea954c36d14
 License: BSD 3-Clause
 License File: src/LICENSE
 Security Critical: Yes
diff --git a/third_party/d3/src/CHANGES.md b/third_party/d3/src/CHANGES.md
deleted file mode 100644
index 64c7595..0000000
--- a/third_party/d3/src/CHANGES.md
+++ /dev/null
@@ -1,1409 +0,0 @@
-# Changes in D3 5.0
-
-[Released March 22, 2018.](https://github.com/d3/d3/releases/tag/v5.0.0)
-
-*This document covers only major changes. For minor and patch changes, please see the [release notes](https://github.com/d3/d3/releases).*
-
-D3 5.0 introduces only a few non-backwards-compatible changes.
-
-D3 now uses [Promises](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Using_promises) instead of asynchronous callbacks to load data. Promises simplify the structure of asynchronous code, especially in modern browsers that support [async and await](https://javascript.info/async-await). (See this [introduction to promises](https://observablehq.com/@observablehq/introduction-to-promises) on [Observable](https://observablehq.com).) For example, to load a CSV file in v4, you might say:
-
-```js
-d3.csv("file.csv", function(error, data) {
-  if (error) throw error;
-  console.log(data);
-});
-```
-
-In v5, using promises:
-
-```js
-d3.csv("file.csv").then(function(data) {
-  console.log(data);
-});
-```
-
-Note that you don’t need to rethrow the error—the promise will reject automatically, and you can *promise*.catch if desired. Using await, the code is even simpler:
-
-```js
-const data = await d3.csv("file.csv");
-console.log(data);
-```
-
-With the adoption of promises, D3 now uses the [Fetch API](https://fetch.spec.whatwg.org/) instead of [XMLHttpRequest](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest): the [d3-request](https://github.com/d3/d3-request) module has been replaced by [d3-fetch](https://github.com/d3/d3-fetch). Fetch supports many powerful new features, such as [streaming responses](https://observablehq.com/@mbostock/streaming-shapefiles). D3 5.0 also deprecates and removes the [d3-queue](https://github.com/d3/d3-queue) module. Use [Promise.all](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) to run a batch of asynchronous tasks in parallel, or a helper library such as [p-queue](https://github.com/sindresorhus/p-queue) to [control concurrency](https://observablehq.com/@mbostock/hello-p-queue).
-
-D3 no longer provides the d3.schemeCategory20* categorical color schemes. These twenty-color schemes were flawed because their grouped design could falsely imply relationships in the data: a shared hue can imply that the encoded data are part of a group (a super-category), while relative lightness can imply order. Instead, D3 now includes [d3-scale-chromatic](https://github.com/d3/d3-scale-chromatic), which implements excellent schemes from ColorBrewer, including [categorical](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#categorical), [diverging](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#diverging), [sequential single-hue](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#sequential-single-hue) and [sequential multi-hue](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#sequential-multi-hue) schemes. These schemes are available in both discrete and continuous variants.
-
-D3 now provides implementations of [marching squares](https://observablehq.com/@d3/contours) and [density estimation](https://observablehq.com/@d3/density-contours) via [d3-contour](https://github.com/d3/d3-contour)! There are two new [d3-selection](https://github.com/d3/d3-selection) methods: [*selection*.clone](https://github.com/d3/d3-selection/blob/master/README.md#selection_clone) for inserting clones of the selected nodes, and [d3.create](https://github.com/d3/d3-selection/blob/master/README.md#create) for creating detached elements. [Geographic projections](https://github.com/d3/d3-geo) now support [*projection*.angle](https://github.com/d3/d3-geo/blob/master/README.md#projection_angle), which has enabled several fantastic new [polyhedral projections](https://github.com/d3/d3-geo-polygon) by Philippe Rivière.
-
-Lastly, D3’s [package.json](https://github.com/d3/d3/blob/master/package.json) no longer pins exact versions of the dependent D3 modules. This fixes an issue with [duplicate installs](https://github.com/d3/d3/issues/3256) of D3 modules.
-
-# Changes in D3 4.0
-
-[Released June 28, 2016.](https://github.com/d3/d3/releases/tag/v4.0.0)
-
-D3 4.0 is modular. Instead of one library, D3 is now [many small libraries](#table-of-contents) that are designed to work together. You can pick and choose which parts to use as you see fit. Each library is maintained in its own repository, allowing decentralized ownership and independent release cycles. The default bundle combines about thirty of these microlibraries.
-
-```html
-<script src="https://d3js.org/d3.v4.js"></script>
-```
-
-As before, you can load optional plugins on top of the default bundle, such as [ColorBrewer scales](https://github.com/d3/d3-scale-chromatic):
-
-```html
-<script src="https://d3js.org/d3.v4.js"></script>
-<script src="https://d3js.org/d3-scale-chromatic.v0.3.js"></script>
-```
-
-You are not required to use the default bundle! If you’re just using [d3-selection](https://github.com/d3/d3-selection), use it as a standalone library. Like the default bundle, you can load D3 microlibraries using vanilla script tags or RequireJS (great for HTTP/2!):
-
-```html
-<script src="https://d3js.org/d3-selection.v1.js"></script>
-```
-
-You can also `cat` D3 microlibraries into a custom bundle, or use tools such as [Webpack](https://webpack.github.io/) and [Rollup](http://rollupjs.org/) to create [optimized bundles](https://bl.ocks.org/mbostock/bb09af4c39c79cffcde4). Custom bundles are great for applications that use a subset of D3’s features; for example, a React chart library might use D3 for scales and shapes, and React to manipulate the DOM. The D3 microlibraries are written as [ES6 modules](http://www.2ality.com/2014/09/es6-modules-final.html), and Rollup lets you pick at the symbol level to produce smaller bundles.
-
-Small files are nice, but modularity is also about making D3 more *fun*. Microlibraries are easier to understand, develop and test. They make it easier for new people to get involved and contribute. They reduce the distinction between a “core module” and a “plugin”, and increase the pace of development in D3 features.
-
-If you don’t care about modularity, you can mostly ignore this change and keep using the default bundle. However, there is one unavoidable consequence of adopting ES6 modules: every symbol in D3 4.0 now shares a flat namespace rather than the nested one of D3 3.x. For example, d3.scale.linear is now d3.scaleLinear, and d3.layout.treemap is now d3.treemap. The adoption of ES6 modules also means that D3 is now written exclusively in [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode) and has better readability. And there have been many other significant improvements to D3’s features! (Nearly all of the code from D3 3.x has been rewritten.) These changes are covered below.
-
-### Other Global Changes
-
-The default [UMD bundle](https://github.com/umdjs/umd) is now [anonymous](https://github.com/requirejs/requirejs/wiki/Updating-existing-libraries#register-as-an-anonymous-module-). No `d3` global is exported if AMD or CommonJS is detected. In a vanilla environment, the D3 microlibraries share the `d3` global, even if you load them independently; thus, code you write is the same whether or not you use the default bundle. (See [Let’s Make a (D3) Plugin](https://bost.ocks.org/mike/d3-plugin/) for more.) The generated bundle is no longer stored in the Git repository; Bower has been repointed to [d3-bower](https://github.com/mbostock-bower/d3-bower), and you can find the generated files on [npm](https://unpkg.com/d3) or attached to the [latest release](https://github.com/d3/d3/releases/latest). The non-minified default bundle is no longer mangled, making it more readable and preserving inline comments.
-
-To the consternation of some users, 3.x employed Unicode variable names such as λ, φ, τ and π for a concise representation of mathematical operations. A downside of this approach was that a SyntaxError would occur if you loaded the non-minified D3 using ISO-8859-1 instead of UTF-8. 3.x also used Unicode string literals, such as the SI-prefix µ for 1e-6. 4.0 uses only ASCII variable names and ASCII string literals (see [rollup-plugin-ascii](https://github.com/mbostock/rollup-plugin-ascii)), avoiding encoding problems.
-
-### Table of Contents
-
-* [Arrays](#arrays-d3-array)
-* [Axes](#axes-d3-axis)
-* [Brushes](#brushes-d3-brush)
-* [Chords](#chords-d3-chord)
-* [Collections](#collections-d3-collection)
-* [Colors](#colors-d3-color)
-* [Dispatches](#dispatches-d3-dispatch)
-* [Dragging](#dragging-d3-drag)
-* [Delimiter-Separated Values](#delimiter-separated-values-d3-dsv)
-* [Easings](#easings-d3-ease)
-* [Forces](#forces-d3-force)
-* [Number Formats](#number-formats-d3-format)
-* [Geographies](#geographies-d3-geo)
-* [Hierarchies](#hierarchies-d3-hierarchy)
-* [Internals](#internals)
-* [Interpolators](#interpolators-d3-interpolate)
-* [Paths](#paths-d3-path)
-* [Polygons](#polygons-d3-polygon)
-* [Quadtrees](#quadtrees-d3-quadtree)
-* [Queues](#queues-d3-queue)
-* [Random Numbers](#random-numbers-d3-random)
-* [Requests](#requests-d3-request)
-* [Scales](#scales-d3-scale)
-* [Selections](#selections-d3-selection)
-* [Shapes](#shapes-d3-shape)
-* [Time Formats](#time-formats-d3-time-format)
-* [Time Intervals](#time-intervals-d3-time)
-* [Timers](#timers-d3-timer)
-* [Transitions](#transitions-d3-transition)
-* [Voronoi Diagrams](#voronoi-diagrams-d3-voronoi)
-* [Zooming](#zooming-d3-zoom)
-
-## [Arrays (d3-array)](https://github.com/d3/d3-array/blob/master/README.md)
-
-The new [d3.scan](https://github.com/d3/d3-array/blob/master/README.md#scan) method performs a linear scan of an array, returning the index of the least element according to the specified comparator. This is similar to [d3.min](https://github.com/d3/d3-array/blob/master/README.md#min) and [d3.max](https://github.com/d3/d3-array/blob/master/README.md#max), except you can use it to find the position of an extreme element, rather than just calculate an extreme value.
-
-```js
-var data = [
-  {name: "Alice", value: 2},
-  {name: "Bob", value: 3},
-  {name: "Carol", value: 1},
-  {name: "Dwayne", value: 5}
-];
-
-var i = d3.scan(data, function(a, b) { return a.value - b.value; }); // 2
-data[i]; // {name: "Carol", value: 1}
-```
-
-The new [d3.ticks](https://github.com/d3/d3-array/blob/master/README.md#ticks) and [d3.tickStep](https://github.com/d3/d3-array/blob/master/README.md#tickStep) methods are useful for generating human-readable numeric ticks. These methods are a low-level alternative to [*continuous*.ticks](https://github.com/d3/d3-scale/blob/master/README.md#continuous_ticks) from [d3-scale](https://github.com/d3/d3-scale). The new implementation is also more accurate, returning the optimal number of ticks as measured by relative error.
-
-```js
-var ticks = d3.ticks(0, 10, 5); // [0, 2, 4, 6, 8, 10]
-```
-
-The [d3.range](https://github.com/d3/d3-array/blob/master/README.md#range) method no longer makes an elaborate attempt to avoid floating-point error when *step* is not an integer. The returned values are strictly defined as *start* + *i* \* *step*, where *i* is an integer. (Learn more about [floating point math](http://0.30000000000000004.com/).) d3.range returns the empty array for infinite ranges, rather than throwing an error.
-
-The method signature for optional accessors has been changed to be more consistent with array methods such as [*array*.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach): the accessor is passed the current element (*d*), the index (*i*), and the array (*data*), with *this* as undefined. This affects [d3.min](https://github.com/d3/d3-array/blob/master/README.md#min), [d3.max](https://github.com/d3/d3-array/blob/master/README.md#max), [d3.extent](https://github.com/d3/d3-array/blob/master/README.md#extent), [d3.sum](https://github.com/d3/d3-array/blob/master/README.md#sum), [d3.mean](https://github.com/d3/d3-array/blob/master/README.md#mean), [d3.median](https://github.com/d3/d3-array/blob/master/README.md#median), [d3.quantile](https://github.com/d3/d3-array/blob/master/README.md#quantile), [d3.variance](https://github.com/d3/d3-array/blob/master/README.md#variance) and [d3.deviation](https://github.com/d3/d3-array/blob/master/README.md#deviation). The [d3.quantile](https://github.com/d3/d3-array/blob/master/README.md#quantile) method previously did not take an accessor. Some methods with optional arguments now treat those arguments as missing if they are null or undefined, rather than strictly checking arguments.length.
-
-The new [d3.histogram](https://github.com/d3/d3-array/blob/master/README.md#histograms) API replaces d3.layout.histogram. Rather than exposing *bin*.x and *bin*.dx on each returned bin, the histogram exposes *bin*.x0 and *bin*.x1, guaranteeing that *bin*.x0 is exactly equal to *bin*.x1 on the preceding bin. The “frequency” and “probability” modes are no longer supported; each bin is simply an array of elements from the input data, so *bin*.length is equal to D3 3.x’s *bin*.y in frequency mode. To compute a probability distribution, divide the number of elements in each bin by the total number of elements.
-
-The *histogram*.range method has been renamed [*histogram*.domain](https://github.com/d3/d3-array/blob/master/README.md#histogram_domain) for consistency with scales. The *histogram*.bins method has been renamed [*histogram*.thresholds](https://github.com/d3/d3-array/blob/master/README.md#histogram_thresholds), and no longer accepts an upper value: *n* thresholds will produce *n* + 1 bins. If you specify a desired number of bins rather than thresholds, d3.histogram now uses [d3.ticks](https://github.com/d3/d3-array/blob/master/README.md#ticks) to compute nice bin thresholds. In addition to the default Sturges’ formula, D3 now implements the [Freedman-Diaconis rule](https://github.com/d3/d3-array/blob/master/README.md#thresholdFreedmanDiaconis) and [Scott’s normal reference rule](https://github.com/d3/d3-array/blob/master/README.md#thresholdScott).
-
-## [Axes (d3-axis)](https://github.com/d3/d3-axis/blob/master/README.md)
-
-To render axes properly in D3 3.x, you needed to style them:
-
-```html
-<style>
-
-.axis path,
-.axis line {
-  fill: none;
-  stroke: #000;
-  shape-rendering: crispEdges;
-}
-
-.axis text {
-  font: 10px sans-serif;
-}
-
-</style>
-<script>
-
-d3.select(".axis")
-    .call(d3.svg.axis()
-        .scale(x)
-        .orient("bottom"));
-
-</script>
-```
-
-If you didn’t, you saw this:
-
-<img src="https://raw.githubusercontent.com/d3/d3/master/img/axis-v3.png" width="100%" height="105">
-
-D3 4.0 provides default styles and shorter syntax. In place of d3.svg.axis and *axis*.orient, D3 4.0 now provides four constructors for each orientation: [d3.axisTop](https://github.com/d3/d3-axis/blob/master/README.md#axisTop), [d3.axisRight](https://github.com/d3/d3-axis/blob/master/README.md#axisRight), [d3.axisBottom](https://github.com/d3/d3-axis/blob/master/README.md#axisBottom), [d3.axisLeft](https://github.com/d3/d3-axis/blob/master/README.md#axisLeft). These constructors accept a scale, so you can reduce all of the above to:
-
-```html
-<script>
-
-d3.select(".axis")
-    .call(d3.axisBottom(x));
-
-</script>
-```
-
-And get this:
-
-<img src="https://raw.githubusercontent.com/d3/d3/master/img/axis-v4.png" width="100%" height="105">
-
-As before, you can customize the axis appearance either by applying stylesheets or by modifying the axis elements. The default appearance has been changed slightly to offset the axis by a half-pixel;  this fixes a crisp-edges rendering issue on Safari where the axis would be drawn two-pixels thick.
-
-There’s now an [*axis*.tickArguments](https://github.com/d3/d3-axis/blob/master/README.md#axis_tickArguments) method, as an alternative to [*axis*.ticks](https://github.com/d3/d3-axis/blob/master/README.md#axis_ticks) that also allows the axis tick arguments to be inspected. The [*axis*.tickSize](https://github.com/d3/d3-axis/blob/master/README.md#axis_tickSize) method has been changed to only allow a single argument when setting the tick size. The *axis*.innerTickSize and *axis*.outerTickSize methods have been renamed [*axis*.tickSizeInner](https://github.com/d3/d3-axis/blob/master/README.md#axis_tickSizeInner) and [*axis*.tickSizeOuter](https://github.com/d3/d3-axis/blob/master/README.md#axis_tickSizeOuter), respectively.
-
-## [Brushes (d3-brush)](https://github.com/d3/d3-brush/blob/master/README.md)
-
-Replacing d3.svg.brush, there are now three classes of brush for brushing along the *x*-dimension, the *y*-dimension, or both: [d3.brushX](https://github.com/d3/d3-brush/blob/master/README.md#brushX), [d3.brushY](https://github.com/d3/d3-brush/blob/master/README.md#brushY), [d3.brush](https://github.com/d3/d3-brush/blob/master/README.md#brush). Brushes are no longer dependent on [scales](#scales-d3-scale); instead, each brush defines a selection in screen coordinates. This selection can be [inverted](https://github.com/d3/d3-scale/blob/master/README.md#continuous_invert) if you want to compute the corresponding data domain. And rather than rely on the scales’ ranges to determine the brushable area, there is now a [*brush*.extent](https://github.com/d3/d3-brush/blob/master/README.md#brush_extent) method for setting it. If you do not set the brush extent, it defaults to the full extent of the owner SVG element. The *brush*.clamp method has also been eliminated; brushing is always restricted to the brushable area defined by the brush extent.
-
-Brushes no longer store the active brush selection (*i.e.*, the highlighted region; the brush’s position) internally. The brush’s position is now stored on any elements to which the brush has been applied. The brush’s position is available as *event*.selection within a brush event or by calling [d3.brushSelection](https://github.com/d3/d3-brush/blob/master/README.md#brushSelection) on a given *element*. To move the brush programmatically, use [*brush*.move](https://github.com/d3/d3-brush/blob/master/README.md#brush_move) with a given [selection](#selections-d3-selection) or [transition](#transitions-d3-transition); see the [brush snapping example](https://bl.ocks.org/mbostock/6232537). The *brush*.event method has been removed.
-
-Brush interaction has been improved. By default, brushes now ignore right-clicks intended for the context menu; you can change this behavior using [*brush*.filter](https://github.com/d3/d3-brush/blob/master/README.md#brush_filter). Brushes also ignore emulated mouse events on iOS. Holding down SHIFT (⇧) while brushing locks the *x*- or *y*-position of the brush. Holding down META (⌘) while clicking and dragging starts a new selection, rather than translating the existing selection.
-
-The default appearance of the brush has also been improved and slightly simplified. Previously it was necessary to apply styles to the brush to give it a reasonable appearance, such as:
-
-```css
-.brush .extent {
-  stroke: #fff;
-  fill-opacity: .125;
-  shape-rendering: crispEdges;
-}
-```
-
-These styles are now applied by default as attributes; if you want to customize the brush appearance, you can still apply external styles or modify the brush elements. (D3 4.0 features a similar improvement to [axes](#axes-d3-axis).) A new [*brush*.handleSize](https://github.com/d3/d3-brush/blob/master/README.md#brush_handleSize) method lets you override the brush handle size; it defaults to six pixels.
-
-The brush now consumes handled events, making it easier to combine with other interactive behaviors such as [dragging](#dragging-d3-drag) and [zooming](#zooming-d3-zoom). The *brushstart* and *brushend* events have been renamed to *start* and *end*, respectively. The brush event no longer reports a *event*.mode to distinguish between resizing and dragging the brush.
-
-## [Chords (d3-chord)](https://github.com/d3/d3-chord/blob/master/README.md)
-
-Pursuant to the great namespace flattening:
-
-* d3.layout.chord ↦ [d3.chord](https://github.com/d3/d3-chord/blob/master/README.md#chord)
-* d3.svg.chord ↦ [d3.ribbon](https://github.com/d3/d3-chord/blob/master/README.md#ribbon)
-
-For consistency with [*arc*.padAngle](https://github.com/d3/d3-shape/blob/master/README.md#arc_padAngle), *chord*.padding has also been renamed to [*ribbon*.padAngle](https://github.com/d3/d3-chord/blob/master/README.md#ribbon_padAngle). A new [*ribbon*.context](https://github.com/d3/d3-chord/blob/master/README.md#ribbon_context) method lets you render chord diagrams to Canvas! See also [d3-path](#paths-d3-path).
-
-## [Collections (d3-collection)](https://github.com/d3/d3-collection/blob/master/README.md)
-
-The [d3.set](https://github.com/d3/d3-collection/blob/master/README.md#set) constructor now accepts an existing set for making a copy. If you pass an array to d3.set, you can also pass a value accessor. This accessor takes the standard arguments: the current element (*d*), the index (*i*), and the array (*data*), with *this* undefined. For example:
-
-```js
-var yields = [
-  {yield: 22.13333, variety: "Manchuria",        year: 1932, site: "Grand Rapids"},
-  {yield: 26.76667, variety: "Peatland",         year: 1932, site: "Grand Rapids"},
-  {yield: 28.10000, variety: "No. 462",          year: 1931, site: "Duluth"},
-  {yield: 38.50000, variety: "Svansota",         year: 1932, site: "Waseca"},
-  {yield: 40.46667, variety: "Svansota",         year: 1931, site: "Crookston"},
-  {yield: 36.03333, variety: "Peatland",         year: 1932, site: "Waseca"},
-  {yield: 34.46667, variety: "Wisconsin No. 38", year: 1931, site: "Grand Rapids"}
-];
-
-var sites = d3.set(yields, function(d) { return d.site; }); // Grand Rapids, Duluth, Waseca, Crookston
-```
-
-The [d3.map](https://github.com/d3/d3-collection/blob/master/README.md#map) constructor also follows the standard array accessor argument pattern.
-
-The *map*.forEach and *set*.forEach methods have been renamed to [*map*.each](https://github.com/d3/d3-collection/blob/master/README.md#map_each) and [*set*.each](https://github.com/d3/d3-collection/blob/master/README.md#set_each) respectively. The order of arguments for *map*.each has also been changed to *value*, *key* and *map*, while the order of arguments for *set*.each is now *value*, *value* and *set*. This is closer to ES6 [*map*.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/forEach) and [*set*.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/forEach). Also like ES6 Map and Set, *map*.set and *set*.add now return the current collection (rather than the added value) to facilitate method chaining. New [*map*.clear](https://github.com/d3/d3-collection/blob/master/README.md#map_clear) and [*set*.clear](https://github.com/d3/d3-collection/blob/master/README.md#set_clear) methods can be used to empty collections.
-
-The [*nest*.map](https://github.com/d3/d3-collection/blob/master/README.md#nest_map) method now always returns a d3.map instance. For a plain object, use [*nest*.object](https://github.com/d3/d3-collection/blob/master/README.md#nest_object) instead. When used in conjunction with [*nest*.rollup](https://github.com/d3/d3-collection/blob/master/README.md#nest_rollup), [*nest*.entries](https://github.com/d3/d3-collection/blob/master/README.md#nest_entries) now returns {key, value} objects for the leaf entries, instead of {key, values}. This makes *nest*.rollup easier to use in conjunction with [hierarchies](#hierarchies-d3-hierarchy), as in this [Nest Treemap example](https://bl.ocks.org/mbostock/2838bf53e0e65f369f476afd653663a2).
-
-## [Colors (d3-color)](https://github.com/d3/d3-color/blob/master/README.md)
-
-All colors now have opacity exposed as *color*.opacity, which is a number in [0, 1]. You can pass an optional opacity argument to the color space constructors [d3.rgb](https://github.com/d3/d3-color/blob/master/README.md#rgb), [d3.hsl](https://github.com/d3/d3-color/blob/master/README.md#hsl), [d3.lab](https://github.com/d3/d3-color/blob/master/README.md#lab), [d3.hcl](https://github.com/d3/d3-color/blob/master/README.md#hcl) or [d3.cubehelix](https://github.com/d3/d3-color/blob/master/README.md#cubehelix).
-
-You can now parse rgba(…) and hsla(…) CSS color specifiers or the string “transparent” using [d3.color](https://github.com/d3/d3-color/blob/master/README.md#color). The “transparent” color is defined as an RGB color with zero opacity and undefined red, green and blue channels; this differs slightly from CSS which defines it as transparent black, but is useful for simplifying color interpolation logic where either the starting or ending color has undefined channels. The [*color*.toString](https://github.com/d3/d3-color/blob/master/README.md#color_toString) method now likewise returns an rgb(…) or rgba(…) string with integer channel values, not the hexadecimal RGB format, consistent with CSS computed values. This improves performance by short-circuiting transitions when the element’s starting style matches its ending style.
-
-The new [d3.color](https://github.com/d3/d3-color/blob/master/README.md#color) method is the primary method for parsing colors: it returns a d3.color instance in the appropriate color space, or null if the CSS color specifier is invalid. For example:
-
-```js
-var red = d3.color("hsl(0, 80%, 50%)"); // {h: 0, l: 0.5, s: 0.8, opacity: 1}
-```
-
-The parsing implementation is now more robust. For example, you can no longer mix integers and percentages in rgb(…), and it correctly handles whitespace, decimal points, number signs, and other edge cases. The color space constructors d3.rgb, d3.hsl, d3.lab, d3.hcl and d3.cubehelix now always return a copy of the input color, converted to the corresponding color space. While [*color*.rgb](https://github.com/d3/d3-color/blob/master/README.md#color_rgb) remains, *rgb*.hsl has been removed; use d3.hsl to convert a color to the RGB color space.
-
-The RGB color space no longer greedily quantizes and clamps channel values when creating colors, improving accuracy in color space conversion. Quantization and clamping now occurs in *color*.toString when formatting a color for display. You can use the new [*color*.displayable](https://github.com/d3/d3-color/blob/master/README.md#color_displayable) to test whether a color is [out-of-gamut](https://en.wikipedia.org/wiki/Gamut).
-
-The [*rgb*.brighter](https://github.com/d3/d3-color/blob/master/README.md#rgb_brighter) method no longer special-cases black. This is a multiplicative operator, defining a new color *r*′, *g*′, *b*′ where *r*′ = *r* × *pow*(0.7, *k*), *g*′ = *g* × *pow*(0.7, *k*) and *b*′ = *b* × *pow*(0.7, *k*); a brighter black is still black.
-
-There’s a new [d3.cubehelix](https://github.com/d3/d3-color/blob/master/README.md#cubehelix) color space, generalizing Dave Green’s color scheme! (See also [d3.interpolateCubehelixDefault](https://github.com/d3/d3-scale/blob/master/README.md#interpolateCubehelixDefault) from [d3-scale](#scales-d3-scale).) You can continue to define your own custom color spaces, too; see [d3-hsv](https://github.com/d3/d3-hsv) for an example.
-
-## [Dispatches (d3-dispatch)](https://github.com/d3/d3-dispatch/blob/master/README.md)
-
-Rather than decorating the *dispatch* object with each event type, the dispatch object now exposes generic [*dispatch*.call](https://github.com/d3/d3-dispatch/blob/master/README.md#dispatch_call) and [*dispatch*.apply](https://github.com/d3/d3-dispatch/blob/master/README.md#dispatch_apply) methods which take the *type* string as the first argument. For example, in D3 3.x, you might say:
-
-```js
-dispatcher.foo.call(that, "Hello, Foo!");
-```
-
-To dispatch a *foo* event in D3 4.0, you’d say:
-
-```js
-dispatcher.call("foo", that, "Hello, Foo!");
-```
-
-The [*dispatch*.on](https://github.com/d3/d3-dispatch/blob/master/README.md#dispatch_on) method now accepts multiple typenames, allowing you to add or remove listeners for multiple events simultaneously. For example, to send both *foo* and *bar* events to the same listener:
-
-```js
-dispatcher.on("foo bar", function(message) {
-  console.log(message);
-});
-```
-
-This matches the new behavior of [*selection*.on](https://github.com/d3/d3-selection/blob/master/README.md#selection_on) in [d3-selection](#selections-d3-selection). The *dispatch*.on method now validates that the specifier *listener* is a function, rather than throwing an error in the future.
-
-The new implementation d3.dispatch is faster, using fewer closures to improve performance. There’s also a new [*dispatch*.copy](https://github.com/d3/d3-dispatch/blob/master/README.md#dispatch_copy) method for making a copy of a dispatcher; this is used by [d3-transition](#transitions-d3-transition) to improve the performance of transitions in the common case where all elements in a transition have the same transition event listeners.
-
-## [Dragging (d3-drag)](https://github.com/d3/d3-drag/blob/master/README.md)
-
-The drag behavior d3.behavior.drag has been renamed to d3.drag. The *drag*.origin method has been replaced by [*drag*.subject](https://github.com/d3/d3-drag/blob/master/README.md#drag_subject), which allows you to define the thing being dragged at the start of a drag gesture. This is particularly useful with Canvas, where draggable objects typically share a Canvas element (as opposed to SVG, where draggable objects typically have distinct DOM elements); see the [circle dragging example](https://bl.ocks.org/mbostock/444757cc9f0fde320a5f469cd36860f4).
-
-A new [*drag*.container](https://github.com/d3/d3-drag/blob/master/README.md#drag_container) method lets you override the parent element that defines the drag gesture coordinate system. This defaults to the parent node of the element to which the drag behavior was applied. For dragging on Canvas elements, you probably want to use the Canvas element as the container.
-
-[Drag events](https://github.com/d3/d3-drag/blob/master/README.md#drag-events) now expose an [*event*.on](https://github.com/d3/d3-drag/blob/master/README.md#event_on) method for registering temporary listeners for duration of the current drag gesture; these listeners can capture state for the current gesture, such as the thing being dragged. A new *event*.active property lets you detect whether multiple (multitouch) drag gestures are active concurrently. The *dragstart* and *dragend* events have been renamed to *start* and *end*. By default, drag behaviors now ignore right-clicks intended for the context menu; use [*drag*.filter](https://github.com/d3/d3-drag/blob/master/README.md#drag_filter) to control which events are ignored. The drag behavior also ignores emulated mouse events on iOS. The drag behavior now consumes handled events, making it easier to combine with other interactive behaviors such as [zooming](#zooming-d3-zoom).
-
-The new [d3.dragEnable](https://github.com/d3/d3-drag/blob/master/README.md#dragEnable) and [d3.dragDisable](https://github.com/d3/d3-drag/blob/master/README.md#dragDisable) methods provide a low-level API for implementing drag gestures across browsers and devices. These methods are also used by other D3 components, such as the [brush](#brushes-d3-brush).
-
-## [Delimiter-Separated Values (d3-dsv)](https://github.com/d3/d3-dsv/blob/master/README.md)
-
-Pursuant to the great namespace flattening, various CSV and TSV methods have new names:
-
-* d3.csv.parse ↦ [d3.csvParse](https://github.com/d3/d3-dsv/blob/master/README.md#csvParse)
-* d3.csv.parseRows ↦ [d3.csvParseRows](https://github.com/d3/d3-dsv/blob/master/README.md#csvParseRows)
-* d3.csv.format ↦ [d3.csvFormat](https://github.com/d3/d3-dsv/blob/master/README.md#csvFormat)
-* d3.csv.formatRows ↦ [d3.csvFormatRows](https://github.com/d3/d3-dsv/blob/master/README.md#csvFormatRows)
-* d3.tsv.parse ↦ [d3.tsvParse](https://github.com/d3/d3-dsv/blob/master/README.md#tsvParse)
-* d3.tsv.parseRows ↦ [d3.tsvParseRows](https://github.com/d3/d3-dsv/blob/master/README.md#tsvParseRows)
-* d3.tsv.format ↦ [d3.tsvFormat](https://github.com/d3/d3-dsv/blob/master/README.md#tsvFormat)
-* d3.tsv.formatRows ↦ [d3.tsvFormatRows](https://github.com/d3/d3-dsv/blob/master/README.md#tsvFormatRows)
-
-The [d3.csv](https://github.com/d3/d3-request/blob/master/README.md#csv) and [d3.tsv](https://github.com/d3/d3-request/blob/master/README.md#tsv) methods for loading files of the corresponding formats have not been renamed, however! Those are defined in [d3-request](#requests-d3-request).There’s no longer a d3.dsv method, which served the triple purpose of defining a DSV formatter, a DSV parser and a DSV requestor; instead, there’s just [d3.dsvFormat](https://github.com/d3/d3-dsv/blob/master/README.md#dsvFormat) which you can use to define a DSV formatter and parser. You can use [*request*.response](https://github.com/d3/d3-request/blob/master/README.md#request_response) to make a request and then parse the response body, or just use [d3.text](https://github.com/d3/d3-request/blob/master/README.md#text).
-
-The [*dsv*.parse](https://github.com/d3/d3-dsv/blob/master/README.md#dsv_parse) method now exposes the column names and their input order as *data*.columns. For example:
-
-```js
-d3.csv("cars.csv", function(error, data) {
-  if (error) throw error;
-  console.log(data.columns); // ["Year", "Make", "Model", "Length"]
-});
-```
-
-You can likewise pass an optional array of column names to [*dsv*.format](https://github.com/d3/d3-dsv/blob/master/README.md#dsv_format) to format only a subset of columns, or to specify the column order explicitly:
-
-```js
-var string = d3.csvFormat(data, ["Year", "Model", "Length"]);
-```
-
-The parser is a bit faster and the formatter is a bit more robust: inputs are coerced to strings before formatting, fixing an obscure crash, and deprecated support for falling back to [*dsv*.formatRows](https://github.com/d3/d3-dsv/blob/master/README.md#dsv_formatRows) when the input *data* is an array of arrays has been removed.
-
-## [Easings (d3-ease)](https://github.com/d3/d3-ease/blob/master/README.md)
-
-D3 3.x used strings, such as “cubic-in-out”, to identify easing methods; these strings could be passed to d3.ease or *transition*.ease. D3 4.0 uses symbols instead, such as [d3.easeCubicInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeCubicInOut). Symbols are simpler and cleaner. They work well with Rollup to produce smaller custom bundles. You can still define your own custom easing function, too, if desired. Here’s the full list of equivalents:
-
-* linear ↦ [d3.easeLinear](https://github.com/d3/d3-ease/blob/master/README.md#easeLinear)¹
-* linear-in ↦ [d3.easeLinear](https://github.com/d3/d3-ease/blob/master/README.md#easeLinear)¹
-* linear-out ↦ [d3.easeLinear](https://github.com/d3/d3-ease/blob/master/README.md#easeLinear)¹
-* linear-in-out ↦ [d3.easeLinear](https://github.com/d3/d3-ease/blob/master/README.md#easeLinear)¹
-* linear-out-in ↦ [d3.easeLinear](https://github.com/d3/d3-ease/blob/master/README.md#easeLinear)¹
-* poly-in ↦ [d3.easePolyIn](https://github.com/d3/d3-ease/blob/master/README.md#easePolyIn)
-* poly-out ↦ [d3.easePolyOut](https://github.com/d3/d3-ease/blob/master/README.md#easePolyOut)
-* poly-in-out ↦ [d3.easePolyInOut](https://github.com/d3/d3-ease/blob/master/README.md#easePolyInOut)
-* poly-out-in ↦ REMOVED²
-* quad-in ↦ [d3.easeQuadIn](https://github.com/d3/d3-ease/blob/master/README.md#easeQuadIn)
-* quad-out ↦ [d3.easeQuadOut](https://github.com/d3/d3-ease/blob/master/README.md#easeQuadOut)
-* quad-in-out ↦ [d3.easeQuadInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeQuadInOut)
-* quad-out-in ↦ REMOVED²
-* cubic-in ↦ [d3.easeCubicIn](https://github.com/d3/d3-ease/blob/master/README.md#easeCubicIn)
-* cubic-out ↦ [d3.easeCubicOut](https://github.com/d3/d3-ease/blob/master/README.md#easeCubicOut)
-* cubic-in-out ↦ [d3.easeCubicInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeCubicInOut)
-* cubic-out-in ↦ REMOVED²
-* sin-in ↦ [d3.easeSinIn](https://github.com/d3/d3-ease/blob/master/README.md#easeSinIn)
-* sin-out ↦ [d3.easeSinOut](https://github.com/d3/d3-ease/blob/master/README.md#easeSinOut)
-* sin-in-out ↦ [d3.easeSinInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeSinInOut)
-* sin-out-in ↦ REMOVED²
-* exp-in ↦ [d3.easeExpIn](https://github.com/d3/d3-ease/blob/master/README.md#easeExpIn)
-* exp-out ↦ [d3.easeExpOut](https://github.com/d3/d3-ease/blob/master/README.md#easeExpOut)
-* exp-in-out ↦ [d3.easeExpInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeExpInOut)
-* exp-out-in ↦ REMOVED²
-* circle-in ↦ [d3.easeCircleIn](https://github.com/d3/d3-ease/blob/master/README.md#easeCircleIn)
-* circle-out ↦ [d3.easeCircleOut](https://github.com/d3/d3-ease/blob/master/README.md#easeCircleOut)
-* circle-in-out ↦ [d3.easeCircleInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeCircleInOut)
-* circle-out-in ↦ REMOVED²
-* elastic-in ↦ [d3.easeElasticOut](https://github.com/d3/d3-ease/blob/master/README.md#easeElasticOut)²
-* elastic-out ↦ [d3.easeElasticIn](https://github.com/d3/d3-ease/blob/master/README.md#easeElasticIn)²
-* elastic-in-out ↦ REMOVED²
-* elastic-out-in ↦ [d3.easeElasticInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeElasticInOut)²
-* back-in ↦ [d3.easeBackIn](https://github.com/d3/d3-ease/blob/master/README.md#easeBackIn)
-* back-out ↦ [d3.easeBackOut](https://github.com/d3/d3-ease/blob/master/README.md#easeBackOut)
-* back-in-out ↦ [d3.easeBackInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeBackInOut)
-* back-out-in ↦ REMOVED²
-* bounce-in ↦ [d3.easeBounceOut](https://github.com/d3/d3-ease/blob/master/README.md#easeBounceOut)²
-* bounce-out ↦ [d3.easeBounceIn](https://github.com/d3/d3-ease/blob/master/README.md#easeBounceIn)²
-* bounce-in-out ↦ REMOVED²
-* bounce-out-in ↦ [d3.easeBounceInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeBounceInOut)²
-
-¹ The -in, -out and -in-out variants of linear easing are identical, so there’s just d3.easeLinear.
-<br>² Elastic and bounce easing were inadvertently reversed in 3.x, so 4.0 eliminates -out-in easing!
-
-For convenience, there are also default aliases for each easing method. For example, [d3.easeCubic](https://github.com/d3/d3-ease/blob/master/README.md#easeCubic) is an alias for [d3.easeCubicInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeCubicInOut). Most default to -in-out; the exceptions are [d3.easeBounce](https://github.com/d3/d3-ease/blob/master/README.md#easeBounce) and [d3.easeElastic](https://github.com/d3/d3-ease/blob/master/README.md#easeElastic), which default to -out.
-
-Rather than pass optional arguments to d3.ease or *transition*.ease, parameterizable easing functions now have named parameters: [*poly*.exponent](https://github.com/d3/d3-ease/blob/master/README.md#poly_exponent), [*elastic*.amplitude](https://github.com/d3/d3-ease/blob/master/README.md#elastic_amplitude), [*elastic*.period](https://github.com/d3/d3-ease/blob/master/README.md#elastic_period) and [*back*.overshoot](https://github.com/d3/d3-ease/blob/master/README.md#back_overshoot). For example, in D3 3.x you might say:
-
-```js
-var e = d3.ease("elastic-out-in", 1.2);
-```
-
-The equivalent in D3 4.0 is:
-
-```js
-var e = d3.easeElastic.amplitude(1.2);
-```
-
-Many of the easing functions have been optimized for performance and accuracy. Several bugs have been fixed, as well, such as the interpretation of the overshoot parameter for back easing, and the period parameter for elastic easing. Also, [d3-transition](#transitions-d3-transition) now explicitly guarantees that the last tick of the transition happens at exactly *t* = 1, avoiding floating point errors in some easing functions.
-
-There’s now a nice [visual reference](https://github.com/d3/d3-ease/blob/master/README.md) and an [animated reference](https://bl.ocks.org/mbostock/248bac3b8e354a9103c4) to the new easing functions, too!
-
-## [Forces (d3-force)](https://github.com/d3/d3-force/blob/master/README.md)
-
-The force layout d3.layout.force has been renamed to d3.forceSimulation. The force simulation now uses [velocity Verlet integration](https://en.wikipedia.org/wiki/Verlet_integration#Velocity_Verlet) rather than position Verlet, tracking the nodes’ positions (*node*.x, *node*.y) and velocities (*node*.vx, *node*.vy) rather than their previous positions (*node*.px, *node*.py).
-
-Rather than hard-coding a set of built-in forces, the force simulation is now extensible: you specify which forces you want! The approach affords greater flexibility through composition. The new forces are more flexible, too: force parameters can typically be configured per-node or per-link. There are separate positioning forces for [*x*](https://github.com/d3/d3-force/blob/master/README.md#forceX) and [*y*](https://github.com/d3/d3-force/blob/master/README.md#forceY) that replace *force*.gravity; [*x*.x](https://github.com/d3/d3-force/blob/master/README.md#x_x) and [*y*.y](https://github.com/d3/d3-force/blob/master/README.md#y_y) replace *force*.size. The new [link force](https://github.com/d3/d3-force/blob/master/README.md#forceLink) replaces *force*.linkStrength and employs better default heuristics to improve stability. The new [many-body force](https://github.com/d3/d3-force/blob/master/README.md#forceManyBody) replaces *force*.charge and supports a new [minimum-distance parameter](https://github.com/d3/d3-force/blob/master/README.md#manyBody_distanceMin) and performance improvements thanks to 4.0’s [new quadtrees](#quadtrees-d3-quadtree). There are also brand-new forces for [centering nodes](https://github.com/d3/d3-force/blob/master/README.md#forceCenter) and [collision resolution](https://github.com/d3/d3-force/blob/master/README.md#forceCollision).
-
-The new forces and simulation have been carefully crafted to avoid nondeterminism. Rather than initializing nodes randomly, if the nodes do not have preset positions, they are placed in a phyllotaxis pattern:
-
-<img alt="Phyllotaxis" src="https://raw.githubusercontent.com/d3/d3-force/master/img/phyllotaxis.png" width="420" height="219">
-
-Random jitter is still needed to resolve link, collision and many-body forces if there are coincident nodes, but at least in the common case, the force simulation (and the resulting force-directed graph layout) is now consistent across browsers and reloads. D3 no longer plays dice!
-
-The force simulation has several new methods for greater control over heating, such as [*simulation*.alphaMin](https://github.com/d3/d3-force/blob/master/README.md#simulation_alphaMin) and [*simulation*.alphaDecay](https://github.com/d3/d3-force/blob/master/README.md#simulation_alphaDecay), and the internal timer. Calling [*simulation*.alpha](https://github.com/d3/d3-force/blob/master/README.md#simulation_alpha) now has no effect on the internal timer, which is controlled independently via [*simulation*.stop](https://github.com/d3/d3-force/blob/master/README.md#simulation_stop) and [*simulation*.restart](https://github.com/d3/d3-force/blob/master/README.md#simulation_restart). The force layout’s internal timer now starts automatically on creation, removing *force*.start. As in 3.x, you can advance the simulation manually using [*simulation*.tick](https://github.com/d3/d3-force/blob/master/README.md#simulation_tick). The *force*.friction parameter is replaced by *simulation*.velocityDecay. A new [*simulation*.alphaTarget](https://github.com/d3/d3-force/blob/master/README.md#simulation_alphaTarget) method allows you to set the desired alpha (temperature) of the simulation, such that the simulation can be smoothly reheated during interaction, and then smoothly cooled again. This improves the stability of the graph during interaction.
-
-The force layout no longer depends on the [drag behavior](#dragging-d3-drag), though you can certainly create [draggable force-directed graphs](https://bl.ocks.org/mbostock/ad70335eeef6d167bc36fd3c04378048)! Set *node*.fx and *node*.fy to fix a node’s position. As an alternative to a [Voronoi](#voronoi-d3-voronoi) SVG overlay, you can now use [*simulation*.find](https://github.com/d3/d3-force/blob/master/README.md#simulation_find) to find the closest node to a pointer.
-
-## [Number Formats (d3-format)](https://github.com/d3/d3-format/blob/master/README.md)
-
-If a precision is not specified, the formatting behavior has changed: there is now a default precision of 6 for all directives except *none*, which defaults to 12. In 3.x, if you did not specify a precision, the number was formatted using its shortest unique representation (per [*number*.toString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString)); this could lead to unexpected digits due to [floating point math](http://0.30000000000000004.com/). The new default precision in 4.0 produces more consistent results:
-
-```js
-var f = d3.format("e");
-f(42);        // "4.200000e+1"
-f(0.1 + 0.2); // "3.000000e-1"
-```
-
-To trim insignificant trailing zeroes, use the *none* directive, which is similar `g`. For example:
-
-```js
-var f = d3.format(".3");
-f(0.12345);   // "0.123"
-f(0.10000);   // "0.1"
-f(0.1 + 0.2); // "0.3"
-```
-
-Under the hood, number formatting has improved accuracy with very large and very small numbers by using [*number*.toExponential](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toExponential) rather than [Math.log](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log) to extract the mantissa and exponent. Negative zero (-0, an IEEE 754 construct) and very small numbers that round to zero are now formatted as unsigned zero. The inherently unsafe d3.round method has been removed, along with d3.requote.
-
-The [d3.formatPrefix](https://github.com/d3/d3-format/blob/master/README.md#formatPrefix) method has been changed. Rather than returning an SI-prefix string, it returns an SI-prefix format function for a given *specifier* and reference *value*. For example, to format thousands:
-
-```js
-var f = d3.formatPrefix(",.0", 1e3);
-f(1e3); // "1k"
-f(1e4); // "10k"
-f(1e5); // "100k"
-f(1e6); // "1,000k"
-```
-
-Unlike the `s` format directive, d3.formatPrefix always employs the same SI-prefix, producing consistent results:
-
-```js
-var f = d3.format(".0s");
-f(1e3); // "1k"
-f(1e4); // "10k"
-f(1e5); // "100k"
-f(1e6); // "1M"
-```
-
-The new `(` sign option uses parentheses for negative values. This is particularly useful in conjunction with `$`. For example:
-
-```js
-d3.format("+.0f")(-42);  // "-42"
-d3.format("(.0f")(-42);  // "(42)"
-d3.format("+$.0f")(-42); // "-$42"
-d3.format("($.0f")(-42); // "($42)"
-```
-
-The new `=` align option places any sign and symbol to the left of any padding:
-
-```js
-d3.format(">6d")(-42);  // "   -42"
-d3.format("=6d")(-42);  // "-   42"
-d3.format(">(6d")(-42); // "  (42)"
-d3.format("=(6d")(-42); // "(  42)"
-```
-
-The `b`, `o`, `d` and `x` directives now round to the nearest integer, rather than returning the empty string for non-integers:
-
-```js
-d3.format("b")(41.9); // "101010"
-d3.format("o")(41.9); // "52"
-d3.format("d")(41.9); // "42"
-d3.format("x")(41.9); // "2a"
-```
-
-The `c` directive is now for character data (*i.e.*, literal strings), not for character codes. The is useful if you just want to apply padding and alignment and don’t care about formatting numbers. For example, the infamous [left-pad](http://blog.npmjs.org/post/141577284765/kik-left-pad-and-npm) (as well as center- and right-pad!) can be conveniently implemented as:
-
-```js
-d3.format(">10c")("foo"); // "       foo"
-d3.format("^10c")("foo"); // "   foo    "
-d3.format("<10c")("foo"); // "foo       "
-```
-
-There are several new methods for computing suggested decimal precisions; these are used by [d3-scale](#scales-d3-scale) for tick formatting, and are helpful for implementing custom number formats: [d3.precisionFixed](https://github.com/d3/d3-format/blob/master/README.md#precisionFixed), [d3.precisionPrefix](https://github.com/d3/d3-format/blob/master/README.md#precisionPrefix) and [d3.precisionRound](https://github.com/d3/d3-format/blob/master/README.md#precisionRound). There’s also a new [d3.formatSpecifier](https://github.com/d3/d3-format/blob/master/README.md#formatSpecifier) method for parsing, validating and debugging format specifiers; it’s also good for deriving related format specifiers, such as when you want to substitute the precision automatically.
-
-You can now set the default locale using [d3.formatDefaultLocale](https://github.com/d3/d3-format/blob/master/README.md#formatDefaultLocale)! The locales are published as [JSON](https://github.com/d3/d3-request/blob/master/README.md#json) to [npm](https://unpkg.com/d3-format/locale/).
-
-## [Geographies (d3-geo)](https://github.com/d3/d3-geo/blob/master/README.md)
-
-Pursuant to the great namespace flattening, various methods have new names:
-
-* d3.geo.graticule ↦ [d3.geoGraticule](https://github.com/d3/d3-geo/blob/master/README.md#geoGraticule)
-* d3.geo.circle ↦ [d3.geoCircle](https://github.com/d3/d3-geo/blob/master/README.md#geoCircle)
-* d3.geo.area ↦ [d3.geoArea](https://github.com/d3/d3-geo/blob/master/README.md#geoArea)
-* d3.geo.bounds ↦ [d3.geoBounds](https://github.com/d3/d3-geo/blob/master/README.md#geoBounds)
-* d3.geo.centroid ↦ [d3.geoCentroid](https://github.com/d3/d3-geo/blob/master/README.md#geoCentroid)
-* d3.geo.distance ↦ [d3.geoDistance](https://github.com/d3/d3-geo/blob/master/README.md#geoDistance)
-* d3.geo.interpolate ↦ [d3.geoInterpolate](https://github.com/d3/d3-geo/blob/master/README.md#geoInterpolate)
-* d3.geo.length ↦ [d3.geoLength](https://github.com/d3/d3-geo/blob/master/README.md#geoLength)
-* d3.geo.rotation ↦ [d3.geoRotation](https://github.com/d3/d3-geo/blob/master/README.md#geoRotation)
-* d3.geo.stream ↦ [d3.geoStream](https://github.com/d3/d3-geo/blob/master/README.md#geoStream)
-* d3.geo.path ↦ [d3.geoPath](https://github.com/d3/d3-geo/blob/master/README.md#geoPath)
-* d3.geo.projection ↦ [d3.geoProjection](https://github.com/d3/d3-geo/blob/master/README.md#geoProjection)
-* d3.geo.projectionMutator ↦ [d3.geoProjectionMutator](https://github.com/d3/d3-geo/blob/master/README.md#geoProjectionMutator)
-* d3.geo.albers ↦ [d3.geoAlbers](https://github.com/d3/d3-geo/blob/master/README.md#geoAlbers)
-* d3.geo.albersUsa ↦ [d3.geoAlbersUsa](https://github.com/d3/d3-geo/blob/master/README.md#geoAlbersUsa)
-* d3.geo.azimuthalEqualArea ↦ [d3.geoAzimuthalEqualArea](https://github.com/d3/d3-geo/blob/master/README.md#geoAzimuthalEqualArea)
-* d3.geo.azimuthalEquidistant ↦ [d3.geoAzimuthalEquidistant](https://github.com/d3/d3-geo/blob/master/README.md#geoAzimuthalEquidistant)
-* d3.geo.conicConformal ↦ [d3.geoConicConformal](https://github.com/d3/d3-geo/blob/master/README.md#geoConicConformal)
-* d3.geo.conicEqualArea ↦ [d3.geoConicEqualArea](https://github.com/d3/d3-geo/blob/master/README.md#geoConicEqualArea)
-* d3.geo.conicEquidistant ↦ [d3.geoConicEquidistant](https://github.com/d3/d3-geo/blob/master/README.md#geoConicEquidistant)
-* d3.geo.equirectangular ↦ [d3.geoEquirectangular](https://github.com/d3/d3-geo/blob/master/README.md#geoEquirectangular)
-* d3.geo.gnomonic ↦ [d3.geoGnomonic](https://github.com/d3/d3-geo/blob/master/README.md#geoGnomonic)
-* d3.geo.mercator ↦ [d3.geoMercator](https://github.com/d3/d3-geo/blob/master/README.md#geoMercator)
-* d3.geo.orthographic ↦ [d3.geoOrthographic](https://github.com/d3/d3-geo/blob/master/README.md#geoOrthographic)
-* d3.geo.stereographic ↦ [d3.geoStereographic](https://github.com/d3/d3-geo/blob/master/README.md#geoStereographic)
-* d3.geo.transverseMercator ↦ [d3.geoTransverseMercator](https://github.com/d3/d3-geo/blob/master/README.md#geoTransverseMercator)
-
-Also renamed for consistency:
-
-* *circle*.origin ↦ [*circle*.center](https://github.com/d3/d3-geo/blob/master/README.md#circle_center)
-* *circle*.angle ↦ [*circle*.radius](https://github.com/d3/d3-geo/blob/master/README.md#circle_radius)
-* *graticule*.majorExtent ↦ [*graticule*.extentMajor](https://github.com/d3/d3-geo/blob/master/README.md#graticule_extentMajor)
-* *graticule*.minorExtent ↦ [*graticule*.extentMinor](https://github.com/d3/d3-geo/blob/master/README.md#graticule_extentMinor)
-* *graticule*.majorStep ↦ [*graticule*.stepMajor](https://github.com/d3/d3-geo/blob/master/README.md#graticule_stepMajor)
-* *graticule*.minorStep ↦ [*graticule*.stepMinor](https://github.com/d3/d3-geo/blob/master/README.md#graticule_stepMinor)
-
-Projections now have more appropriate defaults. For example, [d3.geoOrthographic](https://github.com/d3/d3-geo/blob/master/README.md#geoOrthographic) has a 90° clip angle by default, showing only the front hemisphere, and [d3.geoGnomonic](https://github.com/d3/d3-geo/blob/master/README.md#geoGnomonic) has a default 60° clip angle. The default [projection](https://github.com/d3/d3-geo/blob/master/README.md#path_projection) for [d3.geoPath](https://github.com/d3/d3-geo/blob/master/README.md#geoPath) is now null rather than [d3.geoAlbersUsa](https://github.com/d3/d3-geo/blob/master/README.md#geoAlbersUsa); a null projection is used with [pre-projected geometry](https://bl.ocks.org/mbostock/5557726) and is typically faster to render.
-
-“Fallback projections”—when you pass a function rather than a projection to [*path*.projection](https://github.com/d3/d3-geo/blob/master/README.md#path_projection)—are no longer supported. For geographic projections, use [d3.geoProjection](https://github.com/d3/d3-geo/blob/master/README.md#geoProjection) or [d3.geoProjectionMutator](https://github.com/d3/d3-geo/blob/master/README.md#geoProjectionMutator) to define a custom projection. For arbitrary geometry transformations, implement the [stream interface](https://github.com/d3/d3-geo/blob/master/README.md#streams); see also [d3.geoTransform](https://github.com/d3/d3-geo/blob/master/README.md#geoTransform). The “raw” projections (e.g., d3.geo.equirectangular.raw) are no longer exported.
-
-## [Hierarchies (d3-hierarchy)](https://github.com/d3/d3-hierarchy/blob/master/README.md)
-
-Pursuant to the great namespace flattening:
-
-* d3.layout.cluster ↦ [d3.cluster](https://github.com/d3/d3-hierarchy/blob/master/README.md#cluster)
-* d3.layout.hierarchy ↦ [d3.hierarchy](https://github.com/d3/d3-hierarchy/blob/master/README.md#hierarchy)
-* d3.layout.pack ↦ [d3.pack](https://github.com/d3/d3-hierarchy/blob/master/README.md#pack)
-* d3.layout.partition ↦ [d3.partition](https://github.com/d3/d3-hierarchy/blob/master/README.md#partition)
-* d3.layout.tree ↦ [d3.tree](https://github.com/d3/d3-hierarchy/blob/master/README.md#tree)
-* d3.layout.treemap ↦ [d3.treemap](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap)
-
-As an alternative to using JSON to represent hierarchical data (such as the “flare.json format” used by many D3 examples), the new [d3.stratify](https://github.com/d3/d3-hierarchy/blob/master/README.md#stratify) operator simplifies the conversion of tabular data to hierarchical data! This is convenient if you already have data in a tabular format, such as the result of a SQL query or a CSV file:
-
-```
-name,parent
-Eve,
-Cain,Eve
-Seth,Eve
-Enos,Seth
-Noam,Seth
-Abel,Eve
-Awan,Eve
-Enoch,Awan
-Azura,Eve
-```
-
-To convert this to a root [*node*](https://github.com/d3/d3-hierarchy/blob/master/README.md#hierarchy):
-
-```js
-var root = d3.stratify()
-    .id(function(d) { return d.name; })
-    .parentId(function(d) { return d.parent; })
-    (nodes);
-```
-
-The resulting *root* can be passed to [d3.tree](https://github.com/d3/d3-hierarchy/blob/master/README.md#tree) to produce a tree diagram like this:
-
-<img src="https://raw.githubusercontent.com/d3/d3/master/img/stratify.png" width="298" height="137">
-
-Root nodes can also be created from JSON data using [d3.hierarchy](https://github.com/d3/d3-hierarchy/blob/master/README.md#hierarchy). The hierarchy layouts now take these root nodes as input rather than operating directly on JSON data, which helps to provide a cleaner separation between the input data and the computed layout. (For example, use [*node*.copy](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_copy) to isolate layout changes.) It also simplifies the API: rather than each hierarchy layout needing to implement value and sorting accessors, there are now generic [*node*.sum](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_sum) and [*node*.sort](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_sort) methods that work with any hierarchy layout.
-
-The new d3.hierarchy API also provides a richer set of methods for manipulating hierarchical data. For example, to generate an array of all nodes in topological order, use [*node*.descendants](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_descendants); for just leaf nodes, use [*node*.leaves](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_leaves). To highlight the ancestors of a given *node* on mouseover, use [*node*.ancestors](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_ancestors). To generate an array of {source, target} links for a given hierarchy, use [*node*.links](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_links); this replaces *treemap*.links and similar methods on the other layouts. The new [*node*.path](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_path) method replaces d3.layout.bundle; see also [d3.curveBundle](https://github.com/d3/d3-shape/blob/master/README.md#curveBundle) for hierarchical edge bundling.
-
-The hierarchy layouts have been rewritten using new, non-recursive traversal methods ([*node*.each](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_each), [*node*.eachAfter](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_eachAfter) and [*node*.eachBefore](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_eachBefore)), improving performance on large datasets. The d3.tree layout no longer uses a *node*.\_ field to store temporary state during layout.
-
-Treemap tiling is now [extensible](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap-tiling) via [*treemap*.tile](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_tile)! The default squarified tiling algorithm, [d3.treemapSquarify](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemapSquarify), has been completely rewritten, improving performance and fixing bugs in padding and rounding. The *treemap*.sticky method has been replaced with the [d3.treemapResquarify](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemapResquarify), which is identical to d3.treemapSquarify except it performs stable neighbor-preserving updates. The *treemap*.ratio method has been replaced with [*squarify*.ratio](https://github.com/d3/d3-hierarchy/blob/master/README.md#squarify_ratio). And there’s a new [d3.treemapBinary](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemapBinary) for binary treemaps!
-
-Treemap padding has also been improved. The treemap now distinguishes between [outer padding](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_paddingOuter) that separates a parent from its children, and [inner padding](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_paddingInner) that separates adjacent siblings. You can set the [top-](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_paddingTop), [right-](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_paddingRight), [bottom-](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_paddingBottom) and [left-](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_paddingLeft)outer padding separately. There are new examples for the traditional [nested treemap](https://bl.ocks.org/mbostock/911ad09bdead40ec0061) and for Lü and Fogarty’s [cascaded treemap](https://bl.ocks.org/mbostock/f85ffb3a5ac518598043). And there’s a new example demonstrating [d3.nest with d3.treemap](https://bl.ocks.org/mbostock/2838bf53e0e65f369f476afd653663a2).
-
-The space-filling layouts [d3.treemap](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap) and [d3.partition](https://github.com/d3/d3-hierarchy/blob/master/README.md#partition) now output *x0*, *x1*, *y0*, *y1* on each node instead of *x0*, *dx*, *y0*, *dy*. This improves accuracy by ensuring that the edges of adjacent cells are exactly equal, rather than sometimes being slightly off due to floating point math. The partition layout now supports [rounding](https://github.com/d3/d3-hierarchy/blob/master/README.md#partition_round) and [padding](https://github.com/d3/d3-hierarchy/blob/master/README.md#partition_padding).
-
-The circle-packing layout, [d3.pack](https://github.com/d3/d3-hierarchy/blob/master/README.md#pack), has been completely rewritten to better implement Wang et al.’s algorithm, fixing major bugs and improving results! Welzl’s algorithm is now used to compute the exact [smallest enclosing circle](https://bl.ocks.org/mbostock/29c534ff0b270054a01c) for each parent, rather than the approximate answer used by Wang et al. The 3.x output is shown on the left; 4.0 is shown on the right:
-
-<img alt="Circle Packing in 3.x" src="https://raw.githubusercontent.com/d3/d3/master/img/pack-v3.png" width="420" height="420"> <img alt="Circle Packing in 4.0" src="https://raw.githubusercontent.com/d3/d3/master/img/pack-v4.png" width="420" height="420">
-
-A non-hierarchical implementation is also available as [d3.packSiblings](https://github.com/d3/d3-hierarchy/blob/master/README.md#packSiblings), and the smallest enclosing circle implementation is available as [d3.packEnclose](https://github.com/d3/d3-hierarchy/blob/master/README.md#packEnclose). [Pack padding](https://github.com/d3/d3-hierarchy/blob/master/README.md#pack_padding) now applies between a parent and its children, as well as between adjacent siblings. In addition, you can now specify padding as a function that is computed dynamically for each parent.
-
-## Internals
-
-The d3.rebind method has been removed. (See the [3.x source](https://github.com/d3/d3/blob/v3.5.17/src/core/rebind.js).) If you want to wrap a getter-setter method, the recommend pattern is to implement a wrapper method and check the return value. For example, given a *component* that uses an internal [*dispatch*](#dispatches-d3-dispatch), *component*.on can rebind *dispatch*.on as follows:
-
-```js
-component.on = function() {
-  var value = dispatch.on.apply(dispatch, arguments);
-  return value === dispatch ? component : value;
-};
-```
-
-The d3.functor method has been removed. (See the [3.x source](https://github.com/d3/d3/blob/v3.5.17/src/core/functor.js).) If you want to promote a constant value to a function, the recommended pattern is to implement a closure that returns the constant value. If desired, you can use a helper method as follows:
-
-```js
-function constant(x) {
-  return function() {
-    return x;
-  };
-}
-```
-
-Given a value *x*, to promote *x* to a function if it is not already:
-
-```js
-var fx = typeof x === "function" ? x : constant(x);
-```
-
-## [Interpolators (d3-interpolate)](https://github.com/d3/d3-interpolate/blob/master/README.md)
-
-The [d3.interpolate](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolate) method no longer delegates to d3.interpolators, which has been removed; its behavior is now defined by the library. It is now slightly faster in the common case that *b* is a number. It only uses [d3.interpolateRgb](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateRgb) if *b* is a valid CSS color specifier (and not approximately one). And if the end value *b* is null, undefined, true or false, d3.interpolate now returns a constant function which always returns *b*.
-
-The behavior of [d3.interpolateObject](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateObject) and [d3.interpolateArray](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateArray) has changed slightly with respect to properties or elements in the start value *a* that do not exist in the end value *b*: these properties and elements are now ignored, such that the ending value of the interpolator at *t* = 1 is now precisely equal to *b*. So, in 3.x:
-
-```js
-d3.interpolateObject({foo: 2, bar: 1}, {foo: 3})(0.5); // {bar: 1, foo: 2.5} in 3.x
-```
-
-Whereas in 4.0, *a*.bar is ignored:
-
-```js
-d3.interpolateObject({foo: 2, bar: 1}, {foo: 3})(0.5); // {foo: 2.5} in 4.0
-```
-
-If *a* or *b* are undefined or not an object, they are now implicitly converted to the empty object or empty array as appropriate, rather than throwing a TypeError.
-
-The d3.interpolateTransform interpolator has been renamed to [d3.interpolateTransformSvg](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateTransformSvg), and there is a new [d3.interpolateTransformCss](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateTransformCss) to interpolate CSS transforms! This allows [d3-transition](#transitions-d3-transition) to automatically interpolate both the SVG [transform attribute](https://www.w3.org/TR/SVG/coords.html#TransformAttribute) and the CSS [transform style property](https://www.w3.org/TR/css-transforms-1/#transform-property). (Note, however, that only 2D CSS transforms are supported.) The d3.transform method has been removed.
-
-Color space interpolators now interpolate opacity (see [d3-color](#colors-d3-color)) and return rgb(…) or rgba(…) CSS color specifier strings rather than using the RGB hexadecimal format. This is necessary to support opacity interpolation, but is also beneficial because it matches CSS computed values. When a channel in the start color *a* is undefined, color interpolators now use the corresponding channel value from the end color *b*, or *vice versa*. This logic previously applied to some channels (such as saturation in HSL), but now applies to all channels in all color spaces, and is especially useful when interpolating to or from transparent.
-
-There are now “long” versions of cylindrical color space interpolators: [d3.interpolateHslLong](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateHslLong), [d3.interpolateHclLong](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateHclLong) and [d3.interpolateCubehelixLong](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateCubehelixLong). These interpolators use linear interpolation of hue, rather than using the shortest path around the 360° hue circle. See [d3.interpolateRainbow](https://github.com/d3/d3-scale/blob/master/README.md#interpolateRainbow) for an example. The Cubehelix color space is now supported by [d3-color](#colors-d3-color), and so there are now [d3.interpolateCubehelix](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateCubehelix) and [d3.interpolateCubehelixLong](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateCubehelixLong) interpolators.
-
-[Gamma-corrected color interpolation](https://web.archive.org/web/20160112115812/http://www.4p8.com/eric.brasseur/gamma.html) is now supported for both RGB and Cubehelix color spaces as [*interpolate*.gamma](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolate_gamma). For example, to interpolate from purple to orange with a gamma of 2.2 in RGB space:
-
-```js
-var interpolate = d3.interpolateRgb.gamma(2.2)("purple", "orange");
-```
-
-There are new interpolators for uniform non-rational [B-splines](https://en.wikipedia.org/wiki/B-spline)! These are useful for smoothly interpolating between an arbitrary sequence of values from *t* = 0 to *t* = 1, such as to generate a smooth color gradient from a discrete set of colors. The [d3.interpolateBasis](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateBasis) and [d3.interpolateBasisClosed](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateBasisClosed) interpolators generate one-dimensional B-splines, while [d3.interpolateRgbBasis](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateRgbBasis) and [d3.interpolateRgbBasisClosed](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateRgbBasisClosed) generate three-dimensional B-splines through RGB color space. These are used by [d3-scale-chromatic](https://github.com/d3/d3-scale-chromatic) to generate continuous color scales from ColorBrewer’s discrete color schemes, such as [PiYG](https://bl.ocks.org/mbostock/048d21cf747371b11884f75ad896e5a5).
-
-There’s also now a [d3.quantize](https://github.com/d3/d3-interpolate/blob/master/README.md#quantize) method for generating uniformly-spaced discrete samples from a continuous interpolator. This is useful for taking one of the built-in color scales (such as [d3.interpolateViridis](https://github.com/d3/d3-scale/blob/master/README.md#interpolateViridis)) and quantizing it for use with [d3.scaleQuantize](https://github.com/d3/d3-scale/blob/master/README.md#scaleQuantize), [d3.scaleQuantile](https://github.com/d3/d3-scale/blob/master/README.md#scaleQuantile) or [d3.scaleThreshold](https://github.com/d3/d3-scale/blob/master/README.md#scaleThreshold).
-
-## [Paths (d3-path)](https://github.com/d3/d3-path/blob/master/README.md)
-
-The [d3.path](https://github.com/d3/d3-path/blob/master/README.md#path) serializer implements the [CanvasPathMethods API](https://www.w3.org/TR/2dcontext/#canvaspathmethods), allowing you to write code that can render to either Canvas or SVG. For example, given some code that draws to a canvas:
-
-```js
-function drawCircle(context, radius) {
-  context.moveTo(radius, 0);
-  context.arc(0, 0, radius, 0, 2 * Math.PI);
-}
-```
-
-You can render to SVG as follows:
-
-```js
-var context = d3.path();
-drawCircle(context, 40);
-pathElement.setAttribute("d", context.toString());
-```
-
-The path serializer enables [d3-shape](#shapes-d3-shape) to support both Canvas and SVG; see [*line*.context](https://github.com/d3/d3-shape/blob/master/README.md#line_context) and [*area*.context](https://github.com/d3/d3-shape/blob/master/README.md#area_context), for example.
-
-## [Polygons (d3-polygon)](https://github.com/d3/d3-polygon/blob/master/README.md)
-
-There’s no longer a d3.geom.polygon constructor; instead you just pass an array of vertices to the polygon methods. So instead of *polygon*.area and *polygon*.centroid, there’s [d3.polygonArea](https://github.com/d3/d3-polygon/blob/master/README.md#polygonArea) and [d3.polygonCentroid](https://github.com/d3/d3-polygon/blob/master/README.md#polygonCentroid). There are also new [d3.polygonContains](https://github.com/d3/d3-polygon/blob/master/README.md#polygonContains) and [d3.polygonLength](https://github.com/d3/d3-polygon/blob/master/README.md#polygonLength) methods. There’s no longer an equivalent to *polygon*.clip, but if [Sutherland–Hodgman clipping](https://en.wikipedia.org/wiki/Sutherland–Hodgman_algorithm) is needed, please [file a feature request](https://github.com/d3/d3-polygon/issues).
-
-The d3.geom.hull operator has been simplified: instead of an operator with *hull*.x and *hull*.y accessors, there’s just the [d3.polygonHull](https://github.com/d3/d3-polygon/blob/master/README.md#polygonHull) method which takes an array of points and returns the convex hull.
-
-## [Quadtrees (d3-quadtree)](https://github.com/d3/d3-quadtree/blob/master/README.md)
-
-The d3.geom.quadtree method has been replaced by [d3.quadtree](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree). 4.0 removes the concept of quadtree “generators” (configurable functions that build a quadtree from an array of data); there are now just quadtrees, which you can create via d3.quadtree and add data to via [*quadtree*.add](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_add) and [*quadtree*.addAll](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_addAll). This code in 3.x:
-
-```js
-var quadtree = d3.geom.quadtree()
-    .extent([[0, 0], [width, height]])
-    (data);
-```
-
-Can be rewritten in 4.0 as:
-
-```js
-var quadtree = d3.quadtree()
-    .extent([[0, 0], [width, height]])
-    .addAll(data);
-```
-
-The new quadtree implementation is vastly improved! It is no longer recursive, avoiding stack overflows when there are large numbers of coincident points. The internal storage is now more efficient, and the implementation is also faster; constructing a quadtree of 1M normally-distributed points takes about one second in 4.0, as compared to three seconds in 3.x.
-
-The change in [internal *node* structure](https://github.com/d3/d3-quadtree/blob/master/README.md#nodes) affects [*quadtree*.visit](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_visit): use *node*.length to distinguish leaf nodes from internal nodes. For example, to iterate over all data in a quadtree:
-
-```js
-quadtree.visit(function(node) {
-  if (!node.length) {
-    do {
-      console.log(node.data);
-    } while (node = node.next)
-  }
-});
-```
-
-There’s a new [*quadtree*.visitAfter](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_visitAfter) method for visiting nodes in post-order traversal. This feature is used in [d3-force](#forces-d3-force) to implement the [Barnes–Hut approximation](https://en.wikipedia.org/wiki/Barnes–Hut_simulation).
-
-You can now remove data from a quadtree using [*quadtree*.remove](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_remove) and [*quadtree*.removeAll](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_removeAll). When adding data to a quadtree, the quadtree will now expand its extent by repeated doubling if the new point is outside the existing extent of the quadtree. There are also [*quadtree*.extent](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_extent) and [*quadtree*.cover](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_cover) methods for explicitly expanding the extent of the quadtree after creation.
-
-Quadtrees support several new utility methods: [*quadtree*.copy](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_copy) returns a copy of the quadtree sharing the same data; [*quadtree*.data](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_data) generates an array of all data in the quadtree; [*quadtree*.size](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_size) returns the number of data points in the quadtree; and [*quadtree*.root](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_root) returns the root node, which is useful for manual traversal of the quadtree. The [*quadtree*.find](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_find) method now takes an optional search radius, which is useful for pointer-based selection in [force-directed graphs](https://bl.ocks.org/mbostock/ad70335eeef6d167bc36fd3c04378048).
-
-## [Queues (d3-queue)](https://github.com/d3/d3-queue/blob/master/README.md)
-
-Formerly known as Queue.js and queue-async, [d3.queue](https://github.com/d3/d3-queue) is now included in the default bundle, making it easy to load data files in parallel. It has been rewritten with fewer closures to improve performance, and there are now stricter checks in place to guarantee well-defined behavior. You can now use instanceof d3.queue and inspect the queue’s internal private state.
-
-## [Random Numbers (d3-random)](https://github.com/d3/d3-random/blob/master/README.md)
-
-Pursuant to the great namespace flattening, the random number generators have new names:
-
-* d3.random.normal ↦ [d3.randomNormal](https://github.com/d3/d3-random/blob/master/README.md#randomNormal)
-* d3.random.logNormal ↦ [d3.randomLogNormal](https://github.com/d3/d3-random/blob/master/README.md#randomLogNormal)
-* d3.random.bates ↦ [d3.randomBates](https://github.com/d3/d3-random/blob/master/README.md#randomBates)
-* d3.random.irwinHall ↦ [d3.randomIrwinHall](https://github.com/d3/d3-random/blob/master/README.md#randomIrwinHall)
-
-There are also new random number generators for [exponential](https://github.com/d3/d3-random/blob/master/README.md#randomExponential) and [uniform](https://github.com/d3/d3-random/blob/master/README.md#randomUniform) distributions. The [normal](https://github.com/d3/d3-random/blob/master/README.md#randomNormal) and [log-normal](https://github.com/d3/d3-random/blob/master/README.md#randomLogNormal) random generators have been optimized.
-
-## [Requests (d3-request)](https://github.com/d3/d3-request/blob/master/README.md)
-
-The d3.xhr method has been renamed to [d3.request](https://github.com/d3/d3-request/blob/master/README.md#request). Basic authentication is now supported using [*request*.user](https://github.com/d3/d3-request/blob/master/README.md#request_user) and [*request*.password](https://github.com/d3/d3-request/blob/master/README.md#request_password). You can now configure a timeout using [*request*.timeout](https://github.com/d3/d3-request/blob/master/README.md#request_timeout).
-
-If an error occurs, the corresponding [ProgressEvent](https://xhr.spec.whatwg.org/#interface-progressevent) of type “error” is now passed to the error listener, rather than the [XMLHttpRequest](https://xhr.spec.whatwg.org/#interface-xmlhttprequest). Likewise, the ProgressEvent is passed to progress event listeners, rather than using [d3.event](https://github.com/d3/d3-selection/blob/master/README.md#event). If [d3.xml](https://github.com/d3/d3-request/blob/master/README.md#xml) encounters an error parsing XML, this error is now reported to error listeners rather than returning a null response.
-
-The [d3.request](https://github.com/d3/d3-request/blob/master/README.md#request), [d3.text](https://github.com/d3/d3-request/blob/master/README.md#text) and [d3.xml](https://github.com/d3/d3-request/blob/master/README.md#xml) methods no longer take an optional mime type as the second argument; use [*request*.mimeType](https://github.com/d3/d3-request/blob/master/README.md#request_mimeType) instead. For example:
-
-```js
-d3.xml("file.svg").mimeType("image/svg+xml").get(function(error, svg) {
-  …
-});
-```
-
-With the exception of [d3.html](https://github.com/d3/d3-request/blob/master/README.md#html) and [d3.xml](https://github.com/d3/d3-request/blob/master/README.md#xml), Node is now supported via [node-XMLHttpRequest](https://github.com/driverdan/node-XMLHttpRequest).
-
-## [Scales (d3-scale)](https://github.com/d3/d3-scale/blob/master/README.md)
-
-Pursuant to the great namespace flattening:
-
-* d3.scale.linear ↦ [d3.scaleLinear](https://github.com/d3/d3-scale/blob/master/README.md#scaleLinear)
-* d3.scale.sqrt ↦ [d3.scaleSqrt](https://github.com/d3/d3-scale/blob/master/README.md#scaleSqrt)
-* d3.scale.pow ↦ [d3.scalePow](https://github.com/d3/d3-scale/blob/master/README.md#scalePow)
-* d3.scale.log ↦ [d3.scaleLog](https://github.com/d3/d3-scale/blob/master/README.md#scaleLog)
-* d3.scale.quantize ↦ [d3.scaleQuantize](https://github.com/d3/d3-scale/blob/master/README.md#scaleQuantize)
-* d3.scale.threshold ↦ [d3.scaleThreshold](https://github.com/d3/d3-scale/blob/master/README.md#scaleThreshold)
-* d3.scale.quantile ↦ [d3.scaleQuantile](https://github.com/d3/d3-scale/blob/master/README.md#scaleQuantile)
-* d3.scale.identity ↦ [d3.scaleIdentity](https://github.com/d3/d3-scale/blob/master/README.md#scaleIdentity)
-* d3.scale.ordinal ↦ [d3.scaleOrdinal](https://github.com/d3/d3-scale/blob/master/README.md#scaleOrdinal)
-* d3.time.scale ↦ [d3.scaleTime](https://github.com/d3/d3-scale/blob/master/README.md#scaleTime)
-* d3.time.scale.utc ↦ [d3.scaleUtc](https://github.com/d3/d3-scale/blob/master/README.md#scaleUtc)
-
-Scales now generate ticks in the same order as the domain: if you have a descending domain, you now get descending ticks. This change affects the order of tick elements generated by [axes](#axes-d3-axis). For example:
-
-```js
-d3.scaleLinear().domain([10, 0]).ticks(5); // [10, 8, 6, 4, 2, 0]
-```
-
-[Log tick formatting](https://github.com/d3/d3-scale/blob/master/README.md#log_tickFormat) now assumes a default *count* of ten, not Infinity, if not specified. Log scales with  domains that span many powers (such as from 1e+3 to 1e+29) now return only one [tick](https://github.com/d3/d3-scale/blob/master/README.md#log_ticks) per power rather than returning *base* ticks per power. Non-linear quantitative scales are slightly more accurate.
-
-You can now control whether an ordinal scale’s domain is implicitly extended when the scale is passed a value that is not already in its domain. By default, [*ordinal*.unknown](https://github.com/d3/d3-scale/blob/master/README.md#ordinal_unknown) is [d3.scaleImplicit](https://github.com/d3/d3-scale/blob/master/README.md#scaleImplicit), causing unknown values to be added to the domain:
-
-```js
-var x = d3.scaleOrdinal()
-    .domain([0, 1])
-    .range(["red", "green", "blue"]);
-
-x.domain(); // [0, 1]
-x(2); // "blue"
-x.domain(); // [0, 1, 2]
-```
-
-By setting *ordinal*.unknown, you instead define the output value for unknown inputs. This is particularly useful for choropleth maps where you want to assign a color to missing data.
-
-```js
-var x = d3.scaleOrdinal()
-    .domain([0, 1])
-    .range(["red", "green", "blue"])
-    .unknown(undefined);
-
-x.domain(); // [0, 1]
-x(2); // undefined
-x.domain(); // [0, 1]
-```
-
-The *ordinal*.rangeBands and *ordinal*.rangeRoundBands methods have been replaced with a new subclass of ordinal scale: [band scales](https://github.com/d3/d3-scale/blob/master/README.md#band-scales). The following code in 3.x:
-
-```js
-var x = d3.scale.ordinal()
-    .domain(["a", "b", "c"])
-    .rangeBands([0, width]);
-```
-
-Is equivalent to this in 4.0:
-
-```js
-var x = d3.scaleBand()
-    .domain(["a", "b", "c"])
-    .range([0, width]);
-```
-
-The new [*band*.padding](https://github.com/d3/d3-scale/blob/master/README.md#band_padding), [*band*.paddingInner](https://github.com/d3/d3-scale/blob/master/README.md#band_paddingInner) and [*band*.paddingOuter](https://github.com/d3/d3-scale/blob/master/README.md#band_paddingOuter) methods replace the optional arguments to *ordinal*.rangeBands. The new [*band*.bandwidth](https://github.com/d3/d3-scale/blob/master/README.md#band_bandwidth) and [*band*.step](https://github.com/d3/d3-scale/blob/master/README.md#band_step) methods replace *ordinal*.rangeBand. There’s also a new [*band*.align](https://github.com/d3/d3-scale/blob/master/README.md#band_align) method which you can use to control how the extra space outside the bands is distributed, say to shift columns closer to the *y*-axis.
-
-Similarly, the *ordinal*.rangePoints and *ordinal*.rangeRoundPoints methods have been replaced with a new subclass of ordinal scale: [point scales](https://github.com/d3/d3-scale/blob/master/README.md#point-scales). The following code in 3.x:
-
-```js
-var x = d3.scale.ordinal()
-    .domain(["a", "b", "c"])
-    .rangePoints([0, width]);
-```
-
-Is equivalent to this in 4.0:
-
-```js
-var x = d3.scalePoint()
-    .domain(["a", "b", "c"])
-    .range([0, width]);
-```
-
-The new [*point*.padding](https://github.com/d3/d3-scale/blob/master/README.md#point_padding) method replaces the optional *padding* argument to *ordinal*.rangePoints. Like *ordinal*.rangeBand with *ordinal*.rangePoints, the [*point*.bandwidth](https://github.com/d3/d3-scale/blob/master/README.md#point_bandwidth) method always returns zero; a new [*point*.step](https://github.com/d3/d3-scale/blob/master/README.md#point_step) method returns the interval between adjacent points.
-
-The [ordinal scale constructor](https://github.com/d3/d3-scale/blob/master/README.md#ordinal-scales) now takes an optional *range* for a shorter alternative to [*ordinal*.range](https://github.com/d3/d3-scale/blob/master/README.md#ordinal_range). This is especially useful now that the categorical color scales have been changed to simple arrays of colors rather than specialized ordinal scale constructors:
-
-* d3.scale.category10 ↦ [d3.schemeCategory10](https://github.com/d3/d3-scale/blob/master/README.md#schemeCategory10)
-* d3.scale.category20 ↦ [d3.schemeCategory20](https://github.com/d3/d3-scale/blob/master/README.md#schemeCategory20)
-* d3.scale.category20b ↦ [d3.schemeCategory20b](https://github.com/d3/d3-scale/blob/master/README.md#schemeCategory20b)
-* d3.scale.category20c ↦ [d3.schemeCategory20c](https://github.com/d3/d3-scale/blob/master/README.md#schemeCategory20c)
-
-The following code in 3.x:
-
-```js
-var color = d3.scale.category10();
-```
-
-Is equivalent to this in 4.0:
-
-```js
-var color = d3.scaleOrdinal(d3.schemeCategory10);
-```
-
-[Sequential scales](https://github.com/d3/d3-scale/blob/master/README.md#scaleSequential), are a new class of scales with a fixed output [interpolator](https://github.com/d3/d3-scale/blob/master/README.md#sequential_interpolator) instead of a [range](https://github.com/d3/d3-scale/blob/master/README.md#continuous_range). Typically these scales are used to implement continuous sequential or diverging color schemes. Inspired by Matplotlib’s new [perceptually-motived colormaps](https://bids.github.io/colormap/), 4.0 now features [viridis](https://github.com/d3/d3-scale/blob/master/README.md#interpolateViridis), [inferno](https://github.com/d3/d3-scale/blob/master/README.md#interpolateInferno), [magma](https://github.com/d3/d3-scale/blob/master/README.md#interpolateMagma), [plasma](https://github.com/d3/d3-scale/blob/master/README.md#interpolatePlasma) interpolators for use with sequential scales. Using [d3.quantize](https://github.com/d3/d3-interpolate/blob/master/README.md#quantize), these interpolators can also be applied to [quantile](https://github.com/d3/d3-scale/blob/master/README.md#quantile-scales), [quantize](https://github.com/d3/d3-scale/blob/master/README.md#quantize-scales) and [threshold](https://github.com/d3/d3-scale/blob/master/README.md#threshold-scales) scales.
-
-[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/viridis.png" width="100%" height="40" alt="viridis">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateViridis)
-[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/inferno.png" width="100%" height="40" alt="inferno">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateInferno)
-[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/magma.png" width="100%" height="40" alt="magma">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateMagma)
-[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/plasma.png" width="100%" height="40" alt="plasma">](https://github.com/d3/d3-scale/blob/master/README.md#interpolatePlasma)
-
-4.0 also ships new Cubehelix schemes, including [Dave Green’s default](https://github.com/d3/d3-scale/blob/master/README.md#interpolateCubehelixDefault) and a [cyclical rainbow](https://github.com/d3/d3-scale/blob/master/README.md#interpolateRainbow) inspired by [Matteo Niccoli](https://mycarta.wordpress.com/2013/02/21/perceptual-rainbow-palette-the-method/):
-
-[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/cubehelix.png" width="100%" height="40" alt="cubehelix">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateCubehelixDefault)
-[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/rainbow.png" width="100%" height="40" alt="rainbow">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateRainbow)
-[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/warm.png" width="100%" height="40" alt="warm">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateWarm)
-[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/cool.png" width="100%" height="40" alt="cool">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateCool)
-
-For even more sequential and categorical color schemes, see [d3-scale-chromatic](https://github.com/d3/d3-scale-chromatic).
-
-For an introduction to scales, see [Introducing d3-scale](https://medium.com/@mbostock/introducing-d3-scale-61980c51545f).
-
-## [Selections (d3-selection)](https://github.com/d3/d3-selection/blob/master/README.md)
-
-Selections no longer subclass Array using [prototype chain injection](http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/#wrappers_prototype_chain_injection); they are now plain objects, improving performance. The internal fields (*selection*.\_groups, *selection*.\_parents) are private; please use the documented public API to manipulate selections. The new [*selection*.nodes](https://github.com/d3/d3-selection/blob/master/README.md#selection_nodes) method generates an array of all nodes in a selection.
-
-Selections are now immutable: the elements and parents in a selection never change. (The elements’ attributes and content will of course still be modified!) The [*selection*.sort](https://github.com/d3/d3-selection/blob/master/README.md#selection_sort) and [*selection*.data](https://github.com/d3/d3-selection/blob/master/README.md#selection_data) methods now return new selections rather than modifying the selection in-place. In addition, [*selection*.append](https://github.com/d3/d3-selection/blob/master/README.md#selection_append) no longer merges entering nodes into the update selection; use [*selection*.merge](https://github.com/d3/d3-selection/blob/master/README.md#selection_merge) to combine enter and update after a data join. For example, the following [general update pattern](https://bl.ocks.org/mbostock/a8a5baa4c4a470cda598) in 3.x:
-
-```js
-var circle = svg.selectAll("circle").data(data) // UPDATE
-    .style("fill", "blue");
-
-circle.exit().remove(); // EXIT
-
-circle.enter().append("circle") // ENTER; modifies UPDATE! 🌶
-    .style("fill", "green");
-
-circle // ENTER + UPDATE
-    .style("stroke", "black");
-```
-
-Would be rewritten in 4.0 as:
-
-```js
-var circle = svg.selectAll("circle").data(data) // UPDATE
-    .style("fill", "blue");
-
-circle.exit().remove(); // EXIT
-
-circle.enter().append("circle") // ENTER
-    .style("fill", "green")
-  .merge(circle) // ENTER + UPDATE
-    .style("stroke", "black");
-```
-
-This change is discussed further in [What Makes Software Good](https://medium.com/@mbostock/what-makes-software-good-943557f8a488).
-
-In 3.x, the [*selection*.enter](https://github.com/d3/d3-selection/blob/master/README.md#selection_enter) and [*selection*.exit](https://github.com/d3/d3-selection/blob/master/README.md#selection_exit) methods were undefined until you called *selection*.data, resulting in a TypeError if you attempted to access them. In 4.0, now they simply return the empty selection if the selection has not been joined to data.
-
-In 3.x, [*selection*.append](https://github.com/d3/d3-selection/blob/master/README.md#selection_append) would always append the new element as the last child of its parent. A little-known trick was to use [*selection*.insert](https://github.com/d3/d3-selection/blob/master/README.md#selection_insert) without specifying a *before* selector when entering nodes, causing the entering nodes to be inserted before the following element in the update selection. In 4.0, this is now the default behavior of *selection*.append; if you do not specify a *before* selector to *selection*.insert, the inserted element is appended as the last child. This change makes the general update pattern preserve the relative order of elements and data. For example, given the following DOM:
-
-```html
-<div>a</div>
-<div>b</div>
-<div>f</div>
-```
-
-And the following code:
-
-```js
-var div = d3.select("body").selectAll("div")
-  .data(["a", "b", "c", "d", "e", "f"], function(d) { return d || this.textContent; });
-
-div.enter().append("div")
-    .text(function(d) { return d; });
-```
-
-The resulting DOM will be:
-
-```html
-<div>a</div>
-<div>b</div>
-<div>c</div>
-<div>d</div>
-<div>e</div>
-<div>f</div>
-```
-
-Thus, the entering *c*, *d* and *e* are inserted before *f*, since *f* is the following element in the update selection. Although this behavior is sufficient to preserve order if the new data’s order is stable, if the data changes order, you must still use [*selection*.order](https://github.com/d3/d3-selection/blob/master/README.md#selection_order) to reorder elements.
-
-There is now only one class of selection. 3.x implemented enter selections using a special class with different behavior for *enter*.append and *enter*.select; a consequence of this design was that enter selections in 3.x lacked [certain methods](https://github.com/d3/d3/issues/2043). In 4.0, enter selections are simply normal selections; they have the same methods and the same behavior. Placeholder [enter nodes](https://github.com/d3/d3-selection/blob/master/src/selection/enter.js) now implement [*node*.appendChild](https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild), [*node*.insertBefore](https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore), [*node*.querySelector](https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector), and [*node*.querySelectorAll](https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll).
-
-The [*selection*.data](https://github.com/d3/d3-selection/blob/master/README.md#selection_data) method has been changed slightly with respect to duplicate keys. In 3.x, if multiple data had the same key, the duplicate data would be ignored and not included in enter, update or exit; in 4.0 the duplicate data is always put in the enter selection. In both 3.x and 4.0, if multiple elements have the same key, the duplicate elements are put in the exit selection. Thus, 4.0’s behavior is now symmetric for enter and exit, and the general update pattern will now produce a DOM that matches the data even if there are duplicate keys.
-
-Selections have several new methods! Use [*selection*.raise](https://github.com/d3/d3-selection/blob/master/README.md#selection_raise) to move the selected elements to the front of their siblings, so that they are drawn on top; use [*selection*.lower](https://github.com/d3/d3-selection/blob/master/README.md#selection_lower) to move them to the back. Use [*selection*.dispatch](https://github.com/d3/d3-selection/blob/master/README.md#selection_dispatch) to dispatch a [custom event](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) to event listeners.
-
-When called in getter mode, [*selection*.data](https://github.com/d3/d3-selection/blob/master/README.md#selection_data) now returns the data for all elements in the selection, rather than just the data for the first group of elements. The [*selection*.call](https://github.com/d3/d3-selection/blob/master/README.md#selection_call) method no longer sets the `this` context when invoking the specified function; the *selection* is passed as the first argument to the function, so use that. The [*selection*.on](https://github.com/d3/d3-selection/blob/master/README.md#selection_on) method now accepts multiple whitespace-separated typenames, so you can add or remove multiple listeners simultaneously. For example:
-
-```js
-selection.on("mousedown touchstart", function() {
-  console.log(d3.event.type);
-});
-```
-
-The arguments passed to callback functions has changed slightly in 4.0 to be more consistent. The standard arguments are the element’s datum (*d*), the element’s index (*i*), and the element’s group (*nodes*), with *this* as the element. The slight exception to this convention is *selection*.data, which is evaluated for each group rather than each element; it is passed the group’s parent datum (*d*), the group index (*i*), and the selection’s parents (*parents*), with *this* as the group’s parent.
-
-The new [d3.local](https://github.com/d3/d3-selection/blob/master/README.md#local-variables) provides a mechanism for defining [local variables](https://bl.ocks.org/mbostock/e1192fe405703d8321a5187350910e08): state that is bound to DOM elements, and available to any descendant element. This can be a convenient alternative to using [*selection*.each](https://github.com/d3/d3-selection/blob/master/README.md#selection_each) or storing local state in data.
-
-The d3.ns.prefix namespace prefix map has been renamed to [d3.namespaces](https://github.com/d3/d3-selection/blob/master/README.md#namespaces), and the d3.ns.qualify method has been renamed to [d3.namespace](https://github.com/d3/d3-selection/blob/master/README.md#namespace). Several new low-level methods are now available, as well. [d3.matcher](https://github.com/d3/d3-selection/blob/master/README.md#matcher) is used internally by [*selection*.filter](https://github.com/d3/d3-selection/blob/master/README.md#selection_filter); [d3.selector](https://github.com/d3/d3-selection/blob/master/README.md#selector) is used by [*selection*.select](https://github.com/d3/d3-selection/blob/master/README.md#selection_select); [d3.selectorAll](https://github.com/d3/d3-selection/blob/master/README.md#selectorAll) is used by [*selection*.selectAll](https://github.com/d3/d3-selection/blob/master/README.md#selection_selectAll); [d3.creator](https://github.com/d3/d3-selection/blob/master/README.md#creator) is used by [*selection*.append](https://github.com/d3/d3-selection/blob/master/README.md#selection_append) and [*selection*.insert](https://github.com/d3/d3-selection/blob/master/README.md#selection_insert). The new [d3.window](https://github.com/d3/d3-selection/blob/master/README.md#window) returns the owner window for a given element, window or document. The new [d3.customEvent](https://github.com/d3/d3-selection/blob/master/README.md#customEvent) temporarily sets [d3.event](https://github.com/d3/d3-selection/blob/master/README.md#event) while invoking a function, allowing you to implement controls which dispatch custom events; this is used by [d3-drag](https://github.com/d3/d3-drag), [d3-zoom](https://github.com/d3/d3-zoom) and [d3-brush](https://github.com/d3/d3-brush).
-
-For the sake of parsimony, the multi-value methods—where you pass an object to set multiple attributes, styles or properties simultaneously—have been extracted to [d3-selection-multi](https://github.com/d3/d3-selection-multi) and are no longer part of the default bundle. The multi-value map methods have also been renamed to plural form to reduce overload: [*selection*.attrs](https://github.com/d3/d3-selection-multi/blob/master/README.md#selection_attrs), [*selection*.styles](https://github.com/d3/d3-selection-multi/blob/master/README.md#selection_styles) and [*selection*.properties](https://github.com/d3/d3-selection-multi/blob/master/README.md#selection_properties).
-
-## [Shapes (d3-shape)](https://github.com/d3/d3-shape/blob/master/README.md)
-
-Pursuant to the great namespace flattening:
-
-* d3.svg.line ↦ [d3.line](https://github.com/d3/d3-shape/blob/master/README.md#lines)
-* d3.svg.line.radial ↦ [d3.radialLine](https://github.com/d3/d3-shape/blob/master/README.md#radialLine)
-* d3.svg.area ↦ [d3.area](https://github.com/d3/d3-shape/blob/master/README.md#areas)
-* d3.svg.area.radial ↦ [d3.radialArea](https://github.com/d3/d3-shape/blob/master/README.md#radialArea)
-* d3.svg.arc ↦ [d3.arc](https://github.com/d3/d3-shape/blob/master/README.md#arcs)
-* d3.svg.symbol ↦ [d3.symbol](https://github.com/d3/d3-shape/blob/master/README.md#symbols)
-* d3.svg.symbolTypes ↦ [d3.symbolTypes](https://github.com/d3/d3-shape/blob/master/README.md#symbolTypes)
-* d3.layout.pie ↦ [d3.pie](https://github.com/d3/d3-shape/blob/master/README.md#pies)
-* d3.layout.stack ↦ [d3.stack](https://github.com/d3/d3-shape/blob/master/README.md#stacks)
-* d3.svg.diagonal ↦ REMOVED (see [d3/d3-shape#27](https://github.com/d3/d3-shape/issues/27))
-* d3.svg.diagonal.radial ↦ REMOVED
-
-Shapes are no longer limited to SVG; they can now render to Canvas! Shape generators now support an optional *context*: given a [CanvasRenderingContext2D](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D), you can render a shape as a canvas path to be filled or stroked. For example, a [canvas pie chart](https://bl.ocks.org/mbostock/8878e7fd82034f1d63cf) might use an arc generator:
-
-```js
-var arc = d3.arc()
-    .outerRadius(radius - 10)
-    .innerRadius(0)
-    .context(context);
-```
-
-To render an arc for a given datum *d*:
-
-```js
-context.beginPath();
-arc(d);
-context.fill();
-```
-
-See [*line*.context](https://github.com/d3/d3-shape/blob/master/README.md#line_context), [*area*.context](https://github.com/d3/d3-shape/blob/master/README.md#area_context) and [*arc*.context](https://github.com/d3/d3-shape/blob/master/README.md#arc_context) for more. Under the hood, shapes use [d3-path](#paths-d3-path) to serialize canvas path methods to SVG path data when the context is null; thus, shapes are optimized for rendering to canvas. You can also now derive lines from areas. The line shares most of the same accessors, such as [*line*.defined](https://github.com/d3/d3-shape/blob/master/README.md#line_defined) and [*line*.curve](https://github.com/d3/d3-shape/blob/master/README.md#line_curve), with the area from which it is derived. For example, to render the topline of an area, use [*area*.lineY1](https://github.com/d3/d3-shape/blob/master/README.md#area_lineY1); for the baseline, use [*area*.lineY0](https://github.com/d3/d3-shape/blob/master/README.md#area_lineY0).
-
-4.0 introduces a new curve API for specifying how line and area shapes interpolate between data points. The *line*.interpolate and *area*.interpolate methods have been replaced with [*line*.curve](https://github.com/d3/d3-shape/blob/master/README.md#line_curve) and [*area*.curve](https://github.com/d3/d3-shape/blob/master/README.md#area_curve). Curves are implemented using the [curve interface](https://github.com/d3/d3-shape/blob/master/README.md#custom-curves) rather than as a function that returns an SVG path data string; this allows curves to render to either SVG or Canvas. In addition, *line*.curve and *area*.curve now take a function which instantiates a curve for a given *context*, rather than a string. The full list of equivalents:
-
-* linear ↦ [d3.curveLinear](https://github.com/d3/d3-shape/blob/master/README.md#curveLinear)
-* linear-closed ↦ [d3.curveLinearClosed](https://github.com/d3/d3-shape/blob/master/README.md#curveLinearClosed)
-* step ↦ [d3.curveStep](https://github.com/d3/d3-shape/blob/master/README.md#curveStep)
-* step-before ↦ [d3.curveStepBefore](https://github.com/d3/d3-shape/blob/master/README.md#curveStepBefore)
-* step-after ↦ [d3.curveStepAfter](https://github.com/d3/d3-shape/blob/master/README.md#curveStepAfter)
-* basis ↦ [d3.curveBasis](https://github.com/d3/d3-shape/blob/master/README.md#curveBasis)
-* basis-open ↦ [d3.curveBasisOpen](https://github.com/d3/d3-shape/blob/master/README.md#curveBasisOpen)
-* basis-closed ↦ [d3.curveBasisClosed](https://github.com/d3/d3-shape/blob/master/README.md#curveBasisClosed)
-* bundle ↦ [d3.curveBundle](https://github.com/d3/d3-shape/blob/master/README.md#curveBundle)
-* cardinal ↦ [d3.curveCardinal](https://github.com/d3/d3-shape/blob/master/README.md#curveCardinal)
-* cardinal-open ↦ [d3.curveCardinalOpen](https://github.com/d3/d3-shape/blob/master/README.md#curveCardinalOpen)
-* cardinal-closed ↦ [d3.curveCardinalClosed](https://github.com/d3/d3-shape/blob/master/README.md#curveCardinalClosed)
-* monotone ↦ [d3.curveMonotoneX](https://github.com/d3/d3-shape/blob/master/README.md#curveMonotoneX)
-
-But that’s not all! 4.0 now provides parameterized Catmull–Rom splines as proposed by [Yuksel *et al.*](http://www.cemyuksel.com/research/catmullrom_param/). These are available as [d3.curveCatmullRom](https://github.com/d3/d3-shape/blob/master/README.md#curveCatmullRom), [d3.curveCatmullRomClosed](https://github.com/d3/d3-shape/blob/master/README.md#curveCatmullRomClosed) and [d3.curveCatmullRomOpen](https://github.com/d3/d3-shape/blob/master/README.md#curveCatmullRomOpen).
-
-<img src="https://raw.githubusercontent.com/d3/d3-shape/master/img/catmullRom.png" width="888" height="240" alt="catmullRom">
-<img src="https://raw.githubusercontent.com/d3/d3-shape/master/img/catmullRomOpen.png" width="888" height="240" alt="catmullRomOpen">
-<img src="https://raw.githubusercontent.com/d3/d3-shape/master/img/catmullRomClosed.png" width="888" height="330" alt="catmullRomClosed">
-
-Each curve type can define its own named parameters, replacing *line*.tension and *area*.tension. For example, Catmull–Rom splines are parameterized using [*catmullRom*.alpha](https://github.com/d3/d3-shape/blob/master/README.md#curveCatmullRom_alpha) and defaults to 0.5, which corresponds to a centripetal spline that avoids self-intersections and overshoot. For a uniform Catmull–Rom spline instead:
-
-```js
-var line = d3.line()
-    .curve(d3.curveCatmullRom.alpha(0));
-```
-
-4.0 fixes the interpretation of the cardinal spline *tension* parameter, which is now specified as [*cardinal*.tension](https://github.com/d3/d3-shape/blob/master/README.md#curveCardinal_tension) and defaults to zero for a uniform Catmull–Rom spline; a tension of one produces a linear curve. The first and last segments of basis and cardinal curves have also been fixed! The undocumented *interpolate*.reverse field has been removed. Curves can define different behavior for toplines and baselines by counting the sequence of [*curve*.lineStart](https://github.com/d3/d3-shape/blob/master/README.md#curve_lineStart) within [*curve*.areaStart](https://github.com/d3/d3-shape/blob/master/README.md#curve_areaStart). See the [d3.curveStep implementation](https://github.com/d3/d3-shape/blob/master/src/curve/step.js) for an example.
-
-4.0 fixes numerous bugs in the monotone curve implementation, and introduces [d3.curveMonotoneY](https://github.com/d3/d3-shape/blob/master/README.md#curveMonotoneY); this is like d3.curveMonotoneX, except it requires that the input points are monotone in *y* rather than *x*, such as for a vertically-oriented line chart. The new [d3.curveNatural](https://github.com/d3/d3-shape/blob/master/README.md#curveNatural) produces a [natural cubic spline](http://mathworld.wolfram.com/CubicSpline.html). The default [β](https://github.com/d3/d3-shape/blob/master/README.md#bundle_beta) for [d3.curveBundle](https://github.com/d3/d3-shape/blob/master/README.md#curveBundle) is now 0.85, rather than 0.7, matching the values used by [Holten](https://www.win.tue.nl/vis1/home/dholten/papers/bundles_infovis.pdf). 4.0 also has a more robust implementation of arc padding; see [*arc*.padAngle](https://github.com/d3/d3-shape/blob/master/README.md#arc_padAngle) and [*arc*.padRadius](https://github.com/d3/d3-shape/blob/master/README.md#arc_padRadius).
-
-4.0 introduces a new symbol type API. Symbol types are passed to [*symbol*.type](https://github.com/d3/d3-shape/blob/master/README.md#symbol_type) in place of strings. The equivalents are:
-
-* circle ↦ [d3.symbolCircle](https://github.com/d3/d3-shape/blob/master/README.md#symbolCircle)
-* cross ↦ [d3.symbolCross](https://github.com/d3/d3-shape/blob/master/README.md#symbolCross)
-* diamond ↦ [d3.symbolDiamond](https://github.com/d3/d3-shape/blob/master/README.md#symbolDiamond)
-* square ↦ [d3.symbolSquare](https://github.com/d3/d3-shape/blob/master/README.md#symbolSquare)
-* triangle-down ↦ REMOVED
-* triangle-up ↦ [d3.symbolTriangle](https://github.com/d3/d3-shape/blob/master/README.md#symbolTriangle)
-* ADDED ↦ [d3.symbolStar](https://github.com/d3/d3-shape/blob/master/README.md#symbolStar)
-* ADDED ↦ [d3.symbolWye](https://github.com/d3/d3-shape/blob/master/README.md#symbolWye)
-
-The full set of symbol types is now:
-
-<a href="#symbolCircle"><img src="https://raw.githubusercontent.com/d3/d3-shape/master/img/circle.png" width="100" height="100"></a><a href="#symbolCross"><img src="https://raw.githubusercontent.com/d3/d3-shape/master/img/cross.png" width="100" height="100"></a><a href="#symbolDiamond"><img src="https://raw.githubusercontent.com/d3/d3-shape/master/img/diamond.png" width="100" height="100"></a><a href="#symbolSquare"><img src="https://raw.githubusercontent.com/d3/d3-shape/master/img/square.png" width="100" height="100"></a><a href="#symbolStar"><img src="https://raw.githubusercontent.com/d3/d3-shape/master/img/star.png" width="100" height="100"></a><a href="#symbolTriangle"><img src="https://raw.githubusercontent.com/d3/d3-shape/master/img/triangle.png" width="100" height="100"><a href="#symbolWye"><img src="https://raw.githubusercontent.com/d3/d3-shape/master/img/wye.png" width="100" height="100"></a>
-
-Lastly, 4.0 overhauls the stack layout API, replacing d3.layout.stack with [d3.stack](https://github.com/d3/d3-shape/blob/master/README.md#stacks). The stack generator no longer needs an *x*-accessor. In addition, the API has been simplified: the *stack* generator now accepts tabular input, such as this array of objects:
-
-```js
-var data = [
-  {month: new Date(2015, 0, 1), apples: 3840, bananas: 1920, cherries: 960, dates: 400},
-  {month: new Date(2015, 1, 1), apples: 1600, bananas: 1440, cherries: 960, dates: 400},
-  {month: new Date(2015, 2, 1), apples:  640, bananas:  960, cherries: 640, dates: 400},
-  {month: new Date(2015, 3, 1), apples:  320, bananas:  480, cherries: 640, dates: 400}
-];
-```
-
-To generate the stack layout, first define a stack generator, and then apply it to the data:
-
-```js
-var stack = d3.stack()
-    .keys(["apples", "bananas", "cherries", "dates"])
-    .order(d3.stackOrderNone)
-    .offset(d3.stackOffsetNone);
-
-var series = stack(data);
-```
-
-The resulting array has one element per *series*. Each series has one point per month, and each point has a lower and upper value defining the baseline and topline:
-
-```js
-[
-  [[   0, 3840], [   0, 1600], [   0,  640], [   0,  320]], // apples
-  [[3840, 5760], [1600, 3040], [ 640, 1600], [ 320,  800]], // bananas
-  [[5760, 6720], [3040, 4000], [1600, 2240], [ 800, 1440]], // cherries
-  [[6720, 7120], [4000, 4400], [2240, 2640], [1440, 1840]], // dates
-]
-```
-
-Each series in then typically passed to an [area generator](https://github.com/d3/d3-shape/blob/master/README.md#areas) to render an area chart, or used to construct rectangles for a bar chart. Stack generators no longer modify the input data, so *stack*.out has been removed.
-
-For an introduction to shapes, see [Introducing d3-shape](https://medium.com/@mbostock/introducing-d3-shape-73f8367e6d12).
-
-## [Time Formats (d3-time-format)](https://github.com/d3/d3-time-format/blob/master/README.md)
-
-Pursuant to the great namespace flattening, the format constructors have new names:
-
-* d3.time.format ↦ [d3.timeFormat](https://github.com/d3/d3-time-format/blob/master/README.md#timeFormat)
-* d3.time.format.utc ↦ [d3.utcFormat](https://github.com/d3/d3-time-format/blob/master/README.md#utcFormat)
-* d3.time.format.iso ↦ [d3.isoFormat](https://github.com/d3/d3-time-format/blob/master/README.md#isoFormat)
-
-The *format*.parse method has also been removed in favor of separate [d3.timeParse](https://github.com/d3/d3-time-format/blob/master/README.md#timeParse), [d3.utcParse](https://github.com/d3/d3-time-format/blob/master/README.md#utcParse) and [d3.isoParse](https://github.com/d3/d3-time-format/blob/master/README.md#isoParse) parser constructors. Thus, this code in 3.x:
-
-```js
-var parseTime = d3.time.format("%c").parse;
-```
-
-Can be rewritten in 4.0 as:
-
-```js
-var parseTime = d3.timeParse("%c");
-```
-
-The multi-scale time format d3.time.format.multi has been replaced by [d3.scaleTime](https://github.com/d3/d3-scale/blob/master/README.md#scaleTime)’s [tick format](https://github.com/d3/d3-scale/blob/master/README.md#time_tickFormat). Time formats now coerce inputs to dates, and time parsers coerce inputs to strings. The `%Z` directive now allows more flexible parsing of time zone offsets, such as `-0700`, `-07:00`, `-07`, and `Z`. The `%p` directive is now parsed correctly when the locale’s period name is longer than two characters (*e.g.*, “a.m.”).
-
-The default U.S. English locale now uses 12-hour time and a more concise representation of the date. This aligns with local convention and is consistent with [*date*.toLocaleString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString) in Chrome, Firefox and Node:
-
-```js
-var now = new Date;
-d3.timeFormat("%c")(new Date); // "6/23/2016, 2:01:33 PM"
-d3.timeFormat("%x")(new Date); // "6/23/2016"
-d3.timeFormat("%X")(new Date); // "2:01:38 PM"
-```
-
-You can now set the default locale using [d3.timeFormatDefaultLocale](https://github.com/d3/d3-time-format/blob/master/README.md#timeFormatDefaultLocale)! The locales are published as [JSON](https://github.com/d3/d3-request/blob/master/README.md#json) to [npm](https://unpkg.com/d3-time-format/locale/).
-
-The performance of time formatting and parsing has been improved, and the UTC formatter and parser have a cleaner implementation (that avoids temporarily overriding the Date global).
-
-## [Time Intervals (d3-time)](https://github.com/d3/d3-time/blob/master/README.md)
-
-Pursuant to the great namespace flattening, the local time intervals have been renamed:
-
-* ADDED ↦ [d3.timeMillisecond](https://github.com/d3/d3-time/blob/master/README.md#timeMillisecond)
-* d3.time.second ↦ [d3.timeSecond](https://github.com/d3/d3-time/blob/master/README.md#timeSecond)
-* d3.time.minute ↦ [d3.timeMinute](https://github.com/d3/d3-time/blob/master/README.md#timeMinute)
-* d3.time.hour ↦ [d3.timeHour](https://github.com/d3/d3-time/blob/master/README.md#timeHour)
-* d3.time.day ↦ [d3.timeDay](https://github.com/d3/d3-time/blob/master/README.md#timeDay)
-* d3.time.sunday ↦ [d3.timeSunday](https://github.com/d3/d3-time/blob/master/README.md#timeSunday)
-* d3.time.monday ↦ [d3.timeMonday](https://github.com/d3/d3-time/blob/master/README.md#timeMonday)
-* d3.time.tuesday ↦ [d3.timeTuesday](https://github.com/d3/d3-time/blob/master/README.md#timeTuesday)
-* d3.time.wednesday ↦ [d3.timeWednesday](https://github.com/d3/d3-time/blob/master/README.md#timeWednesday)
-* d3.time.thursday ↦ [d3.timeThursday](https://github.com/d3/d3-time/blob/master/README.md#timeThursday)
-* d3.time.friday ↦ [d3.timeFriday](https://github.com/d3/d3-time/blob/master/README.md#timeFriday)
-* d3.time.saturday ↦ [d3.timeSaturday](https://github.com/d3/d3-time/blob/master/README.md#timeSaturday)
-* d3.time.week ↦ [d3.timeWeek](https://github.com/d3/d3-time/blob/master/README.md#timeWeek)
-* d3.time.month ↦ [d3.timeMonth](https://github.com/d3/d3-time/blob/master/README.md#timeMonth)
-* d3.time.year ↦ [d3.timeYear](https://github.com/d3/d3-time/blob/master/README.md#timeYear)
-
-The UTC time intervals have likewise been renamed:
-
-* ADDED ↦ [d3.utcMillisecond](https://github.com/d3/d3-time/blob/master/README.md#utcMillisecond)
-* d3.time.second.utc ↦ [d3.utcSecond](https://github.com/d3/d3-time/blob/master/README.md#utcSecond)
-* d3.time.minute.utc ↦ [d3.utcMinute](https://github.com/d3/d3-time/blob/master/README.md#utcMinute)
-* d3.time.hour.utc ↦ [d3.utcHour](https://github.com/d3/d3-time/blob/master/README.md#utcHour)
-* d3.time.day.utc ↦ [d3.utcDay](https://github.com/d3/d3-time/blob/master/README.md#utcDay)
-* d3.time.sunday.utc ↦ [d3.utcSunday](https://github.com/d3/d3-time/blob/master/README.md#utcSunday)
-* d3.time.monday.utc ↦ [d3.utcMonday](https://github.com/d3/d3-time/blob/master/README.md#utcMonday)
-* d3.time.tuesday.utc ↦ [d3.utcTuesday](https://github.com/d3/d3-time/blob/master/README.md#utcTuesday)
-* d3.time.wednesday.utc ↦ [d3.utcWednesday](https://github.com/d3/d3-time/blob/master/README.md#utcWednesday)
-* d3.time.thursday.utc ↦ [d3.utcThursday](https://github.com/d3/d3-time/blob/master/README.md#utcThursday)
-* d3.time.friday.utc ↦ [d3.utcFriday](https://github.com/d3/d3-time/blob/master/README.md#utcFriday)
-* d3.time.saturday.utc ↦ [d3.utcSaturday](https://github.com/d3/d3-time/blob/master/README.md#utcSaturday)
-* d3.time.week.utc ↦ [d3.utcWeek](https://github.com/d3/d3-time/blob/master/README.md#utcWeek)
-* d3.time.month.utc ↦ [d3.utcMonth](https://github.com/d3/d3-time/blob/master/README.md#utcMonth)
-* d3.time.year.utc ↦ [d3.utcYear](https://github.com/d3/d3-time/blob/master/README.md#utcYear)
-
-The local time range aliases have been renamed:
-
-* d3.time.seconds ↦ [d3.timeSeconds](https://github.com/d3/d3-time/blob/master/README.md#timeSeconds)
-* d3.time.minutes ↦ [d3.timeMinutes](https://github.com/d3/d3-time/blob/master/README.md#timeMinutes)
-* d3.time.hours ↦ [d3.timeHours](https://github.com/d3/d3-time/blob/master/README.md#timeHours)
-* d3.time.days ↦ [d3.timeDays](https://github.com/d3/d3-time/blob/master/README.md#timeDays)
-* d3.time.sundays ↦ [d3.timeSundays](https://github.com/d3/d3-time/blob/master/README.md#timeSundays)
-* d3.time.mondays ↦ [d3.timeMondays](https://github.com/d3/d3-time/blob/master/README.md#timeMondays)
-* d3.time.tuesdays ↦ [d3.timeTuesdays](https://github.com/d3/d3-time/blob/master/README.md#timeTuesdays)
-* d3.time.wednesdays ↦ [d3.timeWednesdays](https://github.com/d3/d3-time/blob/master/README.md#timeWednesdays)
-* d3.time.thursdays ↦ [d3.timeThursdays](https://github.com/d3/d3-time/blob/master/README.md#timeThursdays)
-* d3.time.fridays ↦ [d3.timeFridays](https://github.com/d3/d3-time/blob/master/README.md#timeFridays)
-* d3.time.saturdays ↦ [d3.timeSaturdays](https://github.com/d3/d3-time/blob/master/README.md#timeSaturdays)
-* d3.time.weeks ↦ [d3.timeWeeks](https://github.com/d3/d3-time/blob/master/README.md#timeWeeks)
-* d3.time.months ↦ [d3.timeMonths](https://github.com/d3/d3-time/blob/master/README.md#timeMonths)
-* d3.time.years ↦ [d3.timeYears](https://github.com/d3/d3-time/blob/master/README.md#timeYears)
-
-The UTC time range aliases have been renamed:
-
-* d3.time.seconds.utc ↦ [d3.utcSeconds](https://github.com/d3/d3-time/blob/master/README.md#utcSeconds)
-* d3.time.minutes.utc ↦ [d3.utcMinutes](https://github.com/d3/d3-time/blob/master/README.md#utcMinutes)
-* d3.time.hours.utc ↦ [d3.utcHours](https://github.com/d3/d3-time/blob/master/README.md#utcHours)
-* d3.time.days.utc ↦ [d3.utcDays](https://github.com/d3/d3-time/blob/master/README.md#utcDays)
-* d3.time.sundays.utc ↦ [d3.utcSundays](https://github.com/d3/d3-time/blob/master/README.md#utcSundays)
-* d3.time.mondays.utc ↦ [d3.utcMondays](https://github.com/d3/d3-time/blob/master/README.md#utcMondays)
-* d3.time.tuesdays.utc ↦ [d3.utcTuesdays](https://github.com/d3/d3-time/blob/master/README.md#utcTuesdays)
-* d3.time.wednesdays.utc ↦ [d3.utcWednesdays](https://github.com/d3/d3-time/blob/master/README.md#utcWednesdays)
-* d3.time.thursdays.utc ↦ [d3.utcThursdays](https://github.com/d3/d3-time/blob/master/README.md#utcThursdays)
-* d3.time.fridays.utc ↦ [d3.utcFridays](https://github.com/d3/d3-time/blob/master/README.md#utcFridays)
-* d3.time.saturdays.utc ↦ [d3.utcSaturdays](https://github.com/d3/d3-time/blob/master/README.md#utcSaturdays)
-* d3.time.weeks.utc ↦ [d3.utcWeeks](https://github.com/d3/d3-time/blob/master/README.md#utcWeeks)
-* d3.time.months.utc ↦ [d3.utcMonths](https://github.com/d3/d3-time/blob/master/README.md#utcMonths)
-* d3.time.years.utc ↦ [d3.utcYears](https://github.com/d3/d3-time/blob/master/README.md#utcYears)
-
-The behavior of [*interval*.range](https://github.com/d3/d3-time/blob/master/README.md#interval_range) (and the convenience aliases such as [d3.timeDays](https://github.com/d3/d3-time/blob/master/README.md#timeDays)) has been changed when *step* is greater than one. Rather than filtering the returned dates using the field number, *interval*.range now behaves like [d3.range](https://github.com/d3/d3-array/blob/master/README.md#range): it simply skips, returning every *step*th date. For example, the following code in 3.x returns only odd days of the month:
-
-```js
-d3.time.days(new Date(2016, 4, 28), new Date(2016, 5, 5), 2);
-// [Sun May 29 2016 00:00:00 GMT-0700 (PDT),
-//  Tue May 31 2016 00:00:00 GMT-0700 (PDT),
-//  Wed Jun 01 2016 00:00:00 GMT-0700 (PDT),
-//  Fri Jun 03 2016 00:00:00 GMT-0700 (PDT)]
-```
-
-Note the returned array of dates does not start on the *start* date because May 28 is even. Also note that May 31 and June 1 are one day apart, not two! The behavior of d3.timeDays in 4.0 is probably closer to what you expect:
-
-```js
-d3.timeDays(new Date(2016, 4, 28), new Date(2016, 5, 5), 2);
-// [Sat May 28 2016 00:00:00 GMT-0700 (PDT),
-//  Mon May 30 2016 00:00:00 GMT-0700 (PDT),
-//  Wed Jun 01 2016 00:00:00 GMT-0700 (PDT),
-//  Fri Jun 03 2016 00:00:00 GMT-0700 (PDT)]
-```
-
-If you want a filtered view of a time interval (say to guarantee that two overlapping ranges are consistent, such as when generating [time scale ticks](https://github.com/d3/d3-scale/blob/master/README.md#time_ticks)), you can use the new [*interval*.every](https://github.com/d3/d3-time/blob/master/README.md#interval_every) method or its more general cousin [*interval*.filter](https://github.com/d3/d3-time/blob/master/README.md#interval_filter):
-
-```js
-d3.timeDay.every(2).range(new Date(2016, 4, 28), new Date(2016, 5, 5));
-// [Sun May 29 2016 00:00:00 GMT-0700 (PDT),
-//  Tue May 31 2016 00:00:00 GMT-0700 (PDT),
-//  Wed Jun 01 2016 00:00:00 GMT-0700 (PDT),
-//  Fri Jun 03 2016 00:00:00 GMT-0700 (PDT)]
-```
-
-Time intervals now expose an [*interval*.count](https://github.com/d3/d3-time/blob/master/README.md#interval_count) method for counting the number of interval boundaries after a *start* date and before or equal to an *end* date. This replaces d3.time.dayOfYear and related methods in 3.x. For example, this code in 3.x:
-
-```js
-var now = new Date;
-d3.time.dayOfYear(now); // 165
-```
-
-Can be rewritten in 4.0 as:
-
-```js
-var now = new Date;
-d3.timeDay.count(d3.timeYear(now), now); // 165
-```
-
-Likewise, in place of 3.x’s d3.time.weekOfYear, in 4.0 you would say:
-
-```js
-d3.timeWeek.count(d3.timeYear(now), now); // 24
-```
-
-The new *interval*.count is of course more general. For example, you can use it to compute hour-of-week for a heatmap:
-
-```js
-d3.timeHour.count(d3.timeWeek(now), now); // 64
-```
-
-Here are all the equivalences from 3.x to 4.0:
-
-* d3.time.dayOfYear ↦ [d3.timeDay](https://github.com/d3/d3-time/blob/master/README.md#timeDay).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.sundayOfYear ↦ [d3.timeSunday](https://github.com/d3/d3-time/blob/master/README.md#timeSunday).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.mondayOfYear ↦ [d3.timeMonday](https://github.com/d3/d3-time/blob/master/README.md#timeMonday).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.tuesdayOfYear ↦ [d3.timeTuesday](https://github.com/d3/d3-time/blob/master/README.md#timeTuesday).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.wednesdayOfYear ↦ [d3.timeWednesday](https://github.com/d3/d3-time/blob/master/README.md#timeWednesday).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.thursdayOfYear ↦ [d3.timeThursday](https://github.com/d3/d3-time/blob/master/README.md#timeThursday).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.fridayOfYear ↦ [d3.timeFriday](https://github.com/d3/d3-time/blob/master/README.md#timeFriday).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.saturdayOfYear ↦ [d3.timeSaturday](https://github.com/d3/d3-time/blob/master/README.md#timeSaturday).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.weekOfYear ↦ [d3.timeWeek](https://github.com/d3/d3-time/blob/master/README.md#timeWeek).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.dayOfYear.utc ↦ [d3.utcDay](https://github.com/d3/d3-time/blob/master/README.md#utcDay).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.sundayOfYear.utc ↦ [d3.utcSunday](https://github.com/d3/d3-time/blob/master/README.md#utcSunday).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.mondayOfYear.utc ↦ [d3.utcMonday](https://github.com/d3/d3-time/blob/master/README.md#utcMonday).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.tuesdayOfYear.utc ↦ [d3.utcTuesday](https://github.com/d3/d3-time/blob/master/README.md#utcTuesday).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.wednesdayOfYear.utc ↦ [d3.utcWednesday](https://github.com/d3/d3-time/blob/master/README.md#utcWednesday).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.thursdayOfYear.utc ↦ [d3.utcThursday](https://github.com/d3/d3-time/blob/master/README.md#utcThursday).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.fridayOfYear.utc ↦ [d3.utcFriday](https://github.com/d3/d3-time/blob/master/README.md#utcFriday).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.saturdayOfYear.utc ↦ [d3.utcSaturday](https://github.com/d3/d3-time/blob/master/README.md#utcSaturday).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-* d3.time.weekOfYear.utc ↦ [d3.utcWeek](https://github.com/d3/d3-time/blob/master/README.md#utcWeek).[count](https://github.com/d3/d3-time/blob/master/README.md#interval_count)
-
-D3 4.0 now also lets you define custom time intervals using [d3.timeInterval](https://github.com/d3/d3-time/blob/master/README.md#timeInterval). The [d3.timeYear](https://github.com/d3/d3-time/blob/master/README.md#timeYear), [d3.utcYear](https://github.com/d3/d3-time/blob/master/README.md#utcYear), [d3.timeMillisecond](https://github.com/d3/d3-time/blob/master/README.md#timeMillisecond) and [d3.utcMillisecond](https://github.com/d3/d3-time/blob/master/README.md#utcMillisecond) intervals have optimized implementations of [*interval*.every](https://github.com/d3/d3-time/blob/master/README.md#interval_every), which is necessary to generate time ticks for very large or very small domains efficiently. More generally, the performance of time intervals has been improved, and time intervals now do a better job with respect to daylight savings in various locales.
-
-## [Timers (d3-timer)](https://github.com/d3/d3-timer/blob/master/README.md)
-
-In D3 3.x, the only way to stop a timer was for its callback to return true. For example, this timer stops after one second:
-
-```js
-d3.timer(function(elapsed) {
-  console.log(elapsed);
-  return elapsed >= 1000;
-});
-```
-
-In 4.0, use [*timer*.stop](https://github.com/d3/d3-timer/blob/master/README.md#timer_stop) instead:
-
-```js
-var t = d3.timer(function(elapsed) {
-  console.log(elapsed);
-  if (elapsed >= 1000) {
-    t.stop();
-  }
-});
-```
-
-The primary benefit of *timer*.stop is that timers are not required to self-terminate: they can be stopped externally, allowing for the immediate and synchronous disposal of associated resources, and the separation of concerns. The above is equivalent to:
-
-```js
-var t = d3.timer(function(elapsed) {
-  console.log(elapsed);
-});
-
-d3.timeout(function() {
-  t.stop();
-}, 1000);
-```
-
-This improvement extends to [d3-transition](#transitions-d3-transition): now when a transition is interrupted, its resources are immediately freed rather than having to wait for transition to start.
-
-4.0 also introduces a new [*timer*.restart](https://github.com/d3/d3-timer/blob/master/README.md#timer_restart) method for restarting timers, for replacing the callback of a running timer, or for changing its delay or reference time. Unlike *timer*.stop followed by [d3.timer](https://github.com/d3/d3-timer/blob/master/README.md#timer), *timer*.restart maintains the invocation priority of an existing timer: it guarantees that the order of invocation of active timers remains the same. The d3.timer.flush method has been renamed to [d3.timerFlush](https://github.com/d3/d3-timer/blob/master/README.md#timerFlush).
-
-Some usage patterns in D3 3.x could cause the browser to hang when a background page returned to the foreground. For example, the following code schedules a transition every second:
-
-```js
-setInterval(function() {
-  d3.selectAll("div").transition().call(someAnimation); // BAD
-}, 1000);
-```
-
-If such code runs in the background for hours, thousands of queued transitions will try to run simultaneously when the page is foregrounded. D3 4.0 avoids this hang by freezing time in the background: when a page is in the background, time does not advance, and so no queue of timers accumulates to run when the page returns to the foreground. Use d3.timer instead of transitions to schedule a long-running animation, or use [d3.timeout](https://github.com/d3/d3-timer/blob/master/README.md#timeout) and [d3.interval](https://github.com/d3/d3-timer/blob/master/README.md#interval) in place of setTimeout and setInterval to prevent transitions from being queued in the background:
-
-```js
-d3.interval(function() {
-  d3.selectAll("div").transition().call(someAnimation); // GOOD
-}, 1000);
-```
-
-By freezing time in the background, timers are effectively “unaware” of being backgrounded. It’s like nothing happened! 4.0 also now uses high-precision time ([performance.now](https://developer.mozilla.org/en-US/docs/Web/API/Performance/now)) where available; the current time is available as [d3.now](https://github.com/d3/d3-timer/blob/master/README.md#now).
-
-## [Transitions (d3-transition)](https://github.com/d3/d3-transition/blob/master/README.md)
-
-The [*selection*.transition](https://github.com/d3/d3-transition/blob/master/README.md#selection_transition) method now takes an optional *transition* instance which can be used to synchronize a new transition with an existing transition. (This change is discussed further in [What Makes Software Good?](https://medium.com/@mbostock/what-makes-software-good-943557f8a488)) For example:
-
-```js
-var t = d3.transition()
-    .duration(750)
-    .ease(d3.easeLinear);
-
-d3.selectAll(".apple").transition(t)
-    .style("fill", "red");
-
-d3.selectAll(".orange").transition(t)
-    .style("fill", "orange");
-```
-
-Transitions created this way inherit timing from the closest ancestor element, and thus are synchronized even when the referenced *transition* has variable timing such as a staggered delay. This method replaces the deeply magical behavior of *transition*.each in 3.x; in 4.0, [*transition*.each](https://github.com/d3/d3-transition/blob/master/README.md#transition_each) is identical to [*selection*.each](https://github.com/d3/d3-selection/blob/master/README.md#selection_each). Use the new [*transition*.on](https://github.com/d3/d3-transition/blob/master/README.md#transition_on) method to listen to transition events.
-
-The meaning of [*transition*.delay](https://github.com/d3/d3-transition/blob/master/README.md#transition_delay) has changed for chained transitions created by [*transition*.transition](https://github.com/d3/d3-transition/blob/master/README.md#transition_transition). The specified delay is now relative to the *previous* transition in the chain, rather than the *first* transition in the chain; this makes it easier to insert interstitial pauses. For example:
-
-```js
-d3.selectAll(".apple")
-  .transition() // First fade to green.
-    .style("fill", "green")
-  .transition() // Then red.
-    .style("fill", "red")
-  .transition() // Wait one second. Then brown, and remove.
-    .delay(1000)
-    .style("fill", "brown")
-    .remove();
-```
-
-Time is now frozen in the background; see [d3-timer](#timers-d3-timer) for more information. While it was previously the case that transitions did not run in the background, now they pick up where they left off when the page returns to the foreground. This avoids page hangs by not scheduling an unbounded number of transitions in the background. If you want to schedule an infinitely-repeating transition, use transition events, or use [d3.timeout](https://github.com/d3/d3-timer/blob/master/README.md#timeout) and [d3.interval](https://github.com/d3/d3-timer/blob/master/README.md#interval) in place of [setTimeout](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout) and [setInterval](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval).
-
-The [*selection*.interrupt](https://github.com/d3/d3-transition/blob/master/README.md#selection_interrupt) method now cancels all scheduled transitions on the selected elements, in addition to interrupting any active transition. When transitions are interrupted, any resources associated with the transition are now released immediately, rather than waiting until the transition starts, improving performance. (See also [*timer*.stop](https://github.com/d3/d3-timer/blob/master/README.md#timer_stop).) The new [d3.interrupt](https://github.com/d3/d3-transition/blob/master/README.md#interrupt) method is an alternative to [*selection*.interrupt](https://github.com/d3/d3-transition/blob/master/README.md#selection_interrupt) for quickly interrupting a single node.
-
-The new [d3.active](https://github.com/d3/d3-transition/blob/master/README.md#active) method allows you to select the currently-active transition on a given *node*, if any. This is useful for modifying in-progress transitions and for scheduling infinitely-repeating transitions. For example, this transition continuously oscillates between red and blue:
-
-```js
-d3.select("circle")
-  .transition()
-    .on("start", function repeat() {
-        d3.active(this)
-            .style("fill", "red")
-          .transition()
-            .style("fill", "blue")
-          .transition()
-            .on("start", repeat);
-      });
-```
-
-The [life cycle of a transition](https://github.com/d3/d3-transition/blob/master/README.md#the-life-of-a-transition) is now more formally defined and enforced. For example, attempting to change the duration of a running transition now throws an error rather than silently failing. The [*transition*.remove](https://github.com/d3/d3-transition/blob/master/README.md#transition_remove) method has been fixed if multiple transition names are in use: the element is only removed if it has no scheduled transitions, regardless of name. The [*transition*.ease](https://github.com/d3/d3-transition/blob/master/README.md#transition_ease) method now always takes an [easing function](#easings-d3-ease), not a string. When a transition ends, the tweens are invoked one last time with *t* equal to exactly 1, regardless of the associated easing function.
-
-As with [selections](#selections-d3-selection) in 4.0, all transition callback functions now receive the standard arguments: the element’s datum (*d*), the element’s index (*i*), and the element’s group (*nodes*), with *this* as the element. This notably affects [*transition*.attrTween](https://github.com/d3/d3-transition/blob/master/README.md#transition_attrTween) and [*transition*.styleTween](https://github.com/d3/d3-transition/blob/master/README.md#transition_styleTween), which no longer pass the *tween* function the current attribute or style value as the third argument. The *transition*.attrTween and *transition*.styleTween methods can now be called in getter modes for debugging or to share tween definitions between transitions.
-
-Homogenous transitions are now optimized! If all elements in a transition share the same tween, interpolator, or event listeners, this state is now shared across the transition rather than separately allocated for each element. 4.0 also uses an optimized default interpolator in place of [d3.interpolate](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolate) for [*transition*.attr](https://github.com/d3/d3-transition/blob/master/README.md#transition_attr) and [*transition*.style](https://github.com/d3/d3-transition/blob/master/README.md#transition_style). And transitions can now interpolate both [CSS](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateTransformCss) and [SVG](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateTransformSvg) transforms.
-
-For reusable components that support transitions, such as [axes](#axes-d3-axis), a new [*transition*.selection](https://github.com/d3/d3-transition/blob/master/README.md#transition_selection) method returns the [selection](#selections-d3-selection) that corresponds to a given transition. There is also a new [*transition*.merge](https://github.com/d3/d3-transition/blob/master/README.md#transition_merge) method that is equivalent to [*selection*.merge](https://github.com/d3/d3-selection/blob/master/README.md#selection_merge).
-
-For the sake of parsimony, the multi-value map methods have been extracted to [d3-selection-multi](https://github.com/d3/d3-selection-multi) and are no longer part of the default bundle. The multi-value map methods have also been renamed to plural form to reduce overload: [*transition*.attrs](https://github.com/d3/d3-selection-multi/blob/master/README.md#transition_attrs) and [*transition*.styles](https://github.com/d3/d3-selection-multi/blob/master/README.md#transition_styles).
-
-## [Voronoi Diagrams (d3-voronoi)](https://github.com/d3/d3-voronoi/blob/master/README.md)
-
-The d3.geom.voronoi method has been renamed to [d3.voronoi](https://github.com/d3/d3-voronoi/blob/master/README.md#voronoi), and the *voronoi*.clipExtent method has been renamed to [*voronoi*.extent](https://github.com/d3/d3-voronoi/blob/master/README.md#voronoi_extent). The undocumented *polygon*.point property in 3.x, which is the element in the input *data* corresponding to the polygon, has been renamed to *polygon*.data.
-
-Calling [*voronoi*](https://github.com/d3/d3-voronoi/blob/master/README.md#_voronoi) now returns the full [Voronoi diagram](https://github.com/d3/d3-voronoi/blob/master/README.md#voronoi-diagrams), which includes topological information: each Voronoi edge exposes *edge*.left and *edge*.right specifying the sites on either side of the edge, and each Voronoi cell is defined as an array of these edges and a corresponding site. The Voronoi diagram can be used to efficiently compute both the Voronoi and Delaunay tessellations for a set of points: [*diagram*.polygons](https://github.com/d3/d3-voronoi/blob/master/README.md#diagram_polygons), [*diagram*.links](https://github.com/d3/d3-voronoi/blob/master/README.md#diagram_links), and [*diagram*.triangles](https://github.com/d3/d3-voronoi/blob/master/README.md#diagram_triangles). The new topology is also useful in conjunction with TopoJSON; see the [Voronoi topology example](https://bl.ocks.org/mbostock/cd52a201d7694eb9d890).
-
-The [*voronoi*.polygons](https://github.com/d3/d3-voronoi/blob/master/README.md#voronoi_polygons) and [*diagram*.polygons](https://github.com/d3/d3-voronoi/blob/master/README.md#diagram_polygons) now require an [extent](https://github.com/d3/d3-voronoi/blob/master/README.md#voronoi_extent); there is no longer an implicit extent of ±1e6. The [*voronoi*.links](https://github.com/d3/d3-voronoi/blob/master/README.md#voronoi_links), [*voronoi*.triangles](https://github.com/d3/d3-voronoi/blob/master/README.md#voronoi_triangles), [*diagram*.links](https://github.com/d3/d3-voronoi/blob/master/README.md#diagram_links) and [*diagram*.triangles](https://github.com/d3/d3-voronoi/blob/master/README.md#diagram_triangles) are now affected by the clip extent: as the Delaunay is computed as the dual of the Voronoi, two sites are only linked if the clipped cells are touching. To compute the Delaunay triangulation without respect to clipping, set the extent to null.
-
-The Voronoi generator finally has well-defined behavior for coincident vertices: the first of a set of coincident points has a defined cell, while the subsequent duplicate points have null cells. The returned array of polygons is sparse, so by using *array*.forEach or *array*.map, you can easily skip undefined cells. The Voronoi generator also now correctly handles the case where no cell edges intersect the extent.
-
-## [Zooming (d3-zoom)](https://github.com/d3/d3-zoom/blob/master/README.md)
-
-The zoom behavior d3.behavior.zoom has been renamed to d3.zoom. Zoom behaviors no longer store the active zoom transform (*i.e.*, the visible region; the scale and translate) internally. The zoom transform is now stored on any elements to which the zoom behavior has been applied. The zoom transform is available as *event*.transform within a zoom event or by calling [d3.zoomTransform](https://github.com/d3/d3-zoom/blob/master/README.md#zoomTransform) on a given *element*. To zoom programmatically, use [*zoom*.transform](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_transform) with a given [selection](#selections-d3-selection) or [transition](#transitions-d3-transition); see the [zoom transitions example](https://bl.ocks.org/mbostock/b783fbb2e673561d214e09c7fb5cedee). The *zoom*.event method has been removed.
-
-To make programmatic zooming easier, there are several new convenience methods on top of *zoom*.transform: [*zoom*.translateBy](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_translateBy), [*zoom*.scaleBy](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_scaleBy) and [*zoom*.scaleTo](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_scaleTo). There is also a new API for describing [zoom transforms](https://github.com/d3/d3-zoom/blob/master/README.md#zoom-transforms). Zoom behaviors are no longer dependent on [scales](#scales-d3-scale), but you can use [*transform*.rescaleX](https://github.com/d3/d3-zoom/blob/master/README.md#transform_rescaleX), [*transform*.rescaleY](https://github.com/d3/d3-zoom/blob/master/README.md#transform_rescaleY), [*transform*.invertX](https://github.com/d3/d3-zoom/blob/master/README.md#transform_invertX) or [*transform*.invertY](https://github.com/d3/d3-zoom/blob/master/README.md#transform_invertY) to transform a scale’s domain. 3.x’s *event*.scale is replaced with *event*.transform.k, and *event*.translate is replaced with *event*.transform.x and *event*.transform.y. The *zoom*.center method has been removed in favor of programmatic zooming.
-
-The zoom behavior finally supports simple constraints on panning! The new [*zoom*.translateExtent](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_translateExtent) lets you define the viewable extent of the world: the currently-visible extent (the extent of the viewport, as defined by [*zoom*.extent](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_extent)) is always contained within the translate extent. The *zoom*.size method has been replaced by *zoom*.extent, and the default behavior is now smarter: it defaults to the extent of the zoom behavior’s owner element, rather than being hardcoded to 960×500. (This also improves the default path chosen during smooth zoom transitions!)
-
-The zoom behavior’s interaction has also improved. It now correctly handles concurrent wheeling and dragging, as well as concurrent touching and mousing. The zoom behavior now ignores wheel events at the limits of its scale extent, allowing you to scroll past a zoomable area. The *zoomstart* and *zoomend* events have been renamed *start* and *end*. By default, zoom behaviors now ignore right-clicks intended for the context menu; use [*zoom*.filter](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_filter) to control which events are ignored. The zoom behavior also ignores emulated mouse events on iOS. The zoom behavior now consumes handled events, making it easier to combine with other interactive behaviors such as [dragging](#dragging-d3-drag).
diff --git a/third_party/d3/src/LICENSE b/third_party/d3/src/LICENSE
index 1d9d875e..3594fffa 100644
--- a/third_party/d3/src/LICENSE
+++ b/third_party/d3/src/LICENSE
@@ -1,27 +1,13 @@
-Copyright 2010-2017 Mike Bostock
-All rights reserved.
+Copyright 2010-2023 Mike Bostock
 
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
+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.
 
-* 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 author nor the names of 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 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.
diff --git a/third_party/d3/src/README.md b/third_party/d3/src/README.md
index 4fa9c4a..e1799925 100644
--- a/third_party/d3/src/README.md
+++ b/third_party/d3/src/README.md
@@ -7,32 +7,49 @@
 ## Resources
 
 * [Introduction](https://observablehq.com/@d3/learn-d3)
-* [API Reference](https://github.com/d3/d3/blob/master/API.md)
+* [API Reference](https://github.com/d3/d3/blob/main/API.md)
 * [Releases](https://github.com/d3/d3/releases)
 * [Examples](https://observablehq.com/@d3/gallery)
 * [Wiki](https://github.com/d3/d3/wiki)
 
 ## Installing
 
-If you use npm, `npm install d3`. Otherwise, download the [latest release](https://github.com/d3/d3/releases/latest). The released bundle supports anonymous AMD, CommonJS, and vanilla environments. You can load directly from [d3js.org](https://d3js.org), [CDNJS](https://cdnjs.com/libraries/d3), or [unpkg](https://unpkg.com/d3/). For example:
+If you use npm, `npm install d3`. You can also download the [latest release on GitHub](https://github.com/d3/d3/releases/latest). For vanilla HTML in modern browsers, import D3 from jsDelivr:
 
 ```html
-<script src="https://d3js.org/d3.v5.js"></script>
+<script type="module">
+
+import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";
+
+const div = d3.selectAll("div");
+
+</script>
 ```
 
-For the minified version:
+For legacy environments, you can load D3’s UMD bundle from an npm-based CDN such as jsDelivr; a `d3` global is exported:
 
 ```html
-<script src="https://d3js.org/d3.v5.min.js"></script>
+<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
+<script>
+
+const div = d3.selectAll("div");
+
+</script>
 ```
 
 You can also use the standalone D3 microlibraries. For example, [d3-selection](https://github.com/d3/d3-selection):
 
 ```html
-<script src="https://d3js.org/d3-selection.v1.js"></script>
+<script type="module">
+
+import {selectAll} from "https://cdn.jsdelivr.net/npm/d3-selection@3/+esm";
+
+const div = selectAll("div");
+
+</script>
 ```
 
-D3 is written using [ES2015 modules](http://www.2ality.com/2014/09/es6-modules-final.html). Create a [custom bundle using Rollup](https://bl.ocks.org/mbostock/bb09af4c39c79cffcde4), Webpack, or your preferred bundler. To import D3 into an ES2015 application, either import specific symbols from specific D3 modules:
+D3 is written using [ES2015 modules](http://www.2ality.com/2014/09/es6-modules-final.html). Create a custom bundle using Rollup, Webpack, or your preferred bundler. To import D3 into an ES2015 application, either import specific symbols from specific D3 modules:
 
 ```js
 import {scaleLinear} from "d3-scale";
@@ -44,14 +61,18 @@
 import * as d3 from "d3";
 ```
 
-In Node:
+Or using dynamic import:
 
 ```js
-var d3 = require("d3");
+const d3 = await import("d3");
 ```
 
-You can also require individual modules and combine them into a `d3` object using [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign):
+You can also import individual modules and combine them into a `d3` object using [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign):
 
 ```js
-var d3 = Object.assign({}, require("d3-format"), require("d3-geo"), require("d3-geo-projection"));
+const d3 = await Promise.all([
+  import("d3-format"),
+  import("d3-geo"),
+  import("d3-geo-projection")
+]).then(d3 => Object.assign({}, ...d3));
 ```
diff --git a/third_party/d3/src/d3.js b/third_party/d3/src/d3.js
index 632b3fa4..e4a786a04 100644
--- a/third_party/d3/src/d3.js
+++ b/third_party/d3/src/d3.js
@@ -1,56 +1,1080 @@
-// https://d3js.org v5.16.0 Copyright 2020 Mike Bostock
+// https://d3js.org v7.8.4 Copyright 2010-2023 Mike Bostock
 (function (global, factory) {
 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
 typeof define === 'function' && define.amd ? define(['exports'], factory) :
-(global = global || self, factory(global.d3 = global.d3 || {}));
-}(this, function (exports) { 'use strict';
+(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = global.d3 || {}));
+})(this, (function (exports) { 'use strict';
 
-var version = "5.16.0";
+var version = "7.8.4";
 
-function ascending(a, b) {
-  return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
+function ascending$3(a, b) {
+  return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
 }
 
-function bisector(compare) {
-  if (compare.length === 1) compare = ascendingComparator(compare);
-  return {
-    left: function(a, x, lo, hi) {
-      if (lo == null) lo = 0;
-      if (hi == null) hi = a.length;
-      while (lo < hi) {
-        var mid = lo + hi >>> 1;
-        if (compare(a[mid], x) < 0) lo = mid + 1;
+function descending$2(a, b) {
+  return a == null || b == null ? NaN
+    : b < a ? -1
+    : b > a ? 1
+    : b >= a ? 0
+    : NaN;
+}
+
+function bisector(f) {
+  let compare1, compare2, delta;
+
+  // If an accessor is specified, promote it to a comparator. In this case we
+  // can test whether the search value is (self-) comparable. We can’t do this
+  // for a comparator (except for specific, known comparators) because we can’t
+  // tell if the comparator is symmetric, and an asymmetric comparator can’t be
+  // used to test whether a single value is comparable.
+  if (f.length !== 2) {
+    compare1 = ascending$3;
+    compare2 = (d, x) => ascending$3(f(d), x);
+    delta = (d, x) => f(d) - x;
+  } else {
+    compare1 = f === ascending$3 || f === descending$2 ? f : zero$1;
+    compare2 = f;
+    delta = f;
+  }
+
+  function left(a, x, lo = 0, hi = a.length) {
+    if (lo < hi) {
+      if (compare1(x, x) !== 0) return hi;
+      do {
+        const mid = (lo + hi) >>> 1;
+        if (compare2(a[mid], x) < 0) lo = mid + 1;
         else hi = mid;
+      } while (lo < hi);
+    }
+    return lo;
+  }
+
+  function right(a, x, lo = 0, hi = a.length) {
+    if (lo < hi) {
+      if (compare1(x, x) !== 0) return hi;
+      do {
+        const mid = (lo + hi) >>> 1;
+        if (compare2(a[mid], x) <= 0) lo = mid + 1;
+        else hi = mid;
+      } while (lo < hi);
+    }
+    return lo;
+  }
+
+  function center(a, x, lo = 0, hi = a.length) {
+    const i = left(a, x, lo, hi - 1);
+    return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i;
+  }
+
+  return {left, center, right};
+}
+
+function zero$1() {
+  return 0;
+}
+
+function number$3(x) {
+  return x === null ? NaN : +x;
+}
+
+function* numbers(values, valueof) {
+  if (valueof === undefined) {
+    for (let value of values) {
+      if (value != null && (value = +value) >= value) {
+        yield value;
       }
-      return lo;
-    },
-    right: function(a, x, lo, hi) {
-      if (lo == null) lo = 0;
-      if (hi == null) hi = a.length;
-      while (lo < hi) {
-        var mid = lo + hi >>> 1;
-        if (compare(a[mid], x) > 0) hi = mid;
-        else lo = mid + 1;
+    }
+  } else {
+    let index = -1;
+    for (let value of values) {
+      if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
+        yield value;
       }
-      return lo;
+    }
+  }
+}
+
+const ascendingBisect = bisector(ascending$3);
+const bisectRight = ascendingBisect.right;
+const bisectLeft = ascendingBisect.left;
+const bisectCenter = bisector(number$3).center;
+var bisect = bisectRight;
+
+function blur(values, r) {
+  if (!((r = +r) >= 0)) throw new RangeError("invalid r");
+  let length = values.length;
+  if (!((length = Math.floor(length)) >= 0)) throw new RangeError("invalid length");
+  if (!length || !r) return values;
+  const blur = blurf(r);
+  const temp = values.slice();
+  blur(values, temp, 0, length, 1);
+  blur(temp, values, 0, length, 1);
+  blur(values, temp, 0, length, 1);
+  return values;
+}
+
+const blur2 = Blur2(blurf);
+
+const blurImage = Blur2(blurfImage);
+
+function Blur2(blur) {
+  return function(data, rx, ry = rx) {
+    if (!((rx = +rx) >= 0)) throw new RangeError("invalid rx");
+    if (!((ry = +ry) >= 0)) throw new RangeError("invalid ry");
+    let {data: values, width, height} = data;
+    if (!((width = Math.floor(width)) >= 0)) throw new RangeError("invalid width");
+    if (!((height = Math.floor(height !== undefined ? height : values.length / width)) >= 0)) throw new RangeError("invalid height");
+    if (!width || !height || (!rx && !ry)) return data;
+    const blurx = rx && blur(rx);
+    const blury = ry && blur(ry);
+    const temp = values.slice();
+    if (blurx && blury) {
+      blurh(blurx, temp, values, width, height);
+      blurh(blurx, values, temp, width, height);
+      blurh(blurx, temp, values, width, height);
+      blurv(blury, values, temp, width, height);
+      blurv(blury, temp, values, width, height);
+      blurv(blury, values, temp, width, height);
+    } else if (blurx) {
+      blurh(blurx, values, temp, width, height);
+      blurh(blurx, temp, values, width, height);
+      blurh(blurx, values, temp, width, height);
+    } else if (blury) {
+      blurv(blury, values, temp, width, height);
+      blurv(blury, temp, values, width, height);
+      blurv(blury, values, temp, width, height);
+    }
+    return data;
+  };
+}
+
+function blurh(blur, T, S, w, h) {
+  for (let y = 0, n = w * h; y < n;) {
+    blur(T, S, y, y += w, 1);
+  }
+}
+
+function blurv(blur, T, S, w, h) {
+  for (let x = 0, n = w * h; x < w; ++x) {
+    blur(T, S, x, x + n, w);
+  }
+}
+
+function blurfImage(radius) {
+  const blur = blurf(radius);
+  return (T, S, start, stop, step) => {
+    start <<= 2, stop <<= 2, step <<= 2;
+    blur(T, S, start + 0, stop + 0, step);
+    blur(T, S, start + 1, stop + 1, step);
+    blur(T, S, start + 2, stop + 2, step);
+    blur(T, S, start + 3, stop + 3, step);
+  };
+}
+
+// Given a target array T, a source array S, sets each value T[i] to the average
+// of {S[i - r], …, S[i], …, S[i + r]}, where r = ⌊radius⌋, start <= i < stop,
+// for each i, i + step, i + 2 * step, etc., and where S[j] is clamped between
+// S[start] (inclusive) and S[stop] (exclusive). If the given radius is not an
+// integer, S[i - r - 1] and S[i + r + 1] are added to the sum, each weighted
+// according to r - ⌊radius⌋.
+function blurf(radius) {
+  const radius0 = Math.floor(radius);
+  if (radius0 === radius) return bluri(radius);
+  const t = radius - radius0;
+  const w = 2 * radius + 1;
+  return (T, S, start, stop, step) => { // stop must be aligned!
+    if (!((stop -= step) >= start)) return; // inclusive stop
+    let sum = radius0 * S[start];
+    const s0 = step * radius0;
+    const s1 = s0 + step;
+    for (let i = start, j = start + s0; i < j; i += step) {
+      sum += S[Math.min(stop, i)];
+    }
+    for (let i = start, j = stop; i <= j; i += step) {
+      sum += S[Math.min(stop, i + s0)];
+      T[i] = (sum + t * (S[Math.max(start, i - s1)] + S[Math.min(stop, i + s1)])) / w;
+      sum -= S[Math.max(start, i - s0)];
     }
   };
 }
 
-function ascendingComparator(f) {
-  return function(d, x) {
-    return ascending(f(d), x);
+// Like blurf, but optimized for integer radius.
+function bluri(radius) {
+  const w = 2 * radius + 1;
+  return (T, S, start, stop, step) => { // stop must be aligned!
+    if (!((stop -= step) >= start)) return; // inclusive stop
+    let sum = radius * S[start];
+    const s = step * radius;
+    for (let i = start, j = start + s; i < j; i += step) {
+      sum += S[Math.min(stop, i)];
+    }
+    for (let i = start, j = stop; i <= j; i += step) {
+      sum += S[Math.min(stop, i + s)];
+      T[i] = sum / w;
+      sum -= S[Math.max(start, i - s)];
+    }
   };
 }
 
-var ascendingBisect = bisector(ascending);
-var bisectRight = ascendingBisect.right;
-var bisectLeft = ascendingBisect.left;
+function count$1(values, valueof) {
+  let count = 0;
+  if (valueof === undefined) {
+    for (let value of values) {
+      if (value != null && (value = +value) >= value) {
+        ++count;
+      }
+    }
+  } else {
+    let index = -1;
+    for (let value of values) {
+      if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
+        ++count;
+      }
+    }
+  }
+  return count;
+}
 
-function pairs(array, f) {
-  if (f == null) f = pair;
-  var i = 0, n = array.length - 1, p = array[0], pairs = new Array(n < 0 ? 0 : n);
-  while (i < n) pairs[i] = f(p, p = array[++i]);
+function length$3(array) {
+  return array.length | 0;
+}
+
+function empty$2(length) {
+  return !(length > 0);
+}
+
+function arrayify(values) {
+  return typeof values !== "object" || "length" in values ? values : Array.from(values);
+}
+
+function reducer(reduce) {
+  return values => reduce(...values);
+}
+
+function cross$2(...values) {
+  const reduce = typeof values[values.length - 1] === "function" && reducer(values.pop());
+  values = values.map(arrayify);
+  const lengths = values.map(length$3);
+  const j = values.length - 1;
+  const index = new Array(j + 1).fill(0);
+  const product = [];
+  if (j < 0 || lengths.some(empty$2)) return product;
+  while (true) {
+    product.push(index.map((j, i) => values[i][j]));
+    let i = j;
+    while (++index[i] === lengths[i]) {
+      if (i === 0) return reduce ? product.map(reduce) : product;
+      index[i--] = 0;
+    }
+  }
+}
+
+function cumsum(values, valueof) {
+  var sum = 0, index = 0;
+  return Float64Array.from(values, valueof === undefined
+    ? v => (sum += +v || 0)
+    : v => (sum += +valueof(v, index++, values) || 0));
+}
+
+function variance(values, valueof) {
+  let count = 0;
+  let delta;
+  let mean = 0;
+  let sum = 0;
+  if (valueof === undefined) {
+    for (let value of values) {
+      if (value != null && (value = +value) >= value) {
+        delta = value - mean;
+        mean += delta / ++count;
+        sum += delta * (value - mean);
+      }
+    }
+  } else {
+    let index = -1;
+    for (let value of values) {
+      if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
+        delta = value - mean;
+        mean += delta / ++count;
+        sum += delta * (value - mean);
+      }
+    }
+  }
+  if (count > 1) return sum / (count - 1);
+}
+
+function deviation(values, valueof) {
+  const v = variance(values, valueof);
+  return v ? Math.sqrt(v) : v;
+}
+
+function extent$1(values, valueof) {
+  let min;
+  let max;
+  if (valueof === undefined) {
+    for (const value of values) {
+      if (value != null) {
+        if (min === undefined) {
+          if (value >= value) min = max = value;
+        } else {
+          if (min > value) min = value;
+          if (max < value) max = value;
+        }
+      }
+    }
+  } else {
+    let index = -1;
+    for (let value of values) {
+      if ((value = valueof(value, ++index, values)) != null) {
+        if (min === undefined) {
+          if (value >= value) min = max = value;
+        } else {
+          if (min > value) min = value;
+          if (max < value) max = value;
+        }
+      }
+    }
+  }
+  return [min, max];
+}
+
+// https://github.com/python/cpython/blob/a74eea238f5baba15797e2e8b570d153bc8690a7/Modules/mathmodule.c#L1423
+class Adder {
+  constructor() {
+    this._partials = new Float64Array(32);
+    this._n = 0;
+  }
+  add(x) {
+    const p = this._partials;
+    let i = 0;
+    for (let j = 0; j < this._n && j < 32; j++) {
+      const y = p[j],
+        hi = x + y,
+        lo = Math.abs(x) < Math.abs(y) ? x - (hi - y) : y - (hi - x);
+      if (lo) p[i++] = lo;
+      x = hi;
+    }
+    p[i] = x;
+    this._n = i + 1;
+    return this;
+  }
+  valueOf() {
+    const p = this._partials;
+    let n = this._n, x, y, lo, hi = 0;
+    if (n > 0) {
+      hi = p[--n];
+      while (n > 0) {
+        x = hi;
+        y = p[--n];
+        hi = x + y;
+        lo = y - (hi - x);
+        if (lo) break;
+      }
+      if (n > 0 && ((lo < 0 && p[n - 1] < 0) || (lo > 0 && p[n - 1] > 0))) {
+        y = lo * 2;
+        x = hi + y;
+        if (y == x - hi) hi = x;
+      }
+    }
+    return hi;
+  }
+}
+
+function fsum(values, valueof) {
+  const adder = new Adder();
+  if (valueof === undefined) {
+    for (let value of values) {
+      if (value = +value) {
+        adder.add(value);
+      }
+    }
+  } else {
+    let index = -1;
+    for (let value of values) {
+      if (value = +valueof(value, ++index, values)) {
+        adder.add(value);
+      }
+    }
+  }
+  return +adder;
+}
+
+function fcumsum(values, valueof) {
+  const adder = new Adder();
+  let index = -1;
+  return Float64Array.from(values, valueof === undefined
+      ? v => adder.add(+v || 0)
+      : v => adder.add(+valueof(v, ++index, values) || 0)
+  );
+}
+
+class InternMap extends Map {
+  constructor(entries, key = keyof) {
+    super();
+    Object.defineProperties(this, {_intern: {value: new Map()}, _key: {value: key}});
+    if (entries != null) for (const [key, value] of entries) this.set(key, value);
+  }
+  get(key) {
+    return super.get(intern_get(this, key));
+  }
+  has(key) {
+    return super.has(intern_get(this, key));
+  }
+  set(key, value) {
+    return super.set(intern_set(this, key), value);
+  }
+  delete(key) {
+    return super.delete(intern_delete(this, key));
+  }
+}
+
+class InternSet extends Set {
+  constructor(values, key = keyof) {
+    super();
+    Object.defineProperties(this, {_intern: {value: new Map()}, _key: {value: key}});
+    if (values != null) for (const value of values) this.add(value);
+  }
+  has(value) {
+    return super.has(intern_get(this, value));
+  }
+  add(value) {
+    return super.add(intern_set(this, value));
+  }
+  delete(value) {
+    return super.delete(intern_delete(this, value));
+  }
+}
+
+function intern_get({_intern, _key}, value) {
+  const key = _key(value);
+  return _intern.has(key) ? _intern.get(key) : value;
+}
+
+function intern_set({_intern, _key}, value) {
+  const key = _key(value);
+  if (_intern.has(key)) return _intern.get(key);
+  _intern.set(key, value);
+  return value;
+}
+
+function intern_delete({_intern, _key}, value) {
+  const key = _key(value);
+  if (_intern.has(key)) {
+    value = _intern.get(key);
+    _intern.delete(key);
+  }
+  return value;
+}
+
+function keyof(value) {
+  return value !== null && typeof value === "object" ? value.valueOf() : value;
+}
+
+function identity$9(x) {
+  return x;
+}
+
+function group(values, ...keys) {
+  return nest(values, identity$9, identity$9, keys);
+}
+
+function groups(values, ...keys) {
+  return nest(values, Array.from, identity$9, keys);
+}
+
+function flatten$1(groups, keys) {
+  for (let i = 1, n = keys.length; i < n; ++i) {
+    groups = groups.flatMap(g => g.pop().map(([key, value]) => [...g, key, value]));
+  }
+  return groups;
+}
+
+function flatGroup(values, ...keys) {
+  return flatten$1(groups(values, ...keys), keys);
+}
+
+function flatRollup(values, reduce, ...keys) {
+  return flatten$1(rollups(values, reduce, ...keys), keys);
+}
+
+function rollup(values, reduce, ...keys) {
+  return nest(values, identity$9, reduce, keys);
+}
+
+function rollups(values, reduce, ...keys) {
+  return nest(values, Array.from, reduce, keys);
+}
+
+function index$4(values, ...keys) {
+  return nest(values, identity$9, unique, keys);
+}
+
+function indexes(values, ...keys) {
+  return nest(values, Array.from, unique, keys);
+}
+
+function unique(values) {
+  if (values.length !== 1) throw new Error("duplicate key");
+  return values[0];
+}
+
+function nest(values, map, reduce, keys) {
+  return (function regroup(values, i) {
+    if (i >= keys.length) return reduce(values);
+    const groups = new InternMap();
+    const keyof = keys[i++];
+    let index = -1;
+    for (const value of values) {
+      const key = keyof(value, ++index, values);
+      const group = groups.get(key);
+      if (group) group.push(value);
+      else groups.set(key, [value]);
+    }
+    for (const [key, values] of groups) {
+      groups.set(key, regroup(values, i));
+    }
+    return map(groups);
+  })(values, 0);
+}
+
+function permute(source, keys) {
+  return Array.from(keys, key => source[key]);
+}
+
+function sort(values, ...F) {
+  if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable");
+  values = Array.from(values);
+  let [f] = F;
+  if ((f && f.length !== 2) || F.length > 1) {
+    const index = Uint32Array.from(values, (d, i) => i);
+    if (F.length > 1) {
+      F = F.map(f => values.map(f));
+      index.sort((i, j) => {
+        for (const f of F) {
+          const c = ascendingDefined(f[i], f[j]);
+          if (c) return c;
+        }
+      });
+    } else {
+      f = values.map(f);
+      index.sort((i, j) => ascendingDefined(f[i], f[j]));
+    }
+    return permute(values, index);
+  }
+  return values.sort(compareDefined(f));
+}
+
+function compareDefined(compare = ascending$3) {
+  if (compare === ascending$3) return ascendingDefined;
+  if (typeof compare !== "function") throw new TypeError("compare is not a function");
+  return (a, b) => {
+    const x = compare(a, b);
+    if (x || x === 0) return x;
+    return (compare(b, b) === 0) - (compare(a, a) === 0);
+  };
+}
+
+function ascendingDefined(a, b) {
+  return (a == null || !(a >= a)) - (b == null || !(b >= b)) || (a < b ? -1 : a > b ? 1 : 0);
+}
+
+function groupSort(values, reduce, key) {
+  return (reduce.length !== 2
+    ? sort(rollup(values, reduce, key), (([ak, av], [bk, bv]) => ascending$3(av, bv) || ascending$3(ak, bk)))
+    : sort(group(values, key), (([ak, av], [bk, bv]) => reduce(av, bv) || ascending$3(ak, bk))))
+    .map(([key]) => key);
+}
+
+var array$5 = Array.prototype;
+
+var slice$3 = array$5.slice;
+
+function constant$b(x) {
+  return () => x;
+}
+
+const e10 = Math.sqrt(50),
+    e5 = Math.sqrt(10),
+    e2 = Math.sqrt(2);
+
+function tickSpec(start, stop, count) {
+  const step = (stop - start) / Math.max(0, count),
+      power = Math.floor(Math.log10(step)),
+      error = step / Math.pow(10, power),
+      factor = error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1;
+  let i1, i2, inc;
+  if (power < 0) {
+    inc = Math.pow(10, -power) / factor;
+    i1 = Math.round(start * inc);
+    i2 = Math.round(stop * inc);
+    if (i1 / inc < start) ++i1;
+    if (i2 / inc > stop) --i2;
+    inc = -inc;
+  } else {
+    inc = Math.pow(10, power) * factor;
+    i1 = Math.round(start / inc);
+    i2 = Math.round(stop / inc);
+    if (i1 * inc < start) ++i1;
+    if (i2 * inc > stop) --i2;
+  }
+  if (i2 < i1 && 0.5 <= count && count < 2) return tickSpec(start, stop, count * 2);
+  return [i1, i2, inc];
+}
+
+function ticks(start, stop, count) {
+  stop = +stop, start = +start, count = +count;
+  if (!(count > 0)) return [];
+  if (start === stop) return [start];
+  const reverse = stop < start, [i1, i2, inc] = reverse ? tickSpec(stop, start, count) : tickSpec(start, stop, count);
+  if (!(i2 >= i1)) return [];
+  const n = i2 - i1 + 1, ticks = new Array(n);
+  if (reverse) {
+    if (inc < 0) for (let i = 0; i < n; ++i) ticks[i] = (i2 - i) / -inc;
+    else for (let i = 0; i < n; ++i) ticks[i] = (i2 - i) * inc;
+  } else {
+    if (inc < 0) for (let i = 0; i < n; ++i) ticks[i] = (i1 + i) / -inc;
+    else for (let i = 0; i < n; ++i) ticks[i] = (i1 + i) * inc;
+  }
+  return ticks;
+}
+
+function tickIncrement(start, stop, count) {
+  stop = +stop, start = +start, count = +count;
+  return tickSpec(start, stop, count)[2];
+}
+
+function tickStep(start, stop, count) {
+  stop = +stop, start = +start, count = +count;
+  const reverse = stop < start, inc = reverse ? tickIncrement(stop, start, count) : tickIncrement(start, stop, count);
+  return (reverse ? -1 : 1) * (inc < 0 ? 1 / -inc : inc);
+}
+
+function nice$1(start, stop, count) {
+  let prestep;
+  while (true) {
+    const step = tickIncrement(start, stop, count);
+    if (step === prestep || step === 0 || !isFinite(step)) {
+      return [start, stop];
+    } else if (step > 0) {
+      start = Math.floor(start / step) * step;
+      stop = Math.ceil(stop / step) * step;
+    } else if (step < 0) {
+      start = Math.ceil(start * step) / step;
+      stop = Math.floor(stop * step) / step;
+    }
+    prestep = step;
+  }
+}
+
+function thresholdSturges(values) {
+  return Math.max(1, Math.ceil(Math.log(count$1(values)) / Math.LN2) + 1);
+}
+
+function bin() {
+  var value = identity$9,
+      domain = extent$1,
+      threshold = thresholdSturges;
+
+  function histogram(data) {
+    if (!Array.isArray(data)) data = Array.from(data);
+
+    var i,
+        n = data.length,
+        x,
+        step,
+        values = new Array(n);
+
+    for (i = 0; i < n; ++i) {
+      values[i] = value(data[i], i, data);
+    }
+
+    var xz = domain(values),
+        x0 = xz[0],
+        x1 = xz[1],
+        tz = threshold(values, x0, x1);
+
+    // Convert number of thresholds into uniform thresholds, and nice the
+    // default domain accordingly.
+    if (!Array.isArray(tz)) {
+      const max = x1, tn = +tz;
+      if (domain === extent$1) [x0, x1] = nice$1(x0, x1, tn);
+      tz = ticks(x0, x1, tn);
+
+      // If the domain is aligned with the first tick (which it will by
+      // default), then we can use quantization rather than bisection to bin
+      // values, which is substantially faster.
+      if (tz[0] <= x0) step = tickIncrement(x0, x1, tn);
+
+      // If the last threshold is coincident with the domain’s upper bound, the
+      // last bin will be zero-width. If the default domain is used, and this
+      // last threshold is coincident with the maximum input value, we can
+      // extend the niced upper bound by one tick to ensure uniform bin widths;
+      // otherwise, we simply remove the last threshold. Note that we don’t
+      // coerce values or the domain to numbers, and thus must be careful to
+      // compare order (>=) rather than strict equality (===)!
+      if (tz[tz.length - 1] >= x1) {
+        if (max >= x1 && domain === extent$1) {
+          const step = tickIncrement(x0, x1, tn);
+          if (isFinite(step)) {
+            if (step > 0) {
+              x1 = (Math.floor(x1 / step) + 1) * step;
+            } else if (step < 0) {
+              x1 = (Math.ceil(x1 * -step) + 1) / -step;
+            }
+          }
+        } else {
+          tz.pop();
+        }
+      }
+    }
+
+    // Remove any thresholds outside the domain.
+    // Be careful not to mutate an array owned by the user!
+    var m = tz.length, a = 0, b = m;
+    while (tz[a] <= x0) ++a;
+    while (tz[b - 1] > x1) --b;
+    if (a || b < m) tz = tz.slice(a, b), m = b - a;
+
+    var bins = new Array(m + 1),
+        bin;
+
+    // Initialize bins.
+    for (i = 0; i <= m; ++i) {
+      bin = bins[i] = [];
+      bin.x0 = i > 0 ? tz[i - 1] : x0;
+      bin.x1 = i < m ? tz[i] : x1;
+    }
+
+    // Assign data to bins by value, ignoring any outside the domain.
+    if (isFinite(step)) {
+      if (step > 0) {
+        for (i = 0; i < n; ++i) {
+          if ((x = values[i]) != null && x0 <= x && x <= x1) {
+            bins[Math.min(m, Math.floor((x - x0) / step))].push(data[i]);
+          }
+        }
+      } else if (step < 0) {
+        for (i = 0; i < n; ++i) {
+          if ((x = values[i]) != null && x0 <= x && x <= x1) {
+            const j = Math.floor((x0 - x) * step);
+            bins[Math.min(m, j + (tz[j] <= x))].push(data[i]); // handle off-by-one due to rounding
+          }
+        }
+      }
+    } else {
+      for (i = 0; i < n; ++i) {
+        if ((x = values[i]) != null && x0 <= x && x <= x1) {
+          bins[bisect(tz, x, 0, m)].push(data[i]);
+        }
+      }
+    }
+
+    return bins;
+  }
+
+  histogram.value = function(_) {
+    return arguments.length ? (value = typeof _ === "function" ? _ : constant$b(_), histogram) : value;
+  };
+
+  histogram.domain = function(_) {
+    return arguments.length ? (domain = typeof _ === "function" ? _ : constant$b([_[0], _[1]]), histogram) : domain;
+  };
+
+  histogram.thresholds = function(_) {
+    return arguments.length ? (threshold = typeof _ === "function" ? _ : constant$b(Array.isArray(_) ? slice$3.call(_) : _), histogram) : threshold;
+  };
+
+  return histogram;
+}
+
+function max$3(values, valueof) {
+  let max;
+  if (valueof === undefined) {
+    for (const value of values) {
+      if (value != null
+          && (max < value || (max === undefined && value >= value))) {
+        max = value;
+      }
+    }
+  } else {
+    let index = -1;
+    for (let value of values) {
+      if ((value = valueof(value, ++index, values)) != null
+          && (max < value || (max === undefined && value >= value))) {
+        max = value;
+      }
+    }
+  }
+  return max;
+}
+
+function maxIndex(values, valueof) {
+  let max;
+  let maxIndex = -1;
+  let index = -1;
+  if (valueof === undefined) {
+    for (const value of values) {
+      ++index;
+      if (value != null
+          && (max < value || (max === undefined && value >= value))) {
+        max = value, maxIndex = index;
+      }
+    }
+  } else {
+    for (let value of values) {
+      if ((value = valueof(value, ++index, values)) != null
+          && (max < value || (max === undefined && value >= value))) {
+        max = value, maxIndex = index;
+      }
+    }
+  }
+  return maxIndex;
+}
+
+function min$2(values, valueof) {
+  let min;
+  if (valueof === undefined) {
+    for (const value of values) {
+      if (value != null
+          && (min > value || (min === undefined && value >= value))) {
+        min = value;
+      }
+    }
+  } else {
+    let index = -1;
+    for (let value of values) {
+      if ((value = valueof(value, ++index, values)) != null
+          && (min > value || (min === undefined && value >= value))) {
+        min = value;
+      }
+    }
+  }
+  return min;
+}
+
+function minIndex(values, valueof) {
+  let min;
+  let minIndex = -1;
+  let index = -1;
+  if (valueof === undefined) {
+    for (const value of values) {
+      ++index;
+      if (value != null
+          && (min > value || (min === undefined && value >= value))) {
+        min = value, minIndex = index;
+      }
+    }
+  } else {
+    for (let value of values) {
+      if ((value = valueof(value, ++index, values)) != null
+          && (min > value || (min === undefined && value >= value))) {
+        min = value, minIndex = index;
+      }
+    }
+  }
+  return minIndex;
+}
+
+// Based on https://github.com/mourner/quickselect
+// ISC license, Copyright 2018 Vladimir Agafonkin.
+function quickselect(array, k, left = 0, right = Infinity, compare) {
+  k = Math.floor(k);
+  left = Math.floor(Math.max(0, left));
+  right = Math.floor(Math.min(array.length - 1, right));
+
+  if (!(left <= k && k <= right)) return array;
+
+  compare = compare === undefined ? ascendingDefined : compareDefined(compare);
+
+  while (right > left) {
+    if (right - left > 600) {
+      const n = right - left + 1;
+      const m = k - left + 1;
+      const z = Math.log(n);
+      const s = 0.5 * Math.exp(2 * z / 3);
+      const sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
+      const newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
+      const newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
+      quickselect(array, k, newLeft, newRight, compare);
+    }
+
+    const t = array[k];
+    let i = left;
+    let j = right;
+
+    swap$1(array, left, k);
+    if (compare(array[right], t) > 0) swap$1(array, left, right);
+
+    while (i < j) {
+      swap$1(array, i, j), ++i, --j;
+      while (compare(array[i], t) < 0) ++i;
+      while (compare(array[j], t) > 0) --j;
+    }
+
+    if (compare(array[left], t) === 0) swap$1(array, left, j);
+    else ++j, swap$1(array, j, right);
+
+    if (j <= k) left = j + 1;
+    if (k <= j) right = j - 1;
+  }
+
+  return array;
+}
+
+function swap$1(array, i, j) {
+  const t = array[i];
+  array[i] = array[j];
+  array[j] = t;
+}
+
+function greatest(values, compare = ascending$3) {
+  let max;
+  let defined = false;
+  if (compare.length === 1) {
+    let maxValue;
+    for (const element of values) {
+      const value = compare(element);
+      if (defined
+          ? ascending$3(value, maxValue) > 0
+          : ascending$3(value, value) === 0) {
+        max = element;
+        maxValue = value;
+        defined = true;
+      }
+    }
+  } else {
+    for (const value of values) {
+      if (defined
+          ? compare(value, max) > 0
+          : compare(value, value) === 0) {
+        max = value;
+        defined = true;
+      }
+    }
+  }
+  return max;
+}
+
+function quantile$1(values, p, valueof) {
+  values = Float64Array.from(numbers(values, valueof));
+  if (!(n = values.length) || isNaN(p = +p)) return;
+  if (p <= 0 || n < 2) return min$2(values);
+  if (p >= 1) return max$3(values);
+  var n,
+      i = (n - 1) * p,
+      i0 = Math.floor(i),
+      value0 = max$3(quickselect(values, i0).subarray(0, i0 + 1)),
+      value1 = min$2(values.subarray(i0 + 1));
+  return value0 + (value1 - value0) * (i - i0);
+}
+
+function quantileSorted(values, p, valueof = number$3) {
+  if (!(n = values.length) || isNaN(p = +p)) return;
+  if (p <= 0 || n < 2) return +valueof(values[0], 0, values);
+  if (p >= 1) return +valueof(values[n - 1], n - 1, values);
+  var n,
+      i = (n - 1) * p,
+      i0 = Math.floor(i),
+      value0 = +valueof(values[i0], i0, values),
+      value1 = +valueof(values[i0 + 1], i0 + 1, values);
+  return value0 + (value1 - value0) * (i - i0);
+}
+
+function quantileIndex(values, p, valueof) {
+  values = Float64Array.from(numbers(values, valueof));
+  if (!(n = values.length) || isNaN(p = +p)) return;
+  if (p <= 0 || n < 2) return minIndex(values);
+  if (p >= 1) return maxIndex(values);
+  var n,
+      i = Math.floor((n - 1) * p),
+      order = (i, j) => ascendingDefined(values[i], values[j]),
+      index = quickselect(Uint32Array.from(values, (_, i) => i), i, 0, n - 1, order);
+  return greatest(index.subarray(0, i + 1), i => values[i]);
+}
+
+function thresholdFreedmanDiaconis(values, min, max) {
+  const c = count$1(values), d = quantile$1(values, 0.75) - quantile$1(values, 0.25);
+  return c && d ? Math.ceil((max - min) / (2 * d * Math.pow(c, -1 / 3))) : 1;
+}
+
+function thresholdScott(values, min, max) {
+  const c = count$1(values), d = deviation(values);
+  return c && d ? Math.ceil((max - min) * Math.cbrt(c) / (3.49 * d)) : 1;
+}
+
+function mean(values, valueof) {
+  let count = 0;
+  let sum = 0;
+  if (valueof === undefined) {
+    for (let value of values) {
+      if (value != null && (value = +value) >= value) {
+        ++count, sum += value;
+      }
+    }
+  } else {
+    let index = -1;
+    for (let value of values) {
+      if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {
+        ++count, sum += value;
+      }
+    }
+  }
+  if (count) return sum / count;
+}
+
+function median(values, valueof) {
+  return quantile$1(values, 0.5, valueof);
+}
+
+function medianIndex(values, valueof) {
+  return quantileIndex(values, 0.5, valueof);
+}
+
+function* flatten(arrays) {
+  for (const array of arrays) {
+    yield* array;
+  }
+}
+
+function merge(arrays) {
+  return Array.from(flatten(arrays));
+}
+
+function mode(values, valueof) {
+  const counts = new InternMap();
+  if (valueof === undefined) {
+    for (let value of values) {
+      if (value != null && value >= value) {
+        counts.set(value, (counts.get(value) || 0) + 1);
+      }
+    }
+  } else {
+    let index = -1;
+    for (let value of values) {
+      if ((value = valueof(value, ++index, values)) != null && value >= value) {
+        counts.set(value, (counts.get(value) || 0) + 1);
+      }
+    }
+  }
+  let modeValue;
+  let modeCount = 0;
+  for (const [value, count] of counts) {
+    if (count > modeCount) {
+      modeCount = count;
+      modeValue = value;
+    }
+  }
+  return modeValue;
+}
+
+function pairs(values, pairof = pair) {
+  const pairs = [];
+  let previous;
+  let first = false;
+  for (const value of values) {
+    if (first) pairs.push(pairof(previous, value));
+    previous = value;
+    first = true;
+  }
   return pairs;
 }
 
@@ -58,125 +1082,7 @@
   return [a, b];
 }
 
-function cross(values0, values1, reduce) {
-  var n0 = values0.length,
-      n1 = values1.length,
-      values = new Array(n0 * n1),
-      i0,
-      i1,
-      i,
-      value0;
-
-  if (reduce == null) reduce = pair;
-
-  for (i0 = i = 0; i0 < n0; ++i0) {
-    for (value0 = values0[i0], i1 = 0; i1 < n1; ++i1, ++i) {
-      values[i] = reduce(value0, values1[i1]);
-    }
-  }
-
-  return values;
-}
-
-function descending(a, b) {
-  return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
-}
-
-function number(x) {
-  return x === null ? NaN : +x;
-}
-
-function variance(values, valueof) {
-  var n = values.length,
-      m = 0,
-      i = -1,
-      mean = 0,
-      value,
-      delta,
-      sum = 0;
-
-  if (valueof == null) {
-    while (++i < n) {
-      if (!isNaN(value = number(values[i]))) {
-        delta = value - mean;
-        mean += delta / ++m;
-        sum += delta * (value - mean);
-      }
-    }
-  }
-
-  else {
-    while (++i < n) {
-      if (!isNaN(value = number(valueof(values[i], i, values)))) {
-        delta = value - mean;
-        mean += delta / ++m;
-        sum += delta * (value - mean);
-      }
-    }
-  }
-
-  if (m > 1) return sum / (m - 1);
-}
-
-function deviation(array, f) {
-  var v = variance(array, f);
-  return v ? Math.sqrt(v) : v;
-}
-
-function extent(values, valueof) {
-  var n = values.length,
-      i = -1,
-      value,
-      min,
-      max;
-
-  if (valueof == null) {
-    while (++i < n) { // Find the first comparable value.
-      if ((value = values[i]) != null && value >= value) {
-        min = max = value;
-        while (++i < n) { // Compare the remaining values.
-          if ((value = values[i]) != null) {
-            if (min > value) min = value;
-            if (max < value) max = value;
-          }
-        }
-      }
-    }
-  }
-
-  else {
-    while (++i < n) { // Find the first comparable value.
-      if ((value = valueof(values[i], i, values)) != null && value >= value) {
-        min = max = value;
-        while (++i < n) { // Compare the remaining values.
-          if ((value = valueof(values[i], i, values)) != null) {
-            if (min > value) min = value;
-            if (max < value) max = value;
-          }
-        }
-      }
-    }
-  }
-
-  return [min, max];
-}
-
-var array = Array.prototype;
-
-var slice = array.slice;
-var map = array.map;
-
-function constant(x) {
-  return function() {
-    return x;
-  };
-}
-
-function identity(x) {
-  return x;
-}
-
-function sequence(start, stop, step) {
+function range$2(start, stop, step) {
   start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
 
   var i = -1,
@@ -190,356 +1096,131 @@
   return range;
 }
 
-var e10 = Math.sqrt(50),
-    e5 = Math.sqrt(10),
-    e2 = Math.sqrt(2);
+function rank(values, valueof = ascending$3) {
+  if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable");
+  let V = Array.from(values);
+  const R = new Float64Array(V.length);
+  if (valueof.length !== 2) V = V.map(valueof), valueof = ascending$3;
+  const compareIndex = (i, j) => valueof(V[i], V[j]);
+  let k, r;
+  values = Uint32Array.from(V, (_, i) => i);
+  // Risky chaining due to Safari 14 https://github.com/d3/d3-array/issues/123
+  values.sort(valueof === ascending$3 ? (i, j) => ascendingDefined(V[i], V[j]) : compareDefined(compareIndex));
+  values.forEach((j, i) => {
+      const c = compareIndex(j, k === undefined ? j : k);
+      if (c >= 0) {
+        if (k === undefined || c > 0) k = j, r = i;
+        R[j] = r;
+      } else {
+        R[j] = NaN;
+      }
+    });
+  return R;
+}
 
-function ticks(start, stop, count) {
-  var reverse,
-      i = -1,
-      n,
-      ticks,
-      step;
-
-  stop = +stop, start = +start, count = +count;
-  if (start === stop && count > 0) return [start];
-  if (reverse = stop < start) n = start, start = stop, stop = n;
-  if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
-
-  if (step > 0) {
-    start = Math.ceil(start / step);
-    stop = Math.floor(stop / step);
-    ticks = new Array(n = Math.ceil(stop - start + 1));
-    while (++i < n) ticks[i] = (start + i) * step;
+function least(values, compare = ascending$3) {
+  let min;
+  let defined = false;
+  if (compare.length === 1) {
+    let minValue;
+    for (const element of values) {
+      const value = compare(element);
+      if (defined
+          ? ascending$3(value, minValue) < 0
+          : ascending$3(value, value) === 0) {
+        min = element;
+        minValue = value;
+        defined = true;
+      }
+    }
   } else {
-    start = Math.floor(start * step);
-    stop = Math.ceil(stop * step);
-    ticks = new Array(n = Math.ceil(start - stop + 1));
-    while (++i < n) ticks[i] = (start - i) / step;
-  }
-
-  if (reverse) ticks.reverse();
-
-  return ticks;
-}
-
-function tickIncrement(start, stop, count) {
-  var step = (stop - start) / Math.max(0, count),
-      power = Math.floor(Math.log(step) / Math.LN10),
-      error = step / Math.pow(10, power);
-  return power >= 0
-      ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power)
-      : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1);
-}
-
-function tickStep(start, stop, count) {
-  var step0 = Math.abs(stop - start) / Math.max(0, count),
-      step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
-      error = step0 / step1;
-  if (error >= e10) step1 *= 10;
-  else if (error >= e5) step1 *= 5;
-  else if (error >= e2) step1 *= 2;
-  return stop < start ? -step1 : step1;
-}
-
-function thresholdSturges(values) {
-  return Math.ceil(Math.log(values.length) / Math.LN2) + 1;
-}
-
-function histogram() {
-  var value = identity,
-      domain = extent,
-      threshold = thresholdSturges;
-
-  function histogram(data) {
-    var i,
-        n = data.length,
-        x,
-        values = new Array(n);
-
-    for (i = 0; i < n; ++i) {
-      values[i] = value(data[i], i, data);
-    }
-
-    var xz = domain(values),
-        x0 = xz[0],
-        x1 = xz[1],
-        tz = threshold(values, x0, x1);
-
-    // Convert number of thresholds into uniform thresholds.
-    if (!Array.isArray(tz)) {
-      tz = tickStep(x0, x1, tz);
-      tz = sequence(Math.ceil(x0 / tz) * tz, x1, tz); // exclusive
-    }
-
-    // Remove any thresholds outside the domain.
-    var m = tz.length;
-    while (tz[0] <= x0) tz.shift(), --m;
-    while (tz[m - 1] > x1) tz.pop(), --m;
-
-    var bins = new Array(m + 1),
-        bin;
-
-    // Initialize bins.
-    for (i = 0; i <= m; ++i) {
-      bin = bins[i] = [];
-      bin.x0 = i > 0 ? tz[i - 1] : x0;
-      bin.x1 = i < m ? tz[i] : x1;
-    }
-
-    // Assign data to bins by value, ignoring any outside the domain.
-    for (i = 0; i < n; ++i) {
-      x = values[i];
-      if (x0 <= x && x <= x1) {
-        bins[bisectRight(tz, x, 0, m)].push(data[i]);
-      }
-    }
-
-    return bins;
-  }
-
-  histogram.value = function(_) {
-    return arguments.length ? (value = typeof _ === "function" ? _ : constant(_), histogram) : value;
-  };
-
-  histogram.domain = function(_) {
-    return arguments.length ? (domain = typeof _ === "function" ? _ : constant([_[0], _[1]]), histogram) : domain;
-  };
-
-  histogram.thresholds = function(_) {
-    return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(slice.call(_)) : constant(_), histogram) : threshold;
-  };
-
-  return histogram;
-}
-
-function threshold(values, p, valueof) {
-  if (valueof == null) valueof = number;
-  if (!(n = values.length)) return;
-  if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values);
-  if (p >= 1) return +valueof(values[n - 1], n - 1, values);
-  var n,
-      i = (n - 1) * p,
-      i0 = Math.floor(i),
-      value0 = +valueof(values[i0], i0, values),
-      value1 = +valueof(values[i0 + 1], i0 + 1, values);
-  return value0 + (value1 - value0) * (i - i0);
-}
-
-function freedmanDiaconis(values, min, max) {
-  values = map.call(values, number).sort(ascending);
-  return Math.ceil((max - min) / (2 * (threshold(values, 0.75) - threshold(values, 0.25)) * Math.pow(values.length, -1 / 3)));
-}
-
-function scott(values, min, max) {
-  return Math.ceil((max - min) / (3.5 * deviation(values) * Math.pow(values.length, -1 / 3)));
-}
-
-function max(values, valueof) {
-  var n = values.length,
-      i = -1,
-      value,
-      max;
-
-  if (valueof == null) {
-    while (++i < n) { // Find the first comparable value.
-      if ((value = values[i]) != null && value >= value) {
-        max = value;
-        while (++i < n) { // Compare the remaining values.
-          if ((value = values[i]) != null && value > max) {
-            max = value;
-          }
-        }
-      }
-    }
-  }
-
-  else {
-    while (++i < n) { // Find the first comparable value.
-      if ((value = valueof(values[i], i, values)) != null && value >= value) {
-        max = value;
-        while (++i < n) { // Compare the remaining values.
-          if ((value = valueof(values[i], i, values)) != null && value > max) {
-            max = value;
-          }
-        }
-      }
-    }
-  }
-
-  return max;
-}
-
-function mean(values, valueof) {
-  var n = values.length,
-      m = n,
-      i = -1,
-      value,
-      sum = 0;
-
-  if (valueof == null) {
-    while (++i < n) {
-      if (!isNaN(value = number(values[i]))) sum += value;
-      else --m;
-    }
-  }
-
-  else {
-    while (++i < n) {
-      if (!isNaN(value = number(valueof(values[i], i, values)))) sum += value;
-      else --m;
-    }
-  }
-
-  if (m) return sum / m;
-}
-
-function median(values, valueof) {
-  var n = values.length,
-      i = -1,
-      value,
-      numbers = [];
-
-  if (valueof == null) {
-    while (++i < n) {
-      if (!isNaN(value = number(values[i]))) {
-        numbers.push(value);
-      }
-    }
-  }
-
-  else {
-    while (++i < n) {
-      if (!isNaN(value = number(valueof(values[i], i, values)))) {
-        numbers.push(value);
-      }
-    }
-  }
-
-  return threshold(numbers.sort(ascending), 0.5);
-}
-
-function merge(arrays) {
-  var n = arrays.length,
-      m,
-      i = -1,
-      j = 0,
-      merged,
-      array;
-
-  while (++i < n) j += arrays[i].length;
-  merged = new Array(j);
-
-  while (--n >= 0) {
-    array = arrays[n];
-    m = array.length;
-    while (--m >= 0) {
-      merged[--j] = array[m];
-    }
-  }
-
-  return merged;
-}
-
-function min(values, valueof) {
-  var n = values.length,
-      i = -1,
-      value,
-      min;
-
-  if (valueof == null) {
-    while (++i < n) { // Find the first comparable value.
-      if ((value = values[i]) != null && value >= value) {
+    for (const value of values) {
+      if (defined
+          ? compare(value, min) < 0
+          : compare(value, value) === 0) {
         min = value;
-        while (++i < n) { // Compare the remaining values.
-          if ((value = values[i]) != null && min > value) {
-            min = value;
-          }
-        }
+        defined = true;
       }
     }
   }
-
-  else {
-    while (++i < n) { // Find the first comparable value.
-      if ((value = valueof(values[i], i, values)) != null && value >= value) {
-        min = value;
-        while (++i < n) { // Compare the remaining values.
-          if ((value = valueof(values[i], i, values)) != null && min > value) {
-            min = value;
-          }
-        }
-      }
-    }
-  }
-
   return min;
 }
 
-function permute(array, indexes) {
-  var i = indexes.length, permutes = new Array(i);
-  while (i--) permutes[i] = array[indexes[i]];
-  return permutes;
+function leastIndex(values, compare = ascending$3) {
+  if (compare.length === 1) return minIndex(values, compare);
+  let minValue;
+  let min = -1;
+  let index = -1;
+  for (const value of values) {
+    ++index;
+    if (min < 0
+        ? compare(value, value) === 0
+        : compare(value, minValue) < 0) {
+      minValue = value;
+      min = index;
+    }
+  }
+  return min;
+}
+
+function greatestIndex(values, compare = ascending$3) {
+  if (compare.length === 1) return maxIndex(values, compare);
+  let maxValue;
+  let max = -1;
+  let index = -1;
+  for (const value of values) {
+    ++index;
+    if (max < 0
+        ? compare(value, value) === 0
+        : compare(value, maxValue) > 0) {
+      maxValue = value;
+      max = index;
+    }
+  }
+  return max;
 }
 
 function scan(values, compare) {
-  if (!(n = values.length)) return;
-  var n,
-      i = 0,
-      j = 0,
-      xi,
-      xj = values[j];
-
-  if (compare == null) compare = ascending;
-
-  while (++i < n) {
-    if (compare(xi = values[i], xj) < 0 || compare(xj, xj) !== 0) {
-      xj = xi, j = i;
-    }
-  }
-
-  if (compare(xj, xj) === 0) return j;
+  const index = leastIndex(values, compare);
+  return index < 0 ? undefined : index;
 }
 
-function shuffle(array, i0, i1) {
-  var m = (i1 == null ? array.length : i1) - (i0 = i0 == null ? 0 : +i0),
-      t,
-      i;
+var shuffle$1 = shuffler(Math.random);
 
-  while (m) {
-    i = Math.random() * m-- | 0;
-    t = array[m + i0];
-    array[m + i0] = array[i + i0];
-    array[i + i0] = t;
-  }
-
-  return array;
+function shuffler(random) {
+  return function shuffle(array, i0 = 0, i1 = array.length) {
+    let m = i1 - (i0 = +i0);
+    while (m) {
+      const i = random() * m-- | 0, t = array[m + i0];
+      array[m + i0] = array[i + i0];
+      array[i + i0] = t;
+    }
+    return array;
+  };
 }
 
-function sum(values, valueof) {
-  var n = values.length,
-      i = -1,
-      value,
-      sum = 0;
-
-  if (valueof == null) {
-    while (++i < n) {
-      if (value = +values[i]) sum += value; // Note: zero and null are equivalent.
+function sum$2(values, valueof) {
+  let sum = 0;
+  if (valueof === undefined) {
+    for (let value of values) {
+      if (value = +value) {
+        sum += value;
+      }
+    }
+  } else {
+    let index = -1;
+    for (let value of values) {
+      if (value = +valueof(value, ++index, values)) {
+        sum += value;
+      }
     }
   }
-
-  else {
-    while (++i < n) {
-      if (value = +valueof(values[i], i, values)) sum += value;
-    }
-  }
-
   return sum;
 }
 
 function transpose(matrix) {
   if (!(n = matrix.length)) return [];
-  for (var i = -1, m = min(matrix, length), transpose = new Array(m); ++i < m;) {
+  for (var i = -1, m = min$2(matrix, length$2), transpose = new Array(m); ++i < m;) {
     for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) {
       row[j] = matrix[j][i];
     }
@@ -547,7 +1228,7 @@
   return transpose;
 }
 
-function length(d) {
+function length$2(d) {
   return d.length;
 }
 
@@ -555,9 +1236,143 @@
   return transpose(arguments);
 }
 
-var slice$1 = Array.prototype.slice;
+function every(values, test) {
+  if (typeof test !== "function") throw new TypeError("test is not a function");
+  let index = -1;
+  for (const value of values) {
+    if (!test(value, ++index, values)) {
+      return false;
+    }
+  }
+  return true;
+}
 
-function identity$1(x) {
+function some(values, test) {
+  if (typeof test !== "function") throw new TypeError("test is not a function");
+  let index = -1;
+  for (const value of values) {
+    if (test(value, ++index, values)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+function filter$1(values, test) {
+  if (typeof test !== "function") throw new TypeError("test is not a function");
+  const array = [];
+  let index = -1;
+  for (const value of values) {
+    if (test(value, ++index, values)) {
+      array.push(value);
+    }
+  }
+  return array;
+}
+
+function map$1(values, mapper) {
+  if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable");
+  if (typeof mapper !== "function") throw new TypeError("mapper is not a function");
+  return Array.from(values, (value, index) => mapper(value, index, values));
+}
+
+function reduce(values, reducer, value) {
+  if (typeof reducer !== "function") throw new TypeError("reducer is not a function");
+  const iterator = values[Symbol.iterator]();
+  let done, next, index = -1;
+  if (arguments.length < 3) {
+    ({done, value} = iterator.next());
+    if (done) return;
+    ++index;
+  }
+  while (({done, value: next} = iterator.next()), !done) {
+    value = reducer(value, next, ++index, values);
+  }
+  return value;
+}
+
+function reverse$1(values) {
+  if (typeof values[Symbol.iterator] !== "function") throw new TypeError("values is not iterable");
+  return Array.from(values).reverse();
+}
+
+function difference(values, ...others) {
+  values = new InternSet(values);
+  for (const other of others) {
+    for (const value of other) {
+      values.delete(value);
+    }
+  }
+  return values;
+}
+
+function disjoint(values, other) {
+  const iterator = other[Symbol.iterator](), set = new InternSet();
+  for (const v of values) {
+    if (set.has(v)) return false;
+    let value, done;
+    while (({value, done} = iterator.next())) {
+      if (done) break;
+      if (Object.is(v, value)) return false;
+      set.add(value);
+    }
+  }
+  return true;
+}
+
+function intersection(values, ...others) {
+  values = new InternSet(values);
+  others = others.map(set$2);
+  out: for (const value of values) {
+    for (const other of others) {
+      if (!other.has(value)) {
+        values.delete(value);
+        continue out;
+      }
+    }
+  }
+  return values;
+}
+
+function set$2(values) {
+  return values instanceof InternSet ? values : new InternSet(values);
+}
+
+function superset(values, other) {
+  const iterator = values[Symbol.iterator](), set = new Set();
+  for (const o of other) {
+    const io = intern(o);
+    if (set.has(io)) continue;
+    let value, done;
+    while (({value, done} = iterator.next())) {
+      if (done) return false;
+      const ivalue = intern(value);
+      set.add(ivalue);
+      if (Object.is(io, ivalue)) break;
+    }
+  }
+  return true;
+}
+
+function intern(value) {
+  return value !== null && typeof value === "object" ? value.valueOf() : value;
+}
+
+function subset(values, other) {
+  return superset(other, values);
+}
+
+function union(...others) {
+  const set = new InternSet();
+  for (const other of others) {
+    for (const o of other) {
+      set.add(o);
+    }
+  }
+  return set;
+}
+
+function identity$8(x) {
   return x;
 }
 
@@ -565,28 +1380,24 @@
     right = 2,
     bottom = 3,
     left = 4,
-    epsilon = 1e-6;
+    epsilon$6 = 1e-6;
 
 function translateX(x) {
-  return "translate(" + (x + 0.5) + ",0)";
+  return "translate(" + x + ",0)";
 }
 
 function translateY(y) {
-  return "translate(0," + (y + 0.5) + ")";
+  return "translate(0," + y + ")";
 }
 
-function number$1(scale) {
-  return function(d) {
-    return +scale(d);
-  };
+function number$2(scale) {
+  return d => +scale(d);
 }
 
-function center(scale) {
-  var offset = Math.max(0, scale.bandwidth() - 1) / 2; // Adjust for 0.5px offset.
+function center$1(scale, offset) {
+  offset = Math.max(0, scale.bandwidth() - offset * 2) / 2;
   if (scale.round()) offset = Math.round(offset);
-  return function(d) {
-    return +scale(d) + offset;
-  };
+  return d => +scale(d) + offset;
 }
 
 function entering() {
@@ -600,18 +1411,19 @@
       tickSizeInner = 6,
       tickSizeOuter = 6,
       tickPadding = 3,
+      offset = typeof window !== "undefined" && window.devicePixelRatio > 1 ? 0 : 0.5,
       k = orient === top || orient === left ? -1 : 1,
       x = orient === left || orient === right ? "x" : "y",
       transform = orient === top || orient === bottom ? translateX : translateY;
 
   function axis(context) {
     var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues,
-        format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity$1) : tickFormat,
+        format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity$8) : tickFormat,
         spacing = Math.max(tickSizeInner, 0) + tickPadding,
         range = scale.range(),
-        range0 = +range[0] + 0.5,
-        range1 = +range[range.length - 1] + 0.5,
-        position = (scale.bandwidth ? center : number$1)(scale.copy()),
+        range0 = +range[0] + offset,
+        range1 = +range[range.length - 1] + offset,
+        position = (scale.bandwidth ? center$1 : number$2)(scale.copy(), offset),
         selection = context.selection ? context.selection() : context,
         path = selection.selectAll(".domain").data([null]),
         tick = selection.selectAll(".tick").data(values, scale).order(),
@@ -642,24 +1454,24 @@
       text = text.transition(context);
 
       tickExit = tickExit.transition(context)
-          .attr("opacity", epsilon)
-          .attr("transform", function(d) { return isFinite(d = position(d)) ? transform(d) : this.getAttribute("transform"); });
+          .attr("opacity", epsilon$6)
+          .attr("transform", function(d) { return isFinite(d = position(d)) ? transform(d + offset) : this.getAttribute("transform"); });
 
       tickEnter
-          .attr("opacity", epsilon)
-          .attr("transform", function(d) { var p = this.parentNode.__axis; return transform(p && isFinite(p = p(d)) ? p : position(d)); });
+          .attr("opacity", epsilon$6)
+          .attr("transform", function(d) { var p = this.parentNode.__axis; return transform((p && isFinite(p = p(d)) ? p : position(d)) + offset); });
     }
 
     tickExit.remove();
 
     path
-        .attr("d", orient === left || orient == right
-            ? (tickSizeOuter ? "M" + k * tickSizeOuter + "," + range0 + "H0.5V" + range1 + "H" + k * tickSizeOuter : "M0.5," + range0 + "V" + range1)
-            : (tickSizeOuter ? "M" + range0 + "," + k * tickSizeOuter + "V0.5H" + range1 + "V" + k * tickSizeOuter : "M" + range0 + ",0.5H" + range1));
+        .attr("d", orient === left || orient === right
+            ? (tickSizeOuter ? "M" + k * tickSizeOuter + "," + range0 + "H" + offset + "V" + range1 + "H" + k * tickSizeOuter : "M" + offset + "," + range0 + "V" + range1)
+            : (tickSizeOuter ? "M" + range0 + "," + k * tickSizeOuter + "V" + offset + "H" + range1 + "V" + k * tickSizeOuter : "M" + range0 + "," + offset + "H" + range1));
 
     tick
         .attr("opacity", 1)
-        .attr("transform", function(d) { return transform(position(d)); });
+        .attr("transform", function(d) { return transform(position(d) + offset); });
 
     line
         .attr(x + "2", k * tickSizeInner);
@@ -683,15 +1495,15 @@
   };
 
   axis.ticks = function() {
-    return tickArguments = slice$1.call(arguments), axis;
+    return tickArguments = Array.from(arguments), axis;
   };
 
   axis.tickArguments = function(_) {
-    return arguments.length ? (tickArguments = _ == null ? [] : slice$1.call(_), axis) : tickArguments.slice();
+    return arguments.length ? (tickArguments = _ == null ? [] : Array.from(_), axis) : tickArguments.slice();
   };
 
   axis.tickValues = function(_) {
-    return arguments.length ? (tickValues = _ == null ? null : slice$1.call(_), axis) : tickValues && tickValues.slice();
+    return arguments.length ? (tickValues = _ == null ? null : Array.from(_), axis) : tickValues && tickValues.slice();
   };
 
   axis.tickFormat = function(_) {
@@ -714,6 +1526,10 @@
     return arguments.length ? (tickPadding = +_, axis) : tickPadding;
   };
 
+  axis.offset = function(_) {
+    return arguments.length ? (offset = +_, axis) : offset;
+  };
+
   return axis;
 }
 
@@ -733,7 +1549,7 @@
   return axis(left, scale);
 }
 
-var noop = {value: function() {}};
+var noop$3 = {value: () => {}};
 
 function dispatch() {
   for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
@@ -747,7 +1563,7 @@
   this._ = _;
 }
 
-function parseTypenames(typenames, types) {
+function parseTypenames$1(typenames, types) {
   return typenames.trim().split(/^|\s+/).map(function(t) {
     var name = "", i = t.indexOf(".");
     if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
@@ -760,14 +1576,14 @@
   constructor: Dispatch,
   on: function(typename, callback) {
     var _ = this._,
-        T = parseTypenames(typename + "", _),
+        T = parseTypenames$1(typename + "", _),
         t,
         i = -1,
         n = T.length;
 
     // If no callback was specified, return the callback of the given type and name.
     if (arguments.length < 2) {
-      while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
+      while (++i < n) if ((t = (typename = T[i]).type) && (t = get$1(_[t], typename.name))) return t;
       return;
     }
 
@@ -775,8 +1591,8 @@
     // Otherwise, if a null callback was specified, remove callbacks of the given name.
     if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
     while (++i < n) {
-      if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback);
-      else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null);
+      if (t = (typename = T[i]).type) _[t] = set$1(_[t], typename.name, callback);
+      else if (callback == null) for (t in _) _[t] = set$1(_[t], typename.name, null);
     }
 
     return this;
@@ -797,7 +1613,7 @@
   }
 };
 
-function get(type, name) {
+function get$1(type, name) {
   for (var i = 0, n = type.length, c; i < n; ++i) {
     if ((c = type[i]).name === name) {
       return c.value;
@@ -805,10 +1621,10 @@
   }
 }
 
-function set(type, name, callback) {
+function set$1(type, name, callback) {
   for (var i = 0, n = type.length; i < n; ++i) {
     if (type[i].name === name) {
-      type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
+      type[i] = noop$3, type = type.slice(0, i).concat(type.slice(i + 1));
       break;
     }
   }
@@ -829,7 +1645,7 @@
 function namespace(name) {
   var prefix = name += "", i = prefix.indexOf(":");
   if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
-  return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name;
+  return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name; // eslint-disable-line no-prototype-builtins
 }
 
 function creatorInherit(name) {
@@ -855,10 +1671,10 @@
       : creatorInherit)(fullname);
 }
 
-function none() {}
+function none$2() {}
 
 function selector(selector) {
-  return selector == null ? none : function() {
+  return selector == null ? none$2 : function() {
     return this.querySelector(selector);
   };
 }
@@ -875,21 +1691,38 @@
     }
   }
 
-  return new Selection(subgroups, this._parents);
+  return new Selection$1(subgroups, this._parents);
 }
 
-function empty() {
+// Given something array like (or null), returns something that is strictly an
+// array. This is used to ensure that array-like objects passed to d3.selectAll
+// or selection.selectAll are converted into proper arrays when creating a
+// selection; we don’t ever want to create a selection backed by a live
+// HTMLCollection or NodeList. However, note that selection.selectAll will use a
+// static NodeList as a group, since it safely derived from querySelectorAll.
+function array$4(x) {
+  return x == null ? [] : Array.isArray(x) ? x : Array.from(x);
+}
+
+function empty$1() {
   return [];
 }
 
 function selectorAll(selector) {
-  return selector == null ? empty : function() {
+  return selector == null ? empty$1 : function() {
     return this.querySelectorAll(selector);
   };
 }
 
+function arrayAll(select) {
+  return function() {
+    return array$4(select.apply(this, arguments));
+  };
+}
+
 function selection_selectAll(select) {
-  if (typeof select !== "function") select = selectorAll(select);
+  if (typeof select === "function") select = arrayAll(select);
+  else select = selectorAll(select);
 
   for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
@@ -900,7 +1733,7 @@
     }
   }
 
-  return new Selection(subgroups, parents);
+  return new Selection$1(subgroups, parents);
 }
 
 function matcher(selector) {
@@ -909,6 +1742,46 @@
   };
 }
 
+function childMatcher(selector) {
+  return function(node) {
+    return node.matches(selector);
+  };
+}
+
+var find$1 = Array.prototype.find;
+
+function childFind(match) {
+  return function() {
+    return find$1.call(this.children, match);
+  };
+}
+
+function childFirst() {
+  return this.firstElementChild;
+}
+
+function selection_selectChild(match) {
+  return this.select(match == null ? childFirst
+      : childFind(typeof match === "function" ? match : childMatcher(match)));
+}
+
+var filter = Array.prototype.filter;
+
+function children() {
+  return Array.from(this.children);
+}
+
+function childrenFilter(match) {
+  return function() {
+    return filter.call(this.children, match);
+  };
+}
+
+function selection_selectChildren(match) {
+  return this.selectAll(match == null ? children
+      : childrenFilter(typeof match === "function" ? match : childMatcher(match)));
+}
+
 function selection_filter(match) {
   if (typeof match !== "function") match = matcher(match);
 
@@ -920,7 +1793,7 @@
     }
   }
 
-  return new Selection(subgroups, this._parents);
+  return new Selection$1(subgroups, this._parents);
 }
 
 function sparse(update) {
@@ -928,7 +1801,7 @@
 }
 
 function selection_enter() {
-  return new Selection(this._enter || this._groups.map(sparse), this._parents);
+  return new Selection$1(this._enter || this._groups.map(sparse), this._parents);
 }
 
 function EnterNode(parent, datum) {
@@ -947,14 +1820,12 @@
   querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); }
 };
 
-function constant$1(x) {
+function constant$a(x) {
   return function() {
     return x;
   };
 }
 
-var keyPrefix = "$"; // Protect against keys like “__proto__”.
-
 function bindIndex(parent, group, enter, update, exit, data) {
   var i = 0,
       node,
@@ -984,7 +1855,7 @@
 function bindKey(parent, group, enter, update, exit, data, key) {
   var i,
       node,
-      nodeByKeyValue = {},
+      nodeByKeyValue = new Map,
       groupLength = group.length,
       dataLength = data.length,
       keyValues = new Array(groupLength),
@@ -994,11 +1865,11 @@
   // If multiple nodes have the same key, the duplicates are added to exit.
   for (i = 0; i < groupLength; ++i) {
     if (node = group[i]) {
-      keyValues[i] = keyValue = keyPrefix + key.call(node, node.__data__, i, group);
-      if (keyValue in nodeByKeyValue) {
+      keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + "";
+      if (nodeByKeyValue.has(keyValue)) {
         exit[i] = node;
       } else {
-        nodeByKeyValue[keyValue] = node;
+        nodeByKeyValue.set(keyValue, node);
       }
     }
   }
@@ -1007,11 +1878,11 @@
   // If there a node associated with this key, join and add it to update.
   // If there is not (or the key is a duplicate), add it to enter.
   for (i = 0; i < dataLength; ++i) {
-    keyValue = keyPrefix + key.call(parent, data[i], i, data);
-    if (node = nodeByKeyValue[keyValue]) {
+    keyValue = key.call(parent, data[i], i, data) + "";
+    if (node = nodeByKeyValue.get(keyValue)) {
       update[i] = node;
       node.__data__ = data[i];
-      nodeByKeyValue[keyValue] = null;
+      nodeByKeyValue.delete(keyValue);
     } else {
       enter[i] = new EnterNode(parent, data[i]);
     }
@@ -1019,30 +1890,30 @@
 
   // Add any remaining nodes that were not bound to data to exit.
   for (i = 0; i < groupLength; ++i) {
-    if ((node = group[i]) && (nodeByKeyValue[keyValues[i]] === node)) {
+    if ((node = group[i]) && (nodeByKeyValue.get(keyValues[i]) === node)) {
       exit[i] = node;
     }
   }
 }
 
+function datum(node) {
+  return node.__data__;
+}
+
 function selection_data(value, key) {
-  if (!value) {
-    data = new Array(this.size()), j = -1;
-    this.each(function(d) { data[++j] = d; });
-    return data;
-  }
+  if (!arguments.length) return Array.from(this, datum);
 
   var bind = key ? bindKey : bindIndex,
       parents = this._parents,
       groups = this._groups;
 
-  if (typeof value !== "function") value = constant$1(value);
+  if (typeof value !== "function") value = constant$a(value);
 
   for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
     var parent = parents[j],
         group = groups[j],
         groupLength = group.length,
-        data = value.call(parent, parent && parent.__data__, j, parents),
+        data = arraylike(value.call(parent, parent && parent.__data__, j, parents)),
         dataLength = data.length,
         enterGroup = enter[j] = new Array(dataLength),
         updateGroup = update[j] = new Array(dataLength),
@@ -1062,25 +1933,46 @@
     }
   }
 
-  update = new Selection(update, parents);
+  update = new Selection$1(update, parents);
   update._enter = enter;
   update._exit = exit;
   return update;
 }
 
+// Given some data, this returns an array-like view of it: an object that
+// exposes a length property and allows numeric indexing. Note that unlike
+// selectAll, this isn’t worried about “live” collections because the resulting
+// array will only be used briefly while data is being bound. (It is possible to
+// cause the data to change while iterating by using a key function, but please
+// don’t; we’d rather avoid a gratuitous copy.)
+function arraylike(data) {
+  return typeof data === "object" && "length" in data
+    ? data // Array, TypedArray, NodeList, array-like
+    : Array.from(data); // Map, Set, iterable, string, or anything else
+}
+
 function selection_exit() {
-  return new Selection(this._exit || this._groups.map(sparse), this._parents);
+  return new Selection$1(this._exit || this._groups.map(sparse), this._parents);
 }
 
 function selection_join(onenter, onupdate, onexit) {
   var enter = this.enter(), update = this, exit = this.exit();
-  enter = typeof onenter === "function" ? onenter(enter) : enter.append(onenter + "");
-  if (onupdate != null) update = onupdate(update);
+  if (typeof onenter === "function") {
+    enter = onenter(enter);
+    if (enter) enter = enter.selection();
+  } else {
+    enter = enter.append(onenter + "");
+  }
+  if (onupdate != null) {
+    update = onupdate(update);
+    if (update) update = update.selection();
+  }
   if (onexit == null) exit.remove(); else onexit(exit);
   return enter && update ? enter.merge(update).order() : update;
 }
 
-function selection_merge(selection) {
+function selection_merge(context) {
+  var selection = context.selection ? context.selection() : context;
 
   for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
     for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
@@ -1094,7 +1986,7 @@
     merges[j] = groups0[j];
   }
 
-  return new Selection(merges, this._parents);
+  return new Selection$1(merges, this._parents);
 }
 
 function selection_order() {
@@ -1112,7 +2004,7 @@
 }
 
 function selection_sort(compare) {
-  if (!compare) compare = ascending$1;
+  if (!compare) compare = ascending$2;
 
   function compareNode(a, b) {
     return a && b ? compare(a.__data__, b.__data__) : !a - !b;
@@ -1127,10 +2019,10 @@
     sortgroup.sort(compareNode);
   }
 
-  return new Selection(sortgroups, this._parents).order();
+  return new Selection$1(sortgroups, this._parents).order();
 }
 
-function ascending$1(a, b) {
+function ascending$2(a, b) {
   return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
 }
 
@@ -1142,9 +2034,7 @@
 }
 
 function selection_nodes() {
-  var nodes = new Array(this.size()), i = -1;
-  this.each(function() { nodes[++i] = this; });
-  return nodes;
+  return Array.from(this);
 }
 
 function selection_node() {
@@ -1160,8 +2050,8 @@
 }
 
 function selection_size() {
-  var size = 0;
-  this.each(function() { ++size; });
+  let size = 0;
+  for (const node of this) ++size; // eslint-disable-line no-unused-vars
   return size;
 }
 
@@ -1180,31 +2070,31 @@
   return this;
 }
 
-function attrRemove(name) {
+function attrRemove$1(name) {
   return function() {
     this.removeAttribute(name);
   };
 }
 
-function attrRemoveNS(fullname) {
+function attrRemoveNS$1(fullname) {
   return function() {
     this.removeAttributeNS(fullname.space, fullname.local);
   };
 }
 
-function attrConstant(name, value) {
+function attrConstant$1(name, value) {
   return function() {
     this.setAttribute(name, value);
   };
 }
 
-function attrConstantNS(fullname, value) {
+function attrConstantNS$1(fullname, value) {
   return function() {
     this.setAttributeNS(fullname.space, fullname.local, value);
   };
 }
 
-function attrFunction(name, value) {
+function attrFunction$1(name, value) {
   return function() {
     var v = value.apply(this, arguments);
     if (v == null) this.removeAttribute(name);
@@ -1212,7 +2102,7 @@
   };
 }
 
-function attrFunctionNS(fullname, value) {
+function attrFunctionNS$1(fullname, value) {
   return function() {
     var v = value.apply(this, arguments);
     if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
@@ -1231,9 +2121,9 @@
   }
 
   return this.each((value == null
-      ? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === "function"
-      ? (fullname.local ? attrFunctionNS : attrFunction)
-      : (fullname.local ? attrConstantNS : attrConstant)))(fullname, value));
+      ? (fullname.local ? attrRemoveNS$1 : attrRemove$1) : (typeof value === "function"
+      ? (fullname.local ? attrFunctionNS$1 : attrFunction$1)
+      : (fullname.local ? attrConstantNS$1 : attrConstant$1)))(fullname, value));
 }
 
 function defaultView(node) {
@@ -1242,19 +2132,19 @@
       || node.defaultView; // node is a Document
 }
 
-function styleRemove(name) {
+function styleRemove$1(name) {
   return function() {
     this.style.removeProperty(name);
   };
 }
 
-function styleConstant(name, value, priority) {
+function styleConstant$1(name, value, priority) {
   return function() {
     this.style.setProperty(name, value, priority);
   };
 }
 
-function styleFunction(name, value, priority) {
+function styleFunction$1(name, value, priority) {
   return function() {
     var v = value.apply(this, arguments);
     if (v == null) this.style.removeProperty(name);
@@ -1265,9 +2155,9 @@
 function selection_style(name, value, priority) {
   return arguments.length > 1
       ? this.each((value == null
-            ? styleRemove : typeof value === "function"
-            ? styleFunction
-            : styleConstant)(name, value, priority == null ? "" : priority))
+            ? styleRemove$1 : typeof value === "function"
+            ? styleFunction$1
+            : styleConstant$1)(name, value, priority == null ? "" : priority))
       : styleValue(this.node(), name);
 }
 
@@ -1385,13 +2275,13 @@
   this.textContent = "";
 }
 
-function textConstant(value) {
+function textConstant$1(value) {
   return function() {
     this.textContent = value;
   };
 }
 
-function textFunction(value) {
+function textFunction$1(value) {
   return function() {
     var v = value.apply(this, arguments);
     this.textContent = v == null ? "" : v;
@@ -1402,8 +2292,8 @@
   return arguments.length
       ? this.each(value == null
           ? textRemove : (typeof value === "function"
-          ? textFunction
-          : textConstant)(value))
+          ? textFunction$1
+          : textConstant$1)(value))
       : this.node().textContent;
 }
 
@@ -1497,40 +2387,13 @@
       : this.node().__data__;
 }
 
-var filterEvents = {};
-
-exports.event = null;
-
-if (typeof document !== "undefined") {
-  var element = document.documentElement;
-  if (!("onmouseenter" in element)) {
-    filterEvents = {mouseenter: "mouseover", mouseleave: "mouseout"};
-  }
-}
-
-function filterContextListener(listener, index, group) {
-  listener = contextListener(listener, index, group);
+function contextListener(listener) {
   return function(event) {
-    var related = event.relatedTarget;
-    if (!related || (related !== this && !(related.compareDocumentPosition(this) & 8))) {
-      listener.call(this, event);
-    }
+    listener.call(this, event, this.__data__);
   };
 }
 
-function contextListener(listener, index, group) {
-  return function(event1) {
-    var event0 = exports.event; // Events can be reentrant (e.g., focus).
-    exports.event = event1;
-    try {
-      listener.call(this, this.__data__, index, group);
-    } finally {
-      exports.event = event0;
-    }
-  };
-}
-
-function parseTypenames$1(typenames) {
+function parseTypenames(typenames) {
   return typenames.trim().split(/^|\s+/).map(function(t) {
     var name = "", i = t.indexOf(".");
     if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
@@ -1544,7 +2407,7 @@
     if (!on) return;
     for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
       if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
-        this.removeEventListener(o.type, o.listener, o.capture);
+        this.removeEventListener(o.type, o.listener, o.options);
       } else {
         on[++i] = o;
       }
@@ -1554,27 +2417,26 @@
   };
 }
 
-function onAdd(typename, value, capture) {
-  var wrap = filterEvents.hasOwnProperty(typename.type) ? filterContextListener : contextListener;
-  return function(d, i, group) {
-    var on = this.__on, o, listener = wrap(value, i, group);
+function onAdd(typename, value, options) {
+  return function() {
+    var on = this.__on, o, listener = contextListener(value);
     if (on) for (var j = 0, m = on.length; j < m; ++j) {
       if ((o = on[j]).type === typename.type && o.name === typename.name) {
-        this.removeEventListener(o.type, o.listener, o.capture);
-        this.addEventListener(o.type, o.listener = listener, o.capture = capture);
+        this.removeEventListener(o.type, o.listener, o.options);
+        this.addEventListener(o.type, o.listener = listener, o.options = options);
         o.value = value;
         return;
       }
     }
-    this.addEventListener(typename.type, listener, capture);
-    o = {type: typename.type, name: typename.name, value: value, listener: listener, capture: capture};
+    this.addEventListener(typename.type, listener, options);
+    o = {type: typename.type, name: typename.name, value: value, listener: listener, options: options};
     if (!on) this.__on = [o];
     else on.push(o);
   };
 }
 
-function selection_on(typename, value, capture) {
-  var typenames = parseTypenames$1(typename + ""), i, n = typenames.length, t;
+function selection_on(typename, value, options) {
+  var typenames = parseTypenames(typename + ""), i, n = typenames.length, t;
 
   if (arguments.length < 2) {
     var on = this.node().__on;
@@ -1589,22 +2451,10 @@
   }
 
   on = value ? onAdd : onRemove;
-  if (capture == null) capture = false;
-  for (i = 0; i < n; ++i) this.each(on(typenames[i], value, capture));
+  for (i = 0; i < n; ++i) this.each(on(typenames[i], value, options));
   return this;
 }
 
-function customEvent(event1, listener, that, args) {
-  var event0 = exports.event;
-  event1.sourceEvent = exports.event;
-  exports.event = event1;
-  try {
-    return listener.apply(that, args);
-  } finally {
-    exports.event = event0;
-  }
-}
-
 function dispatchEvent(node, type, params) {
   var window = defaultView(node),
       event = window.CustomEvent;
@@ -1638,27 +2488,42 @@
       : dispatchConstant)(type, params));
 }
 
-var root = [null];
+function* selection_iterator() {
+  for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
+    for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
+      if (node = group[i]) yield node;
+    }
+  }
+}
 
-function Selection(groups, parents) {
+var root$1 = [null];
+
+function Selection$1(groups, parents) {
   this._groups = groups;
   this._parents = parents;
 }
 
 function selection() {
-  return new Selection([[document.documentElement]], root);
+  return new Selection$1([[document.documentElement]], root$1);
 }
 
-Selection.prototype = selection.prototype = {
-  constructor: Selection,
+function selection_selection() {
+  return this;
+}
+
+Selection$1.prototype = selection.prototype = {
+  constructor: Selection$1,
   select: selection_select,
   selectAll: selection_selectAll,
+  selectChild: selection_selectChild,
+  selectChildren: selection_selectChildren,
   filter: selection_filter,
   data: selection_data,
   enter: selection_enter,
   exit: selection_exit,
   join: selection_join,
   merge: selection_merge,
+  selection: selection_selection,
   order: selection_order,
   sort: selection_sort,
   call: selection_call,
@@ -1681,22 +2546,23 @@
   clone: selection_clone,
   datum: selection_datum,
   on: selection_on,
-  dispatch: selection_dispatch
+  dispatch: selection_dispatch,
+  [Symbol.iterator]: selection_iterator
 };
 
 function select(selector) {
   return typeof selector === "string"
-      ? new Selection([[document.querySelector(selector)]], [document.documentElement])
-      : new Selection([[selector]], root);
+      ? new Selection$1([[document.querySelector(selector)]], [document.documentElement])
+      : new Selection$1([[selector]], root$1);
 }
 
-function create(name) {
+function create$1(name) {
   return select(creator(name).call(document.documentElement));
 }
 
 var nextId = 0;
 
-function local() {
+function local$1() {
   return new Local;
 }
 
@@ -1704,7 +2570,7 @@
   this._ = "@" + (++nextId).toString(36);
 }
 
-Local.prototype = local.prototype = {
+Local.prototype = local$1.prototype = {
   constructor: Local,
   get: function(node) {
     var id = this._;
@@ -1722,74 +2588,65 @@
   }
 };
 
-function sourceEvent() {
-  var current = exports.event, source;
-  while (source = current.sourceEvent) current = source;
-  return current;
+function sourceEvent(event) {
+  let sourceEvent;
+  while (sourceEvent = event.sourceEvent) event = sourceEvent;
+  return event;
 }
 
-function point(node, event) {
-  var svg = node.ownerSVGElement || node;
-
-  if (svg.createSVGPoint) {
-    var point = svg.createSVGPoint();
-    point.x = event.clientX, point.y = event.clientY;
-    point = point.matrixTransform(node.getScreenCTM().inverse());
-    return [point.x, point.y];
+function pointer(event, node) {
+  event = sourceEvent(event);
+  if (node === undefined) node = event.currentTarget;
+  if (node) {
+    var svg = node.ownerSVGElement || node;
+    if (svg.createSVGPoint) {
+      var point = svg.createSVGPoint();
+      point.x = event.clientX, point.y = event.clientY;
+      point = point.matrixTransform(node.getScreenCTM().inverse());
+      return [point.x, point.y];
+    }
+    if (node.getBoundingClientRect) {
+      var rect = node.getBoundingClientRect();
+      return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
+    }
   }
-
-  var rect = node.getBoundingClientRect();
-  return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
+  return [event.pageX, event.pageY];
 }
 
-function mouse(node) {
-  var event = sourceEvent();
-  if (event.changedTouches) event = event.changedTouches[0];
-  return point(node, event);
+function pointers(events, node) {
+  if (events.target) { // i.e., instanceof Event, not TouchList or iterable
+    events = sourceEvent(events);
+    if (node === undefined) node = events.currentTarget;
+    events = events.touches || [events];
+  }
+  return Array.from(events, event => pointer(event, node));
 }
 
 function selectAll(selector) {
   return typeof selector === "string"
-      ? new Selection([document.querySelectorAll(selector)], [document.documentElement])
-      : new Selection([selector == null ? [] : selector], root);
+      ? new Selection$1([document.querySelectorAll(selector)], [document.documentElement])
+      : new Selection$1([array$4(selector)], root$1);
 }
 
-function touch(node, touches, identifier) {
-  if (arguments.length < 3) identifier = touches, touches = sourceEvent().changedTouches;
+// These are typically used in conjunction with noevent to ensure that we can
+// preventDefault on the event.
+const nonpassive = {passive: false};
+const nonpassivecapture = {capture: true, passive: false};
 
-  for (var i = 0, n = touches ? touches.length : 0, touch; i < n; ++i) {
-    if ((touch = touches[i]).identifier === identifier) {
-      return point(node, touch);
-    }
-  }
-
-  return null;
+function nopropagation$2(event) {
+  event.stopImmediatePropagation();
 }
 
-function touches(node, touches) {
-  if (touches == null) touches = sourceEvent().touches;
-
-  for (var i = 0, n = touches ? touches.length : 0, points = new Array(n); i < n; ++i) {
-    points[i] = point(node, touches[i]);
-  }
-
-  return points;
-}
-
-function nopropagation() {
-  exports.event.stopImmediatePropagation();
-}
-
-function noevent() {
-  exports.event.preventDefault();
-  exports.event.stopImmediatePropagation();
+function noevent$2(event) {
+  event.preventDefault();
+  event.stopImmediatePropagation();
 }
 
 function dragDisable(view) {
   var root = view.document.documentElement,
-      selection = select(view).on("dragstart.drag", noevent, true);
+      selection = select(view).on("dragstart.drag", noevent$2, nonpassivecapture);
   if ("onselectstart" in root) {
-    selection.on("selectstart.drag", noevent, true);
+    selection.on("selectstart.drag", noevent$2, nonpassivecapture);
   } else {
     root.__noselect = root.style.MozUserSelect;
     root.style.MozUserSelect = "none";
@@ -1800,7 +2657,7 @@
   var root = view.document.documentElement,
       selection = select(view).on("dragstart.drag", null);
   if (noclick) {
-    selection.on("click.drag", noevent, true);
+    selection.on("click.drag", noevent$2, nonpassivecapture);
     setTimeout(function() { selection.on("click.drag", null); }, 0);
   }
   if ("onselectstart" in root) {
@@ -1811,23 +2668,30 @@
   }
 }
 
-function constant$2(x) {
-  return function() {
-    return x;
-  };
-}
+var constant$9 = x => () => x;
 
-function DragEvent(target, type, subject, id, active, x, y, dx, dy, dispatch) {
-  this.target = target;
-  this.type = type;
-  this.subject = subject;
-  this.identifier = id;
-  this.active = active;
-  this.x = x;
-  this.y = y;
-  this.dx = dx;
-  this.dy = dy;
-  this._ = dispatch;
+function DragEvent(type, {
+  sourceEvent,
+  subject,
+  target,
+  identifier,
+  active,
+  x, y, dx, dy,
+  dispatch
+}) {
+  Object.defineProperties(this, {
+    type: {value: type, enumerable: true, configurable: true},
+    sourceEvent: {value: sourceEvent, enumerable: true, configurable: true},
+    subject: {value: subject, enumerable: true, configurable: true},
+    target: {value: target, enumerable: true, configurable: true},
+    identifier: {value: identifier, enumerable: true, configurable: true},
+    active: {value: active, enumerable: true, configurable: true},
+    x: {value: x, enumerable: true, configurable: true},
+    y: {value: y, enumerable: true, configurable: true},
+    dx: {value: dx, enumerable: true, configurable: true},
+    dy: {value: dy, enumerable: true, configurable: true},
+    _: {value: dispatch}
+  });
 }
 
 DragEvent.prototype.on = function() {
@@ -1836,27 +2700,27 @@
 };
 
 // Ignore right-click, since that should open the context menu.
-function defaultFilter() {
-  return !exports.event.ctrlKey && !exports.event.button;
+function defaultFilter$2(event) {
+  return !event.ctrlKey && !event.button;
 }
 
 function defaultContainer() {
   return this.parentNode;
 }
 
-function defaultSubject(d) {
-  return d == null ? {x: exports.event.x, y: exports.event.y} : d;
+function defaultSubject(event, d) {
+  return d == null ? {x: event.x, y: event.y} : d;
 }
 
-function defaultTouchable() {
+function defaultTouchable$2() {
   return navigator.maxTouchPoints || ("ontouchstart" in this);
 }
 
 function drag() {
-  var filter = defaultFilter,
+  var filter = defaultFilter$2,
       container = defaultContainer,
       subject = defaultSubject,
-      touchable = defaultTouchable,
+      touchable = defaultTouchable$2,
       gestures = {},
       listeners = dispatch("start", "drag", "end"),
       active = 0,
@@ -1871,117 +2735,144 @@
         .on("mousedown.drag", mousedowned)
       .filter(touchable)
         .on("touchstart.drag", touchstarted)
-        .on("touchmove.drag", touchmoved)
+        .on("touchmove.drag", touchmoved, nonpassive)
         .on("touchend.drag touchcancel.drag", touchended)
         .style("touch-action", "none")
         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
   }
 
-  function mousedowned() {
-    if (touchending || !filter.apply(this, arguments)) return;
-    var gesture = beforestart("mouse", container.apply(this, arguments), mouse, this, arguments);
+  function mousedowned(event, d) {
+    if (touchending || !filter.call(this, event, d)) return;
+    var gesture = beforestart(this, container.call(this, event, d), event, d, "mouse");
     if (!gesture) return;
-    select(exports.event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
-    dragDisable(exports.event.view);
-    nopropagation();
+    select(event.view)
+      .on("mousemove.drag", mousemoved, nonpassivecapture)
+      .on("mouseup.drag", mouseupped, nonpassivecapture);
+    dragDisable(event.view);
+    nopropagation$2(event);
     mousemoving = false;
-    mousedownx = exports.event.clientX;
-    mousedowny = exports.event.clientY;
-    gesture("start");
+    mousedownx = event.clientX;
+    mousedowny = event.clientY;
+    gesture("start", event);
   }
 
-  function mousemoved() {
-    noevent();
+  function mousemoved(event) {
+    noevent$2(event);
     if (!mousemoving) {
-      var dx = exports.event.clientX - mousedownx, dy = exports.event.clientY - mousedowny;
+      var dx = event.clientX - mousedownx, dy = event.clientY - mousedowny;
       mousemoving = dx * dx + dy * dy > clickDistance2;
     }
-    gestures.mouse("drag");
+    gestures.mouse("drag", event);
   }
 
-  function mouseupped() {
-    select(exports.event.view).on("mousemove.drag mouseup.drag", null);
-    yesdrag(exports.event.view, mousemoving);
-    noevent();
-    gestures.mouse("end");
+  function mouseupped(event) {
+    select(event.view).on("mousemove.drag mouseup.drag", null);
+    yesdrag(event.view, mousemoving);
+    noevent$2(event);
+    gestures.mouse("end", event);
   }
 
-  function touchstarted() {
-    if (!filter.apply(this, arguments)) return;
-    var touches = exports.event.changedTouches,
-        c = container.apply(this, arguments),
+  function touchstarted(event, d) {
+    if (!filter.call(this, event, d)) return;
+    var touches = event.changedTouches,
+        c = container.call(this, event, d),
         n = touches.length, i, gesture;
 
     for (i = 0; i < n; ++i) {
-      if (gesture = beforestart(touches[i].identifier, c, touch, this, arguments)) {
-        nopropagation();
-        gesture("start");
+      if (gesture = beforestart(this, c, event, d, touches[i].identifier, touches[i])) {
+        nopropagation$2(event);
+        gesture("start", event, touches[i]);
       }
     }
   }
 
-  function touchmoved() {
-    var touches = exports.event.changedTouches,
+  function touchmoved(event) {
+    var touches = event.changedTouches,
         n = touches.length, i, gesture;
 
     for (i = 0; i < n; ++i) {
       if (gesture = gestures[touches[i].identifier]) {
-        noevent();
-        gesture("drag");
+        noevent$2(event);
+        gesture("drag", event, touches[i]);
       }
     }
   }
 
-  function touchended() {
-    var touches = exports.event.changedTouches,
+  function touchended(event) {
+    var touches = event.changedTouches,
         n = touches.length, i, gesture;
 
     if (touchending) clearTimeout(touchending);
     touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
     for (i = 0; i < n; ++i) {
       if (gesture = gestures[touches[i].identifier]) {
-        nopropagation();
-        gesture("end");
+        nopropagation$2(event);
+        gesture("end", event, touches[i]);
       }
     }
   }
 
-  function beforestart(id, container, point, that, args) {
-    var p = point(container, id), s, dx, dy,
-        sublisteners = listeners.copy();
+  function beforestart(that, container, event, d, identifier, touch) {
+    var dispatch = listeners.copy(),
+        p = pointer(touch || event, container), dx, dy,
+        s;
 
-    if (!customEvent(new DragEvent(drag, "beforestart", s, id, active, p[0], p[1], 0, 0, sublisteners), function() {
-      if ((exports.event.subject = s = subject.apply(that, args)) == null) return false;
-      dx = s.x - p[0] || 0;
-      dy = s.y - p[1] || 0;
-      return true;
-    })) return;
+    if ((s = subject.call(that, new DragEvent("beforestart", {
+        sourceEvent: event,
+        target: drag,
+        identifier,
+        active,
+        x: p[0],
+        y: p[1],
+        dx: 0,
+        dy: 0,
+        dispatch
+      }), d)) == null) return;
 
-    return function gesture(type) {
+    dx = s.x - p[0] || 0;
+    dy = s.y - p[1] || 0;
+
+    return function gesture(type, event, touch) {
       var p0 = p, n;
       switch (type) {
-        case "start": gestures[id] = gesture, n = active++; break;
-        case "end": delete gestures[id], --active; // nobreak
-        case "drag": p = point(container, id), n = active; break;
+        case "start": gestures[identifier] = gesture, n = active++; break;
+        case "end": delete gestures[identifier], --active; // falls through
+        case "drag": p = pointer(touch || event, container), n = active; break;
       }
-      customEvent(new DragEvent(drag, type, s, id, n, p[0] + dx, p[1] + dy, p[0] - p0[0], p[1] - p0[1], sublisteners), sublisteners.apply, sublisteners, [type, that, args]);
+      dispatch.call(
+        type,
+        that,
+        new DragEvent(type, {
+          sourceEvent: event,
+          subject: s,
+          target: drag,
+          identifier,
+          active: n,
+          x: p[0] + dx,
+          y: p[1] + dy,
+          dx: p[0] - p0[0],
+          dy: p[1] - p0[1],
+          dispatch
+        }),
+        d
+      );
     };
   }
 
   drag.filter = function(_) {
-    return arguments.length ? (filter = typeof _ === "function" ? _ : constant$2(!!_), drag) : filter;
+    return arguments.length ? (filter = typeof _ === "function" ? _ : constant$9(!!_), drag) : filter;
   };
 
   drag.container = function(_) {
-    return arguments.length ? (container = typeof _ === "function" ? _ : constant$2(_), drag) : container;
+    return arguments.length ? (container = typeof _ === "function" ? _ : constant$9(_), drag) : container;
   };
 
   drag.subject = function(_) {
-    return arguments.length ? (subject = typeof _ === "function" ? _ : constant$2(_), drag) : subject;
+    return arguments.length ? (subject = typeof _ === "function" ? _ : constant$9(_), drag) : subject;
   };
 
   drag.touchable = function(_) {
-    return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$2(!!_), drag) : touchable;
+    return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$9(!!_), drag) : touchable;
   };
 
   drag.on = function() {
@@ -2013,15 +2904,15 @@
 var brighter = 1 / darker;
 
 var reI = "\\s*([+-]?\\d+)\\s*",
-    reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",
-    reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",
+    reN = "\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)\\s*",
+    reP = "\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)%\\s*",
     reHex = /^#([0-9a-f]{3,8})$/,
-    reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"),
-    reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"),
-    reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"),
-    reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$"),
-    reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$"),
-    reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
+    reRgbInteger = new RegExp(`^rgb\\(${reI},${reI},${reI}\\)$`),
+    reRgbPercent = new RegExp(`^rgb\\(${reP},${reP},${reP}\\)$`),
+    reRgbaInteger = new RegExp(`^rgba\\(${reI},${reI},${reI},${reN}\\)$`),
+    reRgbaPercent = new RegExp(`^rgba\\(${reP},${reP},${reP},${reN}\\)$`),
+    reHslPercent = new RegExp(`^hsl\\(${reN},${reP},${reP}\\)$`),
+    reHslaPercent = new RegExp(`^hsla\\(${reN},${reP},${reP},${reN}\\)$`);
 
 var named = {
   aliceblue: 0xf0f8ff,
@@ -2175,14 +3066,15 @@
 };
 
 define(Color, color, {
-  copy: function(channels) {
+  copy(channels) {
     return Object.assign(new this.constructor, this, channels);
   },
-  displayable: function() {
+  displayable() {
     return this.rgb().displayable();
   },
   hex: color_formatHex, // Deprecated! Use color.formatHex.
   formatHex: color_formatHex,
+  formatHex8: color_formatHex8,
   formatHsl: color_formatHsl,
   formatRgb: color_formatRgb,
   toString: color_formatRgb
@@ -2192,6 +3084,10 @@
   return this.rgb().formatHex();
 }
 
+function color_formatHex8() {
+  return this.rgb().formatHex8();
+}
+
 function color_formatHsl() {
   return hslConvert(this).formatHsl();
 }
@@ -2247,18 +3143,21 @@
 }
 
 define(Rgb, rgb, extend(Color, {
-  brighter: function(k) {
+  brighter(k) {
     k = k == null ? brighter : Math.pow(brighter, k);
     return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
   },
-  darker: function(k) {
+  darker(k) {
     k = k == null ? darker : Math.pow(darker, k);
     return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
   },
-  rgb: function() {
+  rgb() {
     return this;
   },
-  displayable: function() {
+  clamp() {
+    return new Rgb(clampi(this.r), clampi(this.g), clampi(this.b), clampa(this.opacity));
+  },
+  displayable() {
     return (-0.5 <= this.r && this.r < 255.5)
         && (-0.5 <= this.g && this.g < 255.5)
         && (-0.5 <= this.b && this.b < 255.5)
@@ -2266,25 +3165,34 @@
   },
   hex: rgb_formatHex, // Deprecated! Use color.formatHex.
   formatHex: rgb_formatHex,
+  formatHex8: rgb_formatHex8,
   formatRgb: rgb_formatRgb,
   toString: rgb_formatRgb
 }));
 
 function rgb_formatHex() {
-  return "#" + hex(this.r) + hex(this.g) + hex(this.b);
+  return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}`;
+}
+
+function rgb_formatHex8() {
+  return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}${hex((isNaN(this.opacity) ? 1 : this.opacity) * 255)}`;
 }
 
 function rgb_formatRgb() {
-  var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
-  return (a === 1 ? "rgb(" : "rgba(")
-      + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", "
-      + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", "
-      + Math.max(0, Math.min(255, Math.round(this.b) || 0))
-      + (a === 1 ? ")" : ", " + a + ")");
+  const a = clampa(this.opacity);
+  return `${a === 1 ? "rgb(" : "rgba("}${clampi(this.r)}, ${clampi(this.g)}, ${clampi(this.b)}${a === 1 ? ")" : `, ${a})`}`;
+}
+
+function clampa(opacity) {
+  return isNaN(opacity) ? 1 : Math.max(0, Math.min(1, opacity));
+}
+
+function clampi(value) {
+  return Math.max(0, Math.min(255, Math.round(value) || 0));
 }
 
 function hex(value) {
-  value = Math.max(0, Math.min(255, Math.round(value) || 0));
+  value = clampi(value);
   return (value < 16 ? "0" : "") + value.toString(16);
 }
 
@@ -2321,7 +3229,7 @@
   return new Hsl(h, s, l, o.opacity);
 }
 
-function hsl(h, s, l, opacity) {
+function hsl$2(h, s, l, opacity) {
   return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
 }
 
@@ -2332,16 +3240,16 @@
   this.opacity = +opacity;
 }
 
-define(Hsl, hsl, extend(Color, {
-  brighter: function(k) {
+define(Hsl, hsl$2, extend(Color, {
+  brighter(k) {
     k = k == null ? brighter : Math.pow(brighter, k);
     return new Hsl(this.h, this.s, this.l * k, this.opacity);
   },
-  darker: function(k) {
+  darker(k) {
     k = k == null ? darker : Math.pow(darker, k);
     return new Hsl(this.h, this.s, this.l * k, this.opacity);
   },
-  rgb: function() {
+  rgb() {
     var h = this.h % 360 + (this.h < 0) * 360,
         s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
         l = this.l,
@@ -2354,21 +3262,29 @@
       this.opacity
     );
   },
-  displayable: function() {
+  clamp() {
+    return new Hsl(clamph(this.h), clampt(this.s), clampt(this.l), clampa(this.opacity));
+  },
+  displayable() {
     return (0 <= this.s && this.s <= 1 || isNaN(this.s))
         && (0 <= this.l && this.l <= 1)
         && (0 <= this.opacity && this.opacity <= 1);
   },
-  formatHsl: function() {
-    var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
-    return (a === 1 ? "hsl(" : "hsla(")
-        + (this.h || 0) + ", "
-        + (this.s || 0) * 100 + "%, "
-        + (this.l || 0) * 100 + "%"
-        + (a === 1 ? ")" : ", " + a + ")");
+  formatHsl() {
+    const a = clampa(this.opacity);
+    return `${a === 1 ? "hsl(" : "hsla("}${clamph(this.h)}, ${clampt(this.s) * 100}%, ${clampt(this.l) * 100}%${a === 1 ? ")" : `, ${a})`}`;
   }
 }));
 
+function clamph(value) {
+  value = (value || 0) % 360;
+  return value < 0 ? value + 360 : value;
+}
+
+function clampt(value) {
+  return Math.max(0, Math.min(1, value || 0));
+}
+
 /* From FvD 13.37, CSS Color Module Level 3 */
 function hsl2rgb(h, m1, m2) {
   return (h < 60 ? m1 + (m2 - m1) * h / 60
@@ -2377,18 +3293,18 @@
       : m1) * 255;
 }
 
-var deg2rad = Math.PI / 180;
-var rad2deg = 180 / Math.PI;
+const radians$1 = Math.PI / 180;
+const degrees$2 = 180 / Math.PI;
 
 // https://observablehq.com/@mbostock/lab-and-rgb
-var K = 18,
+const K = 18,
     Xn = 0.96422,
     Yn = 1,
     Zn = 0.82521,
-    t0 = 4 / 29,
-    t1 = 6 / 29,
-    t2 = 3 * t1 * t1,
-    t3 = t1 * t1 * t1;
+    t0$1 = 4 / 29,
+    t1$1 = 6 / 29,
+    t2 = 3 * t1$1 * t1$1,
+    t3 = t1$1 * t1$1 * t1$1;
 
 function labConvert(o) {
   if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
@@ -2409,7 +3325,7 @@
   return new Lab(l, 0, 0, opacity == null ? 1 : opacity);
 }
 
-function lab(l, a, b, opacity) {
+function lab$1(l, a, b, opacity) {
   return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
 }
 
@@ -2420,14 +3336,14 @@
   this.opacity = +opacity;
 }
 
-define(Lab, lab, extend(Color, {
-  brighter: function(k) {
+define(Lab, lab$1, extend(Color, {
+  brighter(k) {
     return new Lab(this.l + K * (k == null ? 1 : k), this.a, this.b, this.opacity);
   },
-  darker: function(k) {
+  darker(k) {
     return new Lab(this.l - K * (k == null ? 1 : k), this.a, this.b, this.opacity);
   },
-  rgb: function() {
+  rgb() {
     var y = (this.l + 16) / 116,
         x = isNaN(this.a) ? y : y + this.a / 500,
         z = isNaN(this.b) ? y : y - this.b / 200;
@@ -2444,11 +3360,11 @@
 }));
 
 function xyz2lab(t) {
-  return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
+  return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0$1;
 }
 
 function lab2xyz(t) {
-  return t > t1 ? t * t * t : t2 * (t - t0);
+  return t > t1$1 ? t * t * t : t2 * (t - t0$1);
 }
 
 function lrgb2rgb(x) {
@@ -2463,7 +3379,7 @@
   if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
   if (!(o instanceof Lab)) o = labConvert(o);
   if (o.a === 0 && o.b === 0) return new Hcl(NaN, 0 < o.l && o.l < 100 ? 0 : NaN, o.l, o.opacity);
-  var h = Math.atan2(o.b, o.a) * rad2deg;
+  var h = Math.atan2(o.b, o.a) * degrees$2;
   return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
 }
 
@@ -2471,7 +3387,7 @@
   return arguments.length === 1 ? hclConvert(l) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
 }
 
-function hcl(h, c, l, opacity) {
+function hcl$2(h, c, l, opacity) {
   return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
 }
 
@@ -2484,30 +3400,30 @@
 
 function hcl2lab(o) {
   if (isNaN(o.h)) return new Lab(o.l, 0, 0, o.opacity);
-  var h = o.h * deg2rad;
+  var h = o.h * radians$1;
   return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
 }
 
-define(Hcl, hcl, extend(Color, {
-  brighter: function(k) {
+define(Hcl, hcl$2, extend(Color, {
+  brighter(k) {
     return new Hcl(this.h, this.c, this.l + K * (k == null ? 1 : k), this.opacity);
   },
-  darker: function(k) {
+  darker(k) {
     return new Hcl(this.h, this.c, this.l - K * (k == null ? 1 : k), this.opacity);
   },
-  rgb: function() {
+  rgb() {
     return hcl2lab(this).rgb();
   }
 }));
 
 var A = -0.14861,
-    B = +1.78277,
+    B$1 = +1.78277,
     C = -0.29227,
-    D = -0.90649,
+    D$1 = -0.90649,
     E = +1.97294,
-    ED = E * D,
-    EB = E * B,
-    BC_DA = B * C - D * A;
+    ED = E * D$1,
+    EB = E * B$1,
+    BC_DA = B$1 * C - D$1 * A;
 
 function cubehelixConvert(o) {
   if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
@@ -2517,13 +3433,13 @@
       b = o.b / 255,
       l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB),
       bl = b - l,
-      k = (E * (g - l) - C * bl) / D,
+      k = (E * (g - l) - C * bl) / D$1,
       s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1
-      h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN;
+      h = s ? Math.atan2(k, bl) * degrees$2 - 120 : NaN;
   return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
 }
 
-function cubehelix(h, s, l, opacity) {
+function cubehelix$3(h, s, l, opacity) {
   return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity);
 }
 
@@ -2534,31 +3450,31 @@
   this.opacity = +opacity;
 }
 
-define(Cubehelix, cubehelix, extend(Color, {
-  brighter: function(k) {
+define(Cubehelix, cubehelix$3, extend(Color, {
+  brighter(k) {
     k = k == null ? brighter : Math.pow(brighter, k);
     return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
   },
-  darker: function(k) {
+  darker(k) {
     k = k == null ? darker : Math.pow(darker, k);
     return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
   },
-  rgb: function() {
-    var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad,
+  rgb() {
+    var h = isNaN(this.h) ? 0 : (this.h + 120) * radians$1,
         l = +this.l,
         a = isNaN(this.s) ? 0 : this.s * l * (1 - l),
         cosh = Math.cos(h),
         sinh = Math.sin(h);
     return new Rgb(
-      255 * (l + a * (A * cosh + B * sinh)),
-      255 * (l + a * (C * cosh + D * sinh)),
+      255 * (l + a * (A * cosh + B$1 * sinh)),
+      255 * (l + a * (C * cosh + D$1 * sinh)),
       255 * (l + a * (E * cosh)),
       this.opacity
     );
   }
 }));
 
-function basis(t1, v0, v1, v2, v3) {
+function basis$1(t1, v0, v1, v2, v3) {
   var t2 = t1 * t1, t3 = t2 * t1;
   return ((1 - 3 * t1 + 3 * t2 - t3) * v0
       + (4 - 6 * t2 + 3 * t3) * v1
@@ -2566,7 +3482,7 @@
       + t3 * v3) / 6;
 }
 
-function basis$1(values) {
+function basis$2(values) {
   var n = values.length - 1;
   return function(t) {
     var i = t <= 0 ? (t = 0) : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n),
@@ -2574,11 +3490,11 @@
         v2 = values[i + 1],
         v0 = i > 0 ? values[i - 1] : 2 * v1 - v2,
         v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1;
-    return basis((t - i / n) * n, v0, v1, v2, v3);
+    return basis$1((t - i / n) * n, v0, v1, v2, v3);
   };
 }
 
-function basisClosed(values) {
+function basisClosed$1(values) {
   var n = values.length;
   return function(t) {
     var i = Math.floor(((t %= 1) < 0 ? ++t : t) * n),
@@ -2586,46 +3502,42 @@
         v1 = values[i % n],
         v2 = values[(i + 1) % n],
         v3 = values[(i + 2) % n];
-    return basis((t - i / n) * n, v0, v1, v2, v3);
+    return basis$1((t - i / n) * n, v0, v1, v2, v3);
   };
 }
 
-function constant$3(x) {
-  return function() {
-    return x;
-  };
-}
+var constant$8 = x => () => x;
 
-function linear(a, d) {
+function linear$2(a, d) {
   return function(t) {
     return a + t * d;
   };
 }
 
-function exponential(a, b, y) {
+function exponential$1(a, b, y) {
   return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
     return Math.pow(a + t * b, y);
   };
 }
 
-function hue(a, b) {
+function hue$1(a, b) {
   var d = b - a;
-  return d ? linear(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant$3(isNaN(a) ? b : a);
+  return d ? linear$2(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant$8(isNaN(a) ? b : a);
 }
 
-function gamma(y) {
+function gamma$1(y) {
   return (y = +y) === 1 ? nogamma : function(a, b) {
-    return b - a ? exponential(a, b, y) : constant$3(isNaN(a) ? b : a);
+    return b - a ? exponential$1(a, b, y) : constant$8(isNaN(a) ? b : a);
   };
 }
 
 function nogamma(a, b) {
   var d = b - a;
-  return d ? linear(a, d) : constant$3(isNaN(a) ? b : a);
+  return d ? linear$2(a, d) : constant$8(isNaN(a) ? b : a);
 }
 
 var interpolateRgb = (function rgbGamma(y) {
-  var color = gamma(y);
+  var color = gamma$1(y);
 
   function rgb$1(start, end) {
     var r = color((start = rgb(start)).r, (end = rgb(end)).r),
@@ -2672,8 +3584,8 @@
   };
 }
 
-var rgbBasis = rgbSpline(basis$1);
-var rgbBasisClosed = rgbSpline(basisClosed);
+var rgbBasis = rgbSpline(basis$2);
+var rgbBasisClosed = rgbSpline(basisClosed$1);
 
 function numberArray(a, b) {
   if (!b) b = [];
@@ -2690,7 +3602,7 @@
   return ArrayBuffer.isView(x) && !(x instanceof DataView);
 }
 
-function array$1(a, b) {
+function array$3(a, b) {
   return (isNumberArray(b) ? numberArray : genericArray)(a, b);
 }
 
@@ -2701,7 +3613,7 @@
       c = new Array(nb),
       i;
 
-  for (i = 0; i < na; ++i) x[i] = interpolateValue(a[i], b[i]);
+  for (i = 0; i < na; ++i) x[i] = interpolate$2(a[i], b[i]);
   for (; i < nb; ++i) c[i] = b[i];
 
   return function(t) {
@@ -2710,7 +3622,7 @@
   };
 }
 
-function date(a, b) {
+function date$1(a, b) {
   var d = new Date;
   return a = +a, b = +b, function(t) {
     return d.setTime(a * (1 - t) + b * t), d;
@@ -2723,7 +3635,7 @@
   };
 }
 
-function object(a, b) {
+function object$1(a, b) {
   var i = {},
       c = {},
       k;
@@ -2733,7 +3645,7 @@
 
   for (k in b) {
     if (k in a) {
-      i[k] = interpolateValue(a[k], b[k]);
+      i[k] = interpolate$2(a[k], b[k]);
     } else {
       c[k] = b[k];
     }
@@ -2808,16 +3720,16 @@
         });
 }
 
-function interpolateValue(a, b) {
+function interpolate$2(a, b) {
   var t = typeof b, c;
-  return b == null || t === "boolean" ? constant$3(b)
+  return b == null || t === "boolean" ? constant$8(b)
       : (t === "number" ? interpolateNumber
       : t === "string" ? ((c = color(b)) ? (b = c, interpolateRgb) : interpolateString)
       : b instanceof color ? interpolateRgb
-      : b instanceof Date ? date
+      : b instanceof Date ? date$1
       : isNumberArray(b) ? numberArray
       : Array.isArray(b) ? genericArray
-      : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object
+      : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object$1
       : interpolateNumber)(a, b);
 }
 
@@ -2828,8 +3740,8 @@
   };
 }
 
-function hue$1(a, b) {
-  var i = hue(+a, +b);
+function hue(a, b) {
+  var i = hue$1(+a, +b);
   return function(t) {
     var x = i(t);
     return x - 360 * Math.floor(x / 360);
@@ -2842,9 +3754,9 @@
   };
 }
 
-var degrees = 180 / Math.PI;
+var degrees$1 = 180 / Math.PI;
 
-var identity$2 = {
+var identity$7 = {
   translateX: 0,
   translateY: 0,
   rotate: 0,
@@ -2862,33 +3774,26 @@
   return {
     translateX: e,
     translateY: f,
-    rotate: Math.atan2(b, a) * degrees,
-    skewX: Math.atan(skewX) * degrees,
+    rotate: Math.atan2(b, a) * degrees$1,
+    skewX: Math.atan(skewX) * degrees$1,
     scaleX: scaleX,
     scaleY: scaleY
   };
 }
 
-var cssNode,
-    cssRoot,
-    cssView,
-    svgNode;
+var svgNode;
 
+/* eslint-disable no-undef */
 function parseCss(value) {
-  if (value === "none") return identity$2;
-  if (!cssNode) cssNode = document.createElement("DIV"), cssRoot = document.documentElement, cssView = document.defaultView;
-  cssNode.style.transform = value;
-  value = cssView.getComputedStyle(cssRoot.appendChild(cssNode), null).getPropertyValue("transform");
-  cssRoot.removeChild(cssNode);
-  value = value.slice(7, -1).split(",");
-  return decompose(+value[0], +value[1], +value[2], +value[3], +value[4], +value[5]);
+  const m = new (typeof DOMMatrix === "function" ? DOMMatrix : WebKitCSSMatrix)(value + "");
+  return m.isIdentity ? identity$7 : decompose(m.a, m.b, m.c, m.d, m.e, m.f);
 }
 
 function parseSvg(value) {
-  if (value == null) return identity$2;
+  if (value == null) return identity$7;
   if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
   svgNode.setAttribute("transform", value);
-  if (!(value = svgNode.transform.baseVal.consolidate())) return identity$2;
+  if (!(value = svgNode.transform.baseVal.consolidate())) return identity$7;
   value = value.matrix;
   return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
 }
@@ -2954,10 +3859,7 @@
 var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
 var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
 
-var rho = Math.SQRT2,
-    rho2 = 2,
-    rho4 = 4,
-    epsilon2 = 1e-12;
+var epsilon2$1 = 1e-12;
 
 function cosh(x) {
   return ((x = Math.exp(x)) + 1 / x) / 2;
@@ -2971,57 +3873,67 @@
   return ((x = Math.exp(2 * x)) - 1) / (x + 1);
 }
 
-// p0 = [ux0, uy0, w0]
-// p1 = [ux1, uy1, w1]
-function interpolateZoom(p0, p1) {
-  var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],
-      ux1 = p1[0], uy1 = p1[1], w1 = p1[2],
-      dx = ux1 - ux0,
-      dy = uy1 - uy0,
-      d2 = dx * dx + dy * dy,
-      i,
-      S;
+var interpolateZoom = (function zoomRho(rho, rho2, rho4) {
 
-  // Special case for u0 ≅ u1.
-  if (d2 < epsilon2) {
-    S = Math.log(w1 / w0) / rho;
-    i = function(t) {
-      return [
-        ux0 + t * dx,
-        uy0 + t * dy,
-        w0 * Math.exp(rho * t * S)
-      ];
-    };
+  // p0 = [ux0, uy0, w0]
+  // p1 = [ux1, uy1, w1]
+  function zoom(p0, p1) {
+    var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],
+        ux1 = p1[0], uy1 = p1[1], w1 = p1[2],
+        dx = ux1 - ux0,
+        dy = uy1 - uy0,
+        d2 = dx * dx + dy * dy,
+        i,
+        S;
+
+    // Special case for u0 ≅ u1.
+    if (d2 < epsilon2$1) {
+      S = Math.log(w1 / w0) / rho;
+      i = function(t) {
+        return [
+          ux0 + t * dx,
+          uy0 + t * dy,
+          w0 * Math.exp(rho * t * S)
+        ];
+      };
+    }
+
+    // General case.
+    else {
+      var d1 = Math.sqrt(d2),
+          b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
+          b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
+          r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
+          r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
+      S = (r1 - r0) / rho;
+      i = function(t) {
+        var s = t * S,
+            coshr0 = cosh(r0),
+            u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
+        return [
+          ux0 + u * dx,
+          uy0 + u * dy,
+          w0 * coshr0 / cosh(rho * s + r0)
+        ];
+      };
+    }
+
+    i.duration = S * 1000 * rho / Math.SQRT2;
+
+    return i;
   }
 
-  // General case.
-  else {
-    var d1 = Math.sqrt(d2),
-        b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
-        b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
-        r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
-        r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
-    S = (r1 - r0) / rho;
-    i = function(t) {
-      var s = t * S,
-          coshr0 = cosh(r0),
-          u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
-      return [
-        ux0 + u * dx,
-        uy0 + u * dy,
-        w0 * coshr0 / cosh(rho * s + r0)
-      ];
-    };
-  }
+  zoom.rho = function(_) {
+    var _1 = Math.max(1e-3, +_), _2 = _1 * _1, _4 = _2 * _2;
+    return zoomRho(_1, _2, _4);
+  };
 
-  i.duration = S * 1000;
+  return zoom;
+})(Math.SQRT2, 2, 4);
 
-  return i;
-}
-
-function hsl$1(hue) {
+function hsl(hue) {
   return function(start, end) {
-    var h = hue((start = hsl(start)).h, (end = hsl(end)).h),
+    var h = hue((start = hsl$2(start)).h, (end = hsl$2(end)).h),
         s = nogamma(start.s, end.s),
         l = nogamma(start.l, end.l),
         opacity = nogamma(start.opacity, end.opacity);
@@ -3035,11 +3947,11 @@
   }
 }
 
-var hsl$2 = hsl$1(hue);
-var hslLong = hsl$1(nogamma);
+var hsl$1 = hsl(hue$1);
+var hslLong = hsl(nogamma);
 
-function lab$1(start, end) {
-  var l = nogamma((start = lab(start)).l, (end = lab(end)).l),
+function lab(start, end) {
+  var l = nogamma((start = lab$1(start)).l, (end = lab$1(end)).l),
       a = nogamma(start.a, end.a),
       b = nogamma(start.b, end.b),
       opacity = nogamma(start.opacity, end.opacity);
@@ -3052,9 +3964,9 @@
   };
 }
 
-function hcl$1(hue) {
+function hcl(hue) {
   return function(start, end) {
-    var h = hue((start = hcl(start)).h, (end = hcl(end)).h),
+    var h = hue((start = hcl$2(start)).h, (end = hcl$2(end)).h),
         c = nogamma(start.c, end.c),
         l = nogamma(start.l, end.l),
         opacity = nogamma(start.opacity, end.opacity);
@@ -3068,15 +3980,15 @@
   }
 }
 
-var hcl$2 = hcl$1(hue);
-var hclLong = hcl$1(nogamma);
+var hcl$1 = hcl(hue$1);
+var hclLong = hcl(nogamma);
 
 function cubehelix$1(hue) {
   return (function cubehelixGamma(y) {
     y = +y;
 
-    function cubehelix$1(start, end) {
-      var h = hue((start = cubehelix(start)).h, (end = cubehelix(end)).h),
+    function cubehelix(start, end) {
+      var h = hue((start = cubehelix$3(start)).h, (end = cubehelix$3(end)).h),
           s = nogamma(start.s, end.s),
           l = nogamma(start.l, end.l),
           opacity = nogamma(start.opacity, end.opacity);
@@ -3089,16 +4001,17 @@
       };
     }
 
-    cubehelix$1.gamma = cubehelixGamma;
+    cubehelix.gamma = cubehelixGamma;
 
-    return cubehelix$1;
+    return cubehelix;
   })(1);
 }
 
-var cubehelix$2 = cubehelix$1(hue);
+var cubehelix$2 = cubehelix$1(hue$1);
 var cubehelixLong = cubehelix$1(nogamma);
 
 function piecewise(interpolate, values) {
+  if (values === undefined) values = interpolate, interpolate = interpolate$2;
   var i = 0, n = values.length - 1, v = values[0], I = new Array(n < 0 ? 0 : n);
   while (i < n) I[i] = interpolate(v, v = values[++i]);
   return function(t) {
@@ -3107,15 +4020,15 @@
   };
 }
 
-function quantize(interpolator, n) {
+function quantize$1(interpolator, n) {
   var samples = new Array(n);
   for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1));
   return samples;
 }
 
 var frame = 0, // is an animation frame pending?
-    timeout = 0, // is a timeout pending?
-    interval = 0, // are any timers active?
+    timeout$1 = 0, // is a timeout pending?
+    interval$1 = 0, // are any timers active?
     pokeDelay = 1000, // how frequently we check for clock skew
     taskHead,
     taskTail,
@@ -3173,7 +4086,7 @@
   ++frame; // Pretend we’ve set an alarm, if we haven’t already.
   var t = taskHead, e;
   while (t) {
-    if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
+    if ((e = clockNow - t._time) >= 0) t._call.call(undefined, e);
     t = t._next;
   }
   --frame;
@@ -3181,7 +4094,7 @@
 
 function wake() {
   clockNow = (clockLast = clock.now()) + clockSkew;
-  frame = timeout = 0;
+  frame = timeout$1 = 0;
   try {
     timerFlush();
   } finally {
@@ -3213,36 +4126,40 @@
 
 function sleep(time) {
   if (frame) return; // Soonest alarm already set, or will be.
-  if (timeout) timeout = clearTimeout(timeout);
+  if (timeout$1) timeout$1 = clearTimeout(timeout$1);
   var delay = time - clockNow; // Strictly less than if we recomputed clockNow.
   if (delay > 24) {
-    if (time < Infinity) timeout = setTimeout(wake, time - clock.now() - clockSkew);
-    if (interval) interval = clearInterval(interval);
+    if (time < Infinity) timeout$1 = setTimeout(wake, time - clock.now() - clockSkew);
+    if (interval$1) interval$1 = clearInterval(interval$1);
   } else {
-    if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay);
+    if (!interval$1) clockLast = clock.now(), interval$1 = setInterval(poke, pokeDelay);
     frame = 1, setFrame(wake);
   }
 }
 
-function timeout$1(callback, delay, time) {
+function timeout(callback, delay, time) {
   var t = new Timer;
   delay = delay == null ? 0 : +delay;
-  t.restart(function(elapsed) {
+  t.restart(elapsed => {
     t.stop();
     callback(elapsed + delay);
   }, delay, time);
   return t;
 }
 
-function interval$1(callback, delay, time) {
+function interval(callback, delay, time) {
   var t = new Timer, total = delay;
   if (delay == null) return t.restart(callback, delay, time), t;
-  delay = +delay, time = time == null ? now() : +time;
-  t.restart(function tick(elapsed) {
-    elapsed += total;
-    t.restart(tick, total += delay, time);
-    callback(elapsed);
-  }, delay, time);
+  t._restart = t.restart;
+  t.restart = function(callback, delay, time) {
+    delay = +delay, time = time == null ? now() : +time;
+    t._restart(function tick(elapsed) {
+      elapsed += total;
+      t._restart(tick, total += delay, time);
+      callback(elapsed);
+    }, delay, time);
+  };
+  t.restart(callback, delay, time);
   return t;
 }
 
@@ -3261,7 +4178,7 @@
   var schedules = node.__transition;
   if (!schedules) node.__transition = {};
   else if (id in schedules) return;
-  create$1(node, id, {
+  create(node, id, {
     name: name,
     index: index, // For context during callback.
     group: group, // For context during callback.
@@ -3277,24 +4194,24 @@
 }
 
 function init(node, id) {
-  var schedule = get$1(node, id);
+  var schedule = get(node, id);
   if (schedule.state > CREATED) throw new Error("too late; already scheduled");
   return schedule;
 }
 
-function set$1(node, id) {
-  var schedule = get$1(node, id);
+function set(node, id) {
+  var schedule = get(node, id);
   if (schedule.state > STARTED) throw new Error("too late; already running");
   return schedule;
 }
 
-function get$1(node, id) {
+function get(node, id) {
   var schedule = node.__transition;
   if (!schedule || !(schedule = schedule[id])) throw new Error("transition not found");
   return schedule;
 }
 
-function create$1(node, id, self) {
+function create(node, id, self) {
   var schedules = node.__transition,
       tween;
 
@@ -3324,7 +4241,7 @@
       // While this element already has a starting transition during this frame,
       // defer starting an interrupting transition until that transition has a
       // chance to tick (and possibly end); see d3/d3-transition#54!
-      if (o.state === STARTED) return timeout$1(start);
+      if (o.state === STARTED) return timeout(start);
 
       // Interrupt the active transition, if any.
       if (o.state === RUNNING) {
@@ -3347,7 +4264,7 @@
     // Note the transition may be canceled after start and before the first tick!
     // Note this must be scheduled before the start event; see d3/d3-transition#16!
     // Assuming this is successful, subsequent callbacks go straight to tick.
-    timeout$1(function() {
+    timeout(function() {
       if (self.state === STARTED) {
         self.state = RUNNING;
         self.timer.restart(tick, self.delay, self.time);
@@ -3429,7 +4346,7 @@
 function tweenRemove(id, name) {
   var tween0, tween1;
   return function() {
-    var schedule = set$1(this, id),
+    var schedule = set(this, id),
         tween = schedule.tween;
 
     // If this node shared tween with the previous node,
@@ -3454,7 +4371,7 @@
   var tween0, tween1;
   if (typeof value !== "function") throw new Error;
   return function() {
-    var schedule = set$1(this, id),
+    var schedule = set(this, id),
         tween = schedule.tween;
 
     // If this node shared tween with the previous node,
@@ -3481,7 +4398,7 @@
   name += "";
 
   if (arguments.length < 2) {
-    var tween = get$1(this.node(), id).tween;
+    var tween = get(this.node(), id).tween;
     for (var i = 0, n = tween.length, t; i < n; ++i) {
       if ((t = tween[i]).name === name) {
         return t.value;
@@ -3497,16 +4414,16 @@
   var id = transition._id;
 
   transition.each(function() {
-    var schedule = set$1(this, id);
+    var schedule = set(this, id);
     (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);
   });
 
   return function(node) {
-    return get$1(node, id).value[name];
+    return get(node, id).value[name];
   };
 }
 
-function interpolate(a, b) {
+function interpolate$1(a, b) {
   var c;
   return (typeof b === "number" ? interpolateNumber
       : b instanceof color ? interpolateRgb
@@ -3514,19 +4431,19 @@
       : interpolateString)(a, b);
 }
 
-function attrRemove$1(name) {
+function attrRemove(name) {
   return function() {
     this.removeAttribute(name);
   };
 }
 
-function attrRemoveNS$1(fullname) {
+function attrRemoveNS(fullname) {
   return function() {
     this.removeAttributeNS(fullname.space, fullname.local);
   };
 }
 
-function attrConstant$1(name, interpolate, value1) {
+function attrConstant(name, interpolate, value1) {
   var string00,
       string1 = value1 + "",
       interpolate0;
@@ -3538,7 +4455,7 @@
   };
 }
 
-function attrConstantNS$1(fullname, interpolate, value1) {
+function attrConstantNS(fullname, interpolate, value1) {
   var string00,
       string1 = value1 + "",
       interpolate0;
@@ -3550,7 +4467,7 @@
   };
 }
 
-function attrFunction$1(name, interpolate, value) {
+function attrFunction(name, interpolate, value) {
   var string00,
       string10,
       interpolate0;
@@ -3565,7 +4482,7 @@
   };
 }
 
-function attrFunctionNS$1(fullname, interpolate, value) {
+function attrFunctionNS(fullname, interpolate, value) {
   var string00,
       string10,
       interpolate0;
@@ -3581,11 +4498,11 @@
 }
 
 function transition_attr(name, value) {
-  var fullname = namespace(name), i = fullname === "transform" ? interpolateTransformSvg : interpolate;
+  var fullname = namespace(name), i = fullname === "transform" ? interpolateTransformSvg : interpolate$1;
   return this.attrTween(name, typeof value === "function"
-      ? (fullname.local ? attrFunctionNS$1 : attrFunction$1)(fullname, i, tweenValue(this, "attr." + name, value))
-      : value == null ? (fullname.local ? attrRemoveNS$1 : attrRemove$1)(fullname)
-      : (fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, i, value));
+      ? (fullname.local ? attrFunctionNS : attrFunction)(fullname, i, tweenValue(this, "attr." + name, value))
+      : value == null ? (fullname.local ? attrRemoveNS : attrRemove)(fullname)
+      : (fullname.local ? attrConstantNS : attrConstant)(fullname, i, value));
 }
 
 function attrInterpolate(name, i) {
@@ -3650,18 +4567,18 @@
       ? this.each((typeof value === "function"
           ? delayFunction
           : delayConstant)(id, value))
-      : get$1(this.node(), id).delay;
+      : get(this.node(), id).delay;
 }
 
 function durationFunction(id, value) {
   return function() {
-    set$1(this, id).duration = +value.apply(this, arguments);
+    set(this, id).duration = +value.apply(this, arguments);
   };
 }
 
 function durationConstant(id, value) {
   return value = +value, function() {
-    set$1(this, id).duration = value;
+    set(this, id).duration = value;
   };
 }
 
@@ -3672,13 +4589,13 @@
       ? this.each((typeof value === "function"
           ? durationFunction
           : durationConstant)(id, value))
-      : get$1(this.node(), id).duration;
+      : get(this.node(), id).duration;
 }
 
 function easeConstant(id, value) {
   if (typeof value !== "function") throw new Error;
   return function() {
-    set$1(this, id).ease = value;
+    set(this, id).ease = value;
   };
 }
 
@@ -3687,7 +4604,20 @@
 
   return arguments.length
       ? this.each(easeConstant(id, value))
-      : get$1(this.node(), id).ease;
+      : get(this.node(), id).ease;
+}
+
+function easeVarying(id, value) {
+  return function() {
+    var v = value.apply(this, arguments);
+    if (typeof v !== "function") throw new Error;
+    set(this, id).ease = v;
+  };
+}
+
+function transition_easeVarying(value) {
+  if (typeof value !== "function") throw new Error;
+  return this.each(easeVarying(this._id, value));
 }
 
 function transition_filter(match) {
@@ -3731,7 +4661,7 @@
 }
 
 function onFunction(id, name, listener) {
-  var on0, on1, sit = start(name) ? init : set$1;
+  var on0, on1, sit = start(name) ? init : set;
   return function() {
     var schedule = sit(this, id),
         on = schedule.on;
@@ -3749,7 +4679,7 @@
   var id = this._id;
 
   return arguments.length < 2
-      ? get$1(this.node(), id).on.on(name)
+      ? get(this.node(), id).on.on(name)
       : this.each(onFunction(id, name, listener));
 }
 
@@ -3776,7 +4706,7 @@
       if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
         if ("__data__" in node) subnode.__data__ = node.__data__;
         subgroup[i] = subnode;
-        schedule(subgroup[i], name, id, i, subgroup, get$1(node, id));
+        schedule(subgroup[i], name, id, i, subgroup, get(node, id));
       }
     }
   }
@@ -3793,7 +4723,7 @@
   for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
       if (node = group[i]) {
-        for (var children = select.call(node, node.__data__, i, group), child, inherit = get$1(node, id), k = 0, l = children.length; k < l; ++k) {
+        for (var children = select.call(node, node.__data__, i, group), child, inherit = get(node, id), k = 0, l = children.length; k < l; ++k) {
           if (child = children[k]) {
             schedule(child, name, id, k, children, inherit);
           }
@@ -3807,10 +4737,10 @@
   return new Transition(subgroups, parents, name, id);
 }
 
-var Selection$1 = selection.prototype.constructor;
+var Selection = selection.prototype.constructor;
 
 function transition_selection() {
-  return new Selection$1(this._groups, this._parents);
+  return new Selection(this._groups, this._parents);
 }
 
 function styleNull(name, interpolate) {
@@ -3826,13 +4756,13 @@
   };
 }
 
-function styleRemove$1(name) {
+function styleRemove(name) {
   return function() {
     this.style.removeProperty(name);
   };
 }
 
-function styleConstant$1(name, interpolate, value1) {
+function styleConstant(name, interpolate, value1) {
   var string00,
       string1 = value1 + "",
       interpolate0;
@@ -3844,7 +4774,7 @@
   };
 }
 
-function styleFunction$1(name, interpolate, value) {
+function styleFunction(name, interpolate, value) {
   var string00,
       string10,
       interpolate0;
@@ -3862,9 +4792,9 @@
 function styleMaybeRemove(id, name) {
   var on0, on1, listener0, key = "style." + name, event = "end." + key, remove;
   return function() {
-    var schedule = set$1(this, id),
+    var schedule = set(this, id),
         on = schedule.on,
-        listener = schedule.value[key] == null ? remove || (remove = styleRemove$1(name)) : undefined;
+        listener = schedule.value[key] == null ? remove || (remove = styleRemove(name)) : undefined;
 
     // If this node shared a dispatch with the previous node,
     // just assign the updated shared dispatch and we’re done!
@@ -3876,15 +4806,15 @@
 }
 
 function transition_style(name, value, priority) {
-  var i = (name += "") === "transform" ? interpolateTransformCss : interpolate;
+  var i = (name += "") === "transform" ? interpolateTransformCss : interpolate$1;
   return value == null ? this
       .styleTween(name, styleNull(name, i))
-      .on("end.style." + name, styleRemove$1(name))
+      .on("end.style." + name, styleRemove(name))
     : typeof value === "function" ? this
-      .styleTween(name, styleFunction$1(name, i, tweenValue(this, "style." + name, value)))
+      .styleTween(name, styleFunction(name, i, tweenValue(this, "style." + name, value)))
       .each(styleMaybeRemove(this._id, name))
     : this
-      .styleTween(name, styleConstant$1(name, i, value), priority)
+      .styleTween(name, styleConstant(name, i, value), priority)
       .on("end.style." + name, null);
 }
 
@@ -3913,13 +4843,13 @@
   return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
 }
 
-function textConstant$1(value) {
+function textConstant(value) {
   return function() {
     this.textContent = value;
   };
 }
 
-function textFunction$1(value) {
+function textFunction(value) {
   return function() {
     var value1 = value(this);
     this.textContent = value1 == null ? "" : value1;
@@ -3928,8 +4858,8 @@
 
 function transition_text(value) {
   return this.tween("text", typeof value === "function"
-      ? textFunction$1(tweenValue(this, "text", value))
-      : textConstant$1(value == null ? "" : value + ""));
+      ? textFunction(tweenValue(this, "text", value))
+      : textConstant(value == null ? "" : value + ""));
 }
 
 function textInterpolate(i) {
@@ -3965,7 +4895,7 @@
   for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
       if (node = group[i]) {
-        var inherit = get$1(node, id0);
+        var inherit = get(node, id0);
         schedule(node, name, id1, i, group, {
           time: inherit.time + inherit.delay + inherit.duration,
           delay: 0,
@@ -3986,7 +4916,7 @@
         end = {value: function() { if (--size === 0) resolve(); }};
 
     that.each(function() {
-      var schedule = set$1(this, id),
+      var schedule = set(this, id),
           on = schedule.on;
 
       // If this node shared a dispatch with the previous node,
@@ -4001,6 +4931,9 @@
 
       schedule.on = on1;
     });
+
+    // The selection was empty, resolve end immediately
+    if (size === 0) resolve();
   });
 }
 
@@ -4027,6 +4960,8 @@
   constructor: Transition,
   select: transition_select,
   selectAll: transition_selectAll,
+  selectChild: selection_prototype.selectChild,
+  selectChildren: selection_prototype.selectChildren,
   filter: transition_filter,
   merge: transition_merge,
   selection: transition_selection,
@@ -4049,12 +4984,12 @@
   delay: transition_delay,
   duration: transition_duration,
   ease: transition_ease,
-  end: transition_end
+  easeVarying: transition_easeVarying,
+  end: transition_end,
+  [Symbol.iterator]: selection_prototype[Symbol.iterator]
 };
 
-function linear$1(t) {
-  return +t;
-}
+const linear$1 = t => +t;
 
 function quadIn(t) {
   return t * t;
@@ -4080,7 +5015,7 @@
   return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
 }
 
-var exponent = 3;
+var exponent$1 = 3;
 
 var polyIn = (function custom(e) {
   e = +e;
@@ -4092,7 +5027,7 @@
   polyIn.exponent = custom;
 
   return polyIn;
-})(exponent);
+})(exponent$1);
 
 var polyOut = (function custom(e) {
   e = +e;
@@ -4104,7 +5039,7 @@
   polyOut.exponent = custom;
 
   return polyOut;
-})(exponent);
+})(exponent$1);
 
 var polyInOut = (function custom(e) {
   e = +e;
@@ -4116,33 +5051,38 @@
   polyInOut.exponent = custom;
 
   return polyInOut;
-})(exponent);
+})(exponent$1);
 
-var pi = Math.PI,
-    halfPi = pi / 2;
+var pi$4 = Math.PI,
+    halfPi$3 = pi$4 / 2;
 
 function sinIn(t) {
-  return 1 - Math.cos(t * halfPi);
+  return (+t === 1) ? 1 : 1 - Math.cos(t * halfPi$3);
 }
 
 function sinOut(t) {
-  return Math.sin(t * halfPi);
+  return Math.sin(t * halfPi$3);
 }
 
 function sinInOut(t) {
-  return (1 - Math.cos(pi * t)) / 2;
+  return (1 - Math.cos(pi$4 * t)) / 2;
+}
+
+// tpmt is two power minus ten times t scaled to [0,1]
+function tpmt(x) {
+  return (Math.pow(2, -10 * x) - 0.0009765625) * 1.0009775171065494;
 }
 
 function expIn(t) {
-  return Math.pow(2, 10 * t - 10);
+  return tpmt(1 - +t);
 }
 
 function expOut(t) {
-  return 1 - Math.pow(2, -10 * t);
+  return 1 - tpmt(t);
 }
 
 function expInOut(t) {
-  return ((t *= 2) <= 1 ? Math.pow(2, 10 * t - 10) : 2 - Math.pow(2, 10 - 10 * t)) / 2;
+  return ((t *= 2) <= 1 ? tpmt(1 - t) : 2 - tpmt(t - 1)) / 2;
 }
 
 function circleIn(t) {
@@ -4186,7 +5126,7 @@
   s = +s;
 
   function backIn(t) {
-    return t * t * ((s + 1) * t - s);
+    return (t = +t) * t * (s * (t - 1) + t);
   }
 
   backIn.overshoot = custom;
@@ -4198,7 +5138,7 @@
   s = +s;
 
   function backOut(t) {
-    return --t * t * ((s + 1) * t + s) + 1;
+    return --t * t * ((t + 1) * s + t) + 1;
   }
 
   backOut.overshoot = custom;
@@ -4218,46 +5158,46 @@
   return backInOut;
 })(overshoot);
 
-var tau = 2 * Math.PI,
+var tau$5 = 2 * Math.PI,
     amplitude = 1,
     period = 0.3;
 
 var elasticIn = (function custom(a, p) {
-  var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
+  var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau$5);
 
   function elasticIn(t) {
-    return a * Math.pow(2, 10 * --t) * Math.sin((s - t) / p);
+    return a * tpmt(-(--t)) * Math.sin((s - t) / p);
   }
 
-  elasticIn.amplitude = function(a) { return custom(a, p * tau); };
+  elasticIn.amplitude = function(a) { return custom(a, p * tau$5); };
   elasticIn.period = function(p) { return custom(a, p); };
 
   return elasticIn;
 })(amplitude, period);
 
 var elasticOut = (function custom(a, p) {
-  var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
+  var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau$5);
 
   function elasticOut(t) {
-    return 1 - a * Math.pow(2, -10 * (t = +t)) * Math.sin((t + s) / p);
+    return 1 - a * tpmt(t = +t) * Math.sin((t + s) / p);
   }
 
-  elasticOut.amplitude = function(a) { return custom(a, p * tau); };
+  elasticOut.amplitude = function(a) { return custom(a, p * tau$5); };
   elasticOut.period = function(p) { return custom(a, p); };
 
   return elasticOut;
 })(amplitude, period);
 
 var elasticInOut = (function custom(a, p) {
-  var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
+  var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau$5);
 
   function elasticInOut(t) {
     return ((t = t * 2 - 1) < 0
-        ? a * Math.pow(2, 10 * t) * Math.sin((s - t) / p)
-        : 2 - a * Math.pow(2, -10 * t) * Math.sin((s + t) / p)) / 2;
+        ? a * tpmt(-t) * Math.sin((s - t) / p)
+        : 2 - a * tpmt(t) * Math.sin((s + t) / p)) / 2;
   }
 
-  elasticInOut.amplitude = function(a) { return custom(a, p * tau); };
+  elasticInOut.amplitude = function(a) { return custom(a, p * tau$5); };
   elasticInOut.period = function(p) { return custom(a, p); };
 
   return elasticInOut;
@@ -4274,7 +5214,7 @@
   var timing;
   while (!(timing = node.__transition) || !(timing = timing[id])) {
     if (!(node = node.parentNode)) {
-      return defaultTiming.time = now(), defaultTiming;
+      throw new Error(`transition ${id} not found`);
     }
   }
   return timing;
@@ -4304,7 +5244,7 @@
 selection.prototype.interrupt = selection_interrupt;
 selection.prototype.transition = selection_transition;
 
-var root$1 = [null];
+var root = [null];
 
 function active(node, name) {
   var schedules = node.__transition,
@@ -4315,7 +5255,7 @@
     name = name == null ? null : name + "";
     for (i in schedules) {
       if ((schedule = schedules[i]).state > SCHEDULED && schedule.name === name) {
-        return new Transition([[node]], root$1, name, +i);
+        return new Transition([[node]], root, name, +i);
       }
     }
   }
@@ -4323,25 +5263,32 @@
   return null;
 }
 
-function constant$4(x) {
-  return function() {
-    return x;
-  };
+var constant$7 = x => () => x;
+
+function BrushEvent(type, {
+  sourceEvent,
+  target,
+  selection,
+  mode,
+  dispatch
+}) {
+  Object.defineProperties(this, {
+    type: {value: type, enumerable: true, configurable: true},
+    sourceEvent: {value: sourceEvent, enumerable: true, configurable: true},
+    target: {value: target, enumerable: true, configurable: true},
+    selection: {value: selection, enumerable: true, configurable: true},
+    mode: {value: mode, enumerable: true, configurable: true},
+    _: {value: dispatch}
+  });
 }
 
-function BrushEvent(target, type, selection) {
-  this.target = target;
-  this.type = type;
-  this.selection = selection;
+function nopropagation$1(event) {
+  event.stopImmediatePropagation();
 }
 
-function nopropagation$1() {
-  exports.event.stopImmediatePropagation();
-}
-
-function noevent$1() {
-  exports.event.preventDefault();
-  exports.event.stopImmediatePropagation();
+function noevent$1(event) {
+  event.preventDefault();
+  event.stopImmediatePropagation();
 }
 
 var MODE_DRAG = {name: "drag"},
@@ -4349,6 +5296,8 @@
     MODE_HANDLE = {name: "handle"},
     MODE_CENTER = {name: "center"};
 
+const {abs: abs$3, max: max$2, min: min$1} = Math;
+
 function number1(e) {
   return [+e[0], +e[1]];
 }
@@ -4357,12 +5306,6 @@
   return [number1(e[0]), number1(e[1])];
 }
 
-function toucher(identifier) {
-  return function(target) {
-    return touch(target, exports.event.touches, identifier);
-  };
-}
-
 var X = {
   name: "x",
   handles: ["w", "e"].map(type),
@@ -4446,11 +5389,11 @@
 }
 
 // Ignore right-click, since that should open the context menu.
-function defaultFilter$1() {
-  return !exports.event.ctrlKey && !exports.event.button;
+function defaultFilter$1(event) {
+  return !event.ctrlKey && !event.button;
 }
 
-function defaultExtent() {
+function defaultExtent$1() {
   var svg = this.ownerSVGElement || this;
   if (svg.hasAttribute("viewBox")) {
     svg = svg.viewBox.baseVal;
@@ -4464,12 +5407,12 @@
 }
 
 // Like d3.local, but with the name “__brush” rather than auto-generated.
-function local$1(node) {
+function local(node) {
   while (!node.__brush) if (!(node = node.parentNode)) return;
   return node.__brush;
 }
 
-function empty$1(extent) {
+function empty(extent) {
   return extent[0][0] === extent[1][0]
       || extent[0][1] === extent[1][1];
 }
@@ -4492,7 +5435,7 @@
 }
 
 function brush$1(dim) {
-  var extent = defaultExtent,
+  var extent = defaultExtent$1,
       filter = defaultFilter$1,
       touchable = defaultTouchable$1,
       keys = true,
@@ -4512,7 +5455,7 @@
         .attr("cursor", cursors.overlay)
       .merge(overlay)
         .each(function() {
-          var extent = local$1(this).extent;
+          var extent = local(this).extent;
           select(this)
               .attr("x", extent[0][0])
               .attr("y", extent[0][1])
@@ -4552,18 +5495,18 @@
         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
   }
 
-  brush.move = function(group, selection) {
-    if (group.selection) {
+  brush.move = function(group, selection, event) {
+    if (group.tween) {
       group
-          .on("start.brush", function() { emitter(this, arguments).beforestart().start(); })
-          .on("interrupt.brush end.brush", function() { emitter(this, arguments).end(); })
+          .on("start.brush", function(event) { emitter(this, arguments).beforestart().start(event); })
+          .on("interrupt.brush end.brush", function(event) { emitter(this, arguments).end(event); })
           .tween("brush", function() {
             var that = this,
                 state = that.__brush,
                 emit = emitter(that, arguments),
                 selection0 = state.selection,
                 selection1 = dim.input(typeof selection === "function" ? selection.apply(this, arguments) : selection, state.extent),
-                i = interpolateValue(selection0, selection1);
+                i = interpolate$2(selection0, selection1);
 
             function tween(t) {
               state.selection = t === 1 && selection1 === null ? null : i(t);
@@ -4585,18 +5528,18 @@
             interrupt(that);
             state.selection = selection1 === null ? null : selection1;
             redraw.call(that);
-            emit.start().brush().end();
+            emit.start(event).brush(event).end(event);
           });
     }
   };
 
-  brush.clear = function(group) {
-    brush.move(group, null);
+  brush.clear = function(group, event) {
+    brush.move(group, null, event);
   };
 
   function redraw() {
     var group = select(this),
-        selection = local$1(this).selection;
+        selection = local(this).selection;
 
     if (selection) {
       group.selectAll(".selection")
@@ -4625,14 +5568,16 @@
   }
 
   function emitter(that, args, clean) {
-    return (!clean && that.__brush.emitter) || new Emitter(that, args);
+    var emit = that.__brush.emitter;
+    return emit && (!clean || !emit.clean) ? emit : new Emitter(that, args, clean);
   }
 
-  function Emitter(that, args) {
+  function Emitter(that, args, clean) {
     this.that = that;
     this.args = args;
     this.state = that.__brush;
     this.active = 0;
+    this.clean = clean;
   }
 
   Emitter.prototype = {
@@ -4640,34 +5585,46 @@
       if (++this.active === 1) this.state.emitter = this, this.starting = true;
       return this;
     },
-    start: function() {
-      if (this.starting) this.starting = false, this.emit("start");
-      else this.emit("brush");
+    start: function(event, mode) {
+      if (this.starting) this.starting = false, this.emit("start", event, mode);
+      else this.emit("brush", event);
       return this;
     },
-    brush: function() {
-      this.emit("brush");
+    brush: function(event, mode) {
+      this.emit("brush", event, mode);
       return this;
     },
-    end: function() {
-      if (--this.active === 0) delete this.state.emitter, this.emit("end");
+    end: function(event, mode) {
+      if (--this.active === 0) delete this.state.emitter, this.emit("end", event, mode);
       return this;
     },
-    emit: function(type) {
-      customEvent(new BrushEvent(brush, type, dim.output(this.state.selection)), listeners.apply, listeners, [type, this.that, this.args]);
+    emit: function(type, event, mode) {
+      var d = select(this.that).datum();
+      listeners.call(
+        type,
+        this.that,
+        new BrushEvent(type, {
+          sourceEvent: event,
+          target: brush,
+          selection: dim.output(this.state.selection),
+          mode,
+          dispatch: listeners
+        }),
+        d
+      );
     }
   };
 
-  function started() {
-    if (touchending && !exports.event.touches) return;
+  function started(event) {
+    if (touchending && !event.touches) return;
     if (!filter.apply(this, arguments)) return;
 
     var that = this,
-        type = exports.event.target.__data__.type,
-        mode = (keys && exports.event.metaKey ? type = "overlay" : type) === "selection" ? MODE_DRAG : (keys && exports.event.altKey ? MODE_CENTER : MODE_HANDLE),
+        type = event.target.__data__.type,
+        mode = (keys && event.metaKey ? type = "overlay" : type) === "selection" ? MODE_DRAG : (keys && event.altKey ? MODE_CENTER : MODE_HANDLE),
         signX = dim === Y ? null : signsX[type],
         signY = dim === X ? null : signsY[type],
-        state = local$1(that),
+        state = local(that),
         extent = state.extent,
         selection = state.selection,
         W = extent[0][0], w0, w1,
@@ -4677,20 +5634,31 @@
         dx = 0,
         dy = 0,
         moving,
-        shifting = signX && signY && keys && exports.event.shiftKey,
+        shifting = signX && signY && keys && event.shiftKey,
         lockX,
         lockY,
-        pointer = exports.event.touches ? toucher(exports.event.changedTouches[0].identifier) : mouse,
-        point0 = pointer(that),
-        point = point0,
-        emit = emitter(that, arguments, true).beforestart();
+        points = Array.from(event.touches || [event], t => {
+          const i = t.identifier;
+          t = pointer(t, that);
+          t.point0 = t.slice();
+          t.identifier = i;
+          return t;
+        });
+
+    interrupt(that);
+    var emit = emitter(that, arguments, true).beforestart();
 
     if (type === "overlay") {
       if (selection) moving = true;
-      state.selection = selection = [
-        [w0 = dim === Y ? W : point0[0], n0 = dim === X ? N : point0[1]],
-        [e0 = dim === Y ? E : w0, s0 = dim === X ? S : n0]
-      ];
+      const pts = [points[0], points[1] || points[0]];
+      state.selection = selection = [[
+          w0 = dim === Y ? W : min$1(pts[0][0], pts[1][0]),
+          n0 = dim === X ? N : min$1(pts[0][1], pts[1][1])
+        ], [
+          e0 = dim === Y ? E : max$2(pts[0][0], pts[1][0]),
+          s0 = dim === X ? S : max$2(pts[0][1], pts[1][1])
+        ]];
+      if (points.length > 1) move(event);
     } else {
       w0 = selection[0][0];
       n0 = selection[0][1];
@@ -4709,38 +5677,44 @@
     var overlay = group.selectAll(".overlay")
         .attr("cursor", cursors[type]);
 
-    if (exports.event.touches) {
+    if (event.touches) {
       emit.moved = moved;
       emit.ended = ended;
     } else {
-      var view = select(exports.event.view)
+      var view = select(event.view)
           .on("mousemove.brush", moved, true)
           .on("mouseup.brush", ended, true);
       if (keys) view
           .on("keydown.brush", keydowned, true)
           .on("keyup.brush", keyupped, true);
 
-      dragDisable(exports.event.view);
+      dragDisable(event.view);
     }
 
-    nopropagation$1();
-    interrupt(that);
     redraw.call(that);
-    emit.start();
+    emit.start(event, mode.name);
 
-    function moved() {
-      var point1 = pointer(that);
-      if (shifting && !lockX && !lockY) {
-        if (Math.abs(point1[0] - point[0]) > Math.abs(point1[1] - point[1])) lockY = true;
-        else lockX = true;
+    function moved(event) {
+      for (const p of event.changedTouches || [event]) {
+        for (const d of points)
+          if (d.identifier === p.identifier) d.cur = pointer(p, that);
       }
-      point = point1;
+      if (shifting && !lockX && !lockY && points.length === 1) {
+        const point = points[0];
+        if (abs$3(point.cur[0] - point[0]) > abs$3(point.cur[1] - point[1]))
+          lockY = true;
+        else
+          lockX = true;
+      }
+      for (const point of points)
+        if (point.cur) point[0] = point.cur[0], point[1] = point.cur[1];
       moving = true;
-      noevent$1();
-      move();
+      noevent$1(event);
+      move(event);
     }
 
-    function move() {
+    function move(event) {
+      const point = points[0], point0 = point.point0;
       var t;
 
       dx = point[0] - point0[0];
@@ -4749,20 +5723,25 @@
       switch (mode) {
         case MODE_SPACE:
         case MODE_DRAG: {
-          if (signX) dx = Math.max(W - w0, Math.min(E - e0, dx)), w1 = w0 + dx, e1 = e0 + dx;
-          if (signY) dy = Math.max(N - n0, Math.min(S - s0, dy)), n1 = n0 + dy, s1 = s0 + dy;
+          if (signX) dx = max$2(W - w0, min$1(E - e0, dx)), w1 = w0 + dx, e1 = e0 + dx;
+          if (signY) dy = max$2(N - n0, min$1(S - s0, dy)), n1 = n0 + dy, s1 = s0 + dy;
           break;
         }
         case MODE_HANDLE: {
-          if (signX < 0) dx = Math.max(W - w0, Math.min(E - w0, dx)), w1 = w0 + dx, e1 = e0;
-          else if (signX > 0) dx = Math.max(W - e0, Math.min(E - e0, dx)), w1 = w0, e1 = e0 + dx;
-          if (signY < 0) dy = Math.max(N - n0, Math.min(S - n0, dy)), n1 = n0 + dy, s1 = s0;
-          else if (signY > 0) dy = Math.max(N - s0, Math.min(S - s0, dy)), n1 = n0, s1 = s0 + dy;
+          if (points[1]) {
+            if (signX) w1 = max$2(W, min$1(E, points[0][0])), e1 = max$2(W, min$1(E, points[1][0])), signX = 1;
+            if (signY) n1 = max$2(N, min$1(S, points[0][1])), s1 = max$2(N, min$1(S, points[1][1])), signY = 1;
+          } else {
+            if (signX < 0) dx = max$2(W - w0, min$1(E - w0, dx)), w1 = w0 + dx, e1 = e0;
+            else if (signX > 0) dx = max$2(W - e0, min$1(E - e0, dx)), w1 = w0, e1 = e0 + dx;
+            if (signY < 0) dy = max$2(N - n0, min$1(S - n0, dy)), n1 = n0 + dy, s1 = s0;
+            else if (signY > 0) dy = max$2(N - s0, min$1(S - s0, dy)), n1 = n0, s1 = s0 + dy;
+          }
           break;
         }
         case MODE_CENTER: {
-          if (signX) w1 = Math.max(W, Math.min(E, w0 - dx * signX)), e1 = Math.max(W, Math.min(E, e0 + dx * signX));
-          if (signY) n1 = Math.max(N, Math.min(S, n0 - dy * signY)), s1 = Math.max(N, Math.min(S, s0 + dy * signY));
+          if (signX) w1 = max$2(W, min$1(E, w0 - dx * signX)), e1 = max$2(W, min$1(E, e0 + dx * signX));
+          if (signY) n1 = max$2(N, min$1(S, n0 - dy * signY)), s1 = max$2(N, min$1(S, s0 + dy * signY));
           break;
         }
       }
@@ -4791,29 +5770,29 @@
           || selection[1][1] !== s1) {
         state.selection = [[w1, n1], [e1, s1]];
         redraw.call(that);
-        emit.brush();
+        emit.brush(event, mode.name);
       }
     }
 
-    function ended() {
-      nopropagation$1();
-      if (exports.event.touches) {
-        if (exports.event.touches.length) return;
+    function ended(event) {
+      nopropagation$1(event);
+      if (event.touches) {
+        if (event.touches.length) return;
         if (touchending) clearTimeout(touchending);
         touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
       } else {
-        yesdrag(exports.event.view, moving);
+        yesdrag(event.view, moving);
         view.on("keydown.brush keyup.brush mousemove.brush mouseup.brush", null);
       }
       group.attr("pointer-events", "all");
       overlay.attr("cursor", cursors.overlay);
       if (state.selection) selection = state.selection; // May be set by brush.move (on start)!
-      if (empty$1(selection)) state.selection = null, redraw.call(that);
-      emit.end();
+      if (empty(selection)) state.selection = null, redraw.call(that);
+      emit.end(event, mode.name);
     }
 
-    function keydowned() {
-      switch (exports.event.keyCode) {
+    function keydowned(event) {
+      switch (event.keyCode) {
         case 16: { // SHIFT
           shifting = signX && signY;
           break;
@@ -4823,7 +5802,7 @@
             if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
             if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
             mode = MODE_CENTER;
-            move();
+            move(event);
           }
           break;
         }
@@ -4833,21 +5812,21 @@
             if (signY < 0) s0 = s1 - dy; else if (signY > 0) n0 = n1 - dy;
             mode = MODE_SPACE;
             overlay.attr("cursor", cursors.selection);
-            move();
+            move(event);
           }
           break;
         }
         default: return;
       }
-      noevent$1();
+      noevent$1(event);
     }
 
-    function keyupped() {
-      switch (exports.event.keyCode) {
+    function keyupped(event) {
+      switch (event.keyCode) {
         case 16: { // SHIFT
           if (shifting) {
             lockX = lockY = shifting = false;
-            move();
+            move(event);
           }
           break;
         }
@@ -4856,13 +5835,13 @@
             if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
             if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
             mode = MODE_HANDLE;
-            move();
+            move(event);
           }
           break;
         }
         case 32: { // SPACE
           if (mode === MODE_SPACE) {
-            if (exports.event.altKey) {
+            if (event.altKey) {
               if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
               if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
               mode = MODE_CENTER;
@@ -4872,22 +5851,22 @@
               mode = MODE_HANDLE;
             }
             overlay.attr("cursor", cursors[type]);
-            move();
+            move(event);
           }
           break;
         }
         default: return;
       }
-      noevent$1();
+      noevent$1(event);
     }
   }
 
-  function touchmoved() {
-    emitter(this, arguments).moved();
+  function touchmoved(event) {
+    emitter(this, arguments).moved(event);
   }
 
-  function touchended() {
-    emitter(this, arguments).ended();
+  function touchended(event) {
+    emitter(this, arguments).ended(event);
   }
 
   function initialize() {
@@ -4898,15 +5877,15 @@
   }
 
   brush.extent = function(_) {
-    return arguments.length ? (extent = typeof _ === "function" ? _ : constant$4(number2(_)), brush) : extent;
+    return arguments.length ? (extent = typeof _ === "function" ? _ : constant$7(number2(_)), brush) : extent;
   };
 
   brush.filter = function(_) {
-    return arguments.length ? (filter = typeof _ === "function" ? _ : constant$4(!!_), brush) : filter;
+    return arguments.length ? (filter = typeof _ === "function" ? _ : constant$7(!!_), brush) : filter;
   };
 
   brush.touchable = function(_) {
-    return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$4(!!_), brush) : touchable;
+    return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$7(!!_), brush) : touchable;
   };
 
   brush.handleSize = function(_) {
@@ -4925,12 +5904,18 @@
   return brush;
 }
 
-var cos = Math.cos;
-var sin = Math.sin;
-var pi$1 = Math.PI;
-var halfPi$1 = pi$1 / 2;
-var tau$1 = pi$1 * 2;
+var abs$2 = Math.abs;
+var cos$2 = Math.cos;
+var sin$2 = Math.sin;
+var pi$3 = Math.PI;
+var halfPi$2 = pi$3 / 2;
+var tau$4 = pi$3 * 2;
 var max$1 = Math.max;
+var epsilon$5 = 1e-12;
+
+function range$1(i, j) {
+  return Array.from({length: j - i}, (_, k) => i + k);
+}
 
 function compareValue(compare) {
   return function(a, b) {
@@ -4942,6 +5927,18 @@
 }
 
 function chord() {
+  return chord$1(false, false);
+}
+
+function chordTranspose() {
+  return chord$1(false, true);
+}
+
+function chordDirected() {
+  return chord$1(true, false);
+}
+
+function chord$1(directed, transpose) {
   var padAngle = 0,
       sortGroups = null,
       sortSubgroups = null,
@@ -4949,86 +5946,72 @@
 
   function chord(matrix) {
     var n = matrix.length,
-        groupSums = [],
-        groupIndex = sequence(n),
-        subgroupIndex = [],
-        chords = [],
-        groups = chords.groups = new Array(n),
-        subgroups = new Array(n * n),
-        k,
-        x,
-        x0,
-        dx,
-        i,
-        j;
+        groupSums = new Array(n),
+        groupIndex = range$1(0, n),
+        chords = new Array(n * n),
+        groups = new Array(n),
+        k = 0, dx;
 
-    // Compute the sum.
-    k = 0, i = -1; while (++i < n) {
-      x = 0, j = -1; while (++j < n) {
-        x += matrix[i][j];
-      }
-      groupSums.push(x);
-      subgroupIndex.push(sequence(n));
-      k += x;
+    matrix = Float64Array.from({length: n * n}, transpose
+        ? (_, i) => matrix[i % n][i / n | 0]
+        : (_, i) => matrix[i / n | 0][i % n]);
+
+    // Compute the scaling factor from value to angle in [0, 2pi].
+    for (let i = 0; i < n; ++i) {
+      let x = 0;
+      for (let j = 0; j < n; ++j) x += matrix[i * n + j] + directed * matrix[j * n + i];
+      k += groupSums[i] = x;
     }
+    k = max$1(0, tau$4 - padAngle * n) / k;
+    dx = k ? padAngle : tau$4 / n;
 
-    // Sort groups…
-    if (sortGroups) groupIndex.sort(function(a, b) {
-      return sortGroups(groupSums[a], groupSums[b]);
-    });
-
-    // Sort subgroups…
-    if (sortSubgroups) subgroupIndex.forEach(function(d, i) {
-      d.sort(function(a, b) {
-        return sortSubgroups(matrix[i][a], matrix[i][b]);
-      });
-    });
-
-    // Convert the sum to scaling factor for [0, 2pi].
-    // TODO Allow start and end angle to be specified?
-    // TODO Allow padding to be specified as percentage?
-    k = max$1(0, tau$1 - padAngle * n) / k;
-    dx = k ? padAngle : tau$1 / n;
-
-    // Compute the start and end angle for each group and subgroup.
-    // Note: Opera has a bug reordering object literal properties!
-    x = 0, i = -1; while (++i < n) {
-      x0 = x, j = -1; while (++j < n) {
-        var di = groupIndex[i],
-            dj = subgroupIndex[di][j],
-            v = matrix[di][dj],
-            a0 = x,
-            a1 = x += v * k;
-        subgroups[dj * n + di] = {
-          index: di,
-          subindex: dj,
-          startAngle: a0,
-          endAngle: a1,
-          value: v
-        };
-      }
-      groups[di] = {
-        index: di,
-        startAngle: x0,
-        endAngle: x,
-        value: groupSums[di]
-      };
-      x += dx;
-    }
-
-    // Generate chords for each (non-empty) subgroup-subgroup link.
-    i = -1; while (++i < n) {
-      j = i - 1; while (++j < n) {
-        var source = subgroups[j * n + i],
-            target = subgroups[i * n + j];
-        if (source.value || target.value) {
-          chords.push(source.value < target.value
-              ? {source: target, target: source}
-              : {source: source, target: target});
+    // Compute the angles for each group and constituent chord.
+    {
+      let x = 0;
+      if (sortGroups) groupIndex.sort((a, b) => sortGroups(groupSums[a], groupSums[b]));
+      for (const i of groupIndex) {
+        const x0 = x;
+        if (directed) {
+          const subgroupIndex = range$1(~n + 1, n).filter(j => j < 0 ? matrix[~j * n + i] : matrix[i * n + j]);
+          if (sortSubgroups) subgroupIndex.sort((a, b) => sortSubgroups(a < 0 ? -matrix[~a * n + i] : matrix[i * n + a], b < 0 ? -matrix[~b * n + i] : matrix[i * n + b]));
+          for (const j of subgroupIndex) {
+            if (j < 0) {
+              const chord = chords[~j * n + i] || (chords[~j * n + i] = {source: null, target: null});
+              chord.target = {index: i, startAngle: x, endAngle: x += matrix[~j * n + i] * k, value: matrix[~j * n + i]};
+            } else {
+              const chord = chords[i * n + j] || (chords[i * n + j] = {source: null, target: null});
+              chord.source = {index: i, startAngle: x, endAngle: x += matrix[i * n + j] * k, value: matrix[i * n + j]};
+            }
+          }
+          groups[i] = {index: i, startAngle: x0, endAngle: x, value: groupSums[i]};
+        } else {
+          const subgroupIndex = range$1(0, n).filter(j => matrix[i * n + j] || matrix[j * n + i]);
+          if (sortSubgroups) subgroupIndex.sort((a, b) => sortSubgroups(matrix[i * n + a], matrix[i * n + b]));
+          for (const j of subgroupIndex) {
+            let chord;
+            if (i < j) {
+              chord = chords[i * n + j] || (chords[i * n + j] = {source: null, target: null});
+              chord.source = {index: i, startAngle: x, endAngle: x += matrix[i * n + j] * k, value: matrix[i * n + j]};
+            } else {
+              chord = chords[j * n + i] || (chords[j * n + i] = {source: null, target: null});
+              chord.target = {index: i, startAngle: x, endAngle: x += matrix[i * n + j] * k, value: matrix[i * n + j]};
+              if (i === j) chord.source = chord.target;
+            }
+            if (chord.source && chord.target && chord.source.value < chord.target.value) {
+              const source = chord.source;
+              chord.source = chord.target;
+              chord.target = source;
+            }
+          }
+          groups[i] = {index: i, startAngle: x0, endAngle: x, value: groupSums[i]};
         }
+        x += dx;
       }
     }
 
+    // Remove empty chords.
+    chords = Object.values(chords);
+    chords.groups = groups;
     return sortChords ? chords.sort(sortChords) : chords;
   }
 
@@ -5051,52 +6034,63 @@
   return chord;
 }
 
-var slice$2 = Array.prototype.slice;
+const pi$2 = Math.PI,
+    tau$3 = 2 * pi$2,
+    epsilon$4 = 1e-6,
+    tauEpsilon = tau$3 - epsilon$4;
 
-function constant$5(x) {
-  return function() {
-    return x;
+function append$1(strings) {
+  this._ += strings[0];
+  for (let i = 1, n = strings.length; i < n; ++i) {
+    this._ += arguments[i] + strings[i];
+  }
+}
+
+function appendRound$1(digits) {
+  let d = Math.floor(digits);
+  if (!(d >= 0)) throw new Error(`invalid digits: ${digits}`);
+  if (d > 15) return append$1;
+  const k = 10 ** d;
+  return function(strings) {
+    this._ += strings[0];
+    for (let i = 1, n = strings.length; i < n; ++i) {
+      this._ += Math.round(arguments[i] * k) / k + strings[i];
+    }
   };
 }
 
-var pi$2 = Math.PI,
-    tau$2 = 2 * pi$2,
-    epsilon$1 = 1e-6,
-    tauEpsilon = tau$2 - epsilon$1;
-
-function Path() {
-  this._x0 = this._y0 = // start of current subpath
-  this._x1 = this._y1 = null; // end of current subpath
-  this._ = "";
-}
-
-function path() {
-  return new Path;
-}
-
-Path.prototype = path.prototype = {
-  constructor: Path,
-  moveTo: function(x, y) {
-    this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y);
-  },
-  closePath: function() {
+let Path$1 = class Path {
+  constructor(digits) {
+    this._x0 = this._y0 = // start of current subpath
+    this._x1 = this._y1 = null; // end of current subpath
+    this._ = "";
+    this._append = digits == null ? append$1 : appendRound$1(digits);
+  }
+  moveTo(x, y) {
+    this._append`M${this._x0 = this._x1 = +x},${this._y0 = this._y1 = +y}`;
+  }
+  closePath() {
     if (this._x1 !== null) {
       this._x1 = this._x0, this._y1 = this._y0;
-      this._ += "Z";
+      this._append`Z`;
     }
-  },
-  lineTo: function(x, y) {
-    this._ += "L" + (this._x1 = +x) + "," + (this._y1 = +y);
-  },
-  quadraticCurveTo: function(x1, y1, x, y) {
-    this._ += "Q" + (+x1) + "," + (+y1) + "," + (this._x1 = +x) + "," + (this._y1 = +y);
-  },
-  bezierCurveTo: function(x1, y1, x2, y2, x, y) {
-    this._ += "C" + (+x1) + "," + (+y1) + "," + (+x2) + "," + (+y2) + "," + (this._x1 = +x) + "," + (this._y1 = +y);
-  },
-  arcTo: function(x1, y1, x2, y2, r) {
+  }
+  lineTo(x, y) {
+    this._append`L${this._x1 = +x},${this._y1 = +y}`;
+  }
+  quadraticCurveTo(x1, y1, x, y) {
+    this._append`Q${+x1},${+y1},${this._x1 = +x},${this._y1 = +y}`;
+  }
+  bezierCurveTo(x1, y1, x2, y2, x, y) {
+    this._append`C${+x1},${+y1},${+x2},${+y2},${this._x1 = +x},${this._y1 = +y}`;
+  }
+  arcTo(x1, y1, x2, y2, r) {
     x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;
-    var x0 = this._x1,
+
+    // Is the radius negative? Error.
+    if (r < 0) throw new Error(`negative radius: ${r}`);
+
+    let x0 = this._x1,
         y0 = this._y1,
         x21 = x2 - x1,
         y21 = y2 - y1,
@@ -5104,27 +6098,24 @@
         y01 = y0 - y1,
         l01_2 = x01 * x01 + y01 * y01;
 
-    // Is the radius negative? Error.
-    if (r < 0) throw new Error("negative radius: " + r);
-
     // Is this path empty? Move to (x1,y1).
     if (this._x1 === null) {
-      this._ += "M" + (this._x1 = x1) + "," + (this._y1 = y1);
+      this._append`M${this._x1 = x1},${this._y1 = y1}`;
     }
 
     // Or, is (x1,y1) coincident with (x0,y0)? Do nothing.
-    else if (!(l01_2 > epsilon$1));
+    else if (!(l01_2 > epsilon$4));
 
     // Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?
     // Equivalently, is (x1,y1) coincident with (x2,y2)?
     // Or, is the radius zero? Line to (x1,y1).
-    else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon$1) || !r) {
-      this._ += "L" + (this._x1 = x1) + "," + (this._y1 = y1);
+    else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon$4) || !r) {
+      this._append`L${this._x1 = x1},${this._y1 = y1}`;
     }
 
     // Otherwise, draw an arc!
     else {
-      var x20 = x2 - x0,
+      let x20 = x2 - x0,
           y20 = y2 - y0,
           l21_2 = x21 * x21 + y21 * y21,
           l20_2 = x20 * x20 + y20 * y20,
@@ -5135,60 +6126,80 @@
           t21 = l / l21;
 
       // If the start tangent is not coincident with (x0,y0), line to.
-      if (Math.abs(t01 - 1) > epsilon$1) {
-        this._ += "L" + (x1 + t01 * x01) + "," + (y1 + t01 * y01);
+      if (Math.abs(t01 - 1) > epsilon$4) {
+        this._append`L${x1 + t01 * x01},${y1 + t01 * y01}`;
       }
 
-      this._ += "A" + r + "," + r + ",0,0," + (+(y01 * x20 > x01 * y20)) + "," + (this._x1 = x1 + t21 * x21) + "," + (this._y1 = y1 + t21 * y21);
+      this._append`A${r},${r},0,0,${+(y01 * x20 > x01 * y20)},${this._x1 = x1 + t21 * x21},${this._y1 = y1 + t21 * y21}`;
     }
-  },
-  arc: function(x, y, r, a0, a1, ccw) {
+  }
+  arc(x, y, r, a0, a1, ccw) {
     x = +x, y = +y, r = +r, ccw = !!ccw;
-    var dx = r * Math.cos(a0),
+
+    // Is the radius negative? Error.
+    if (r < 0) throw new Error(`negative radius: ${r}`);
+
+    let dx = r * Math.cos(a0),
         dy = r * Math.sin(a0),
         x0 = x + dx,
         y0 = y + dy,
         cw = 1 ^ ccw,
         da = ccw ? a0 - a1 : a1 - a0;
 
-    // Is the radius negative? Error.
-    if (r < 0) throw new Error("negative radius: " + r);
-
     // Is this path empty? Move to (x0,y0).
     if (this._x1 === null) {
-      this._ += "M" + x0 + "," + y0;
+      this._append`M${x0},${y0}`;
     }
 
     // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).
-    else if (Math.abs(this._x1 - x0) > epsilon$1 || Math.abs(this._y1 - y0) > epsilon$1) {
-      this._ += "L" + x0 + "," + y0;
+    else if (Math.abs(this._x1 - x0) > epsilon$4 || Math.abs(this._y1 - y0) > epsilon$4) {
+      this._append`L${x0},${y0}`;
     }
 
     // Is this arc empty? We’re done.
     if (!r) return;
 
     // Does the angle go the wrong way? Flip the direction.
-    if (da < 0) da = da % tau$2 + tau$2;
+    if (da < 0) da = da % tau$3 + tau$3;
 
     // Is this a complete circle? Draw two arcs to complete the circle.
     if (da > tauEpsilon) {
-      this._ += "A" + r + "," + r + ",0,1," + cw + "," + (x - dx) + "," + (y - dy) + "A" + r + "," + r + ",0,1," + cw + "," + (this._x1 = x0) + "," + (this._y1 = y0);
+      this._append`A${r},${r},0,1,${cw},${x - dx},${y - dy}A${r},${r},0,1,${cw},${this._x1 = x0},${this._y1 = y0}`;
     }
 
     // Is this arc non-empty? Draw an arc!
-    else if (da > epsilon$1) {
-      this._ += "A" + r + "," + r + ",0," + (+(da >= pi$2)) + "," + cw + "," + (this._x1 = x + r * Math.cos(a1)) + "," + (this._y1 = y + r * Math.sin(a1));
+    else if (da > epsilon$4) {
+      this._append`A${r},${r},0,${+(da >= pi$2)},${cw},${this._x1 = x + r * Math.cos(a1)},${this._y1 = y + r * Math.sin(a1)}`;
     }
-  },
-  rect: function(x, y, w, h) {
-    this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y) + "h" + (+w) + "v" + (+h) + "h" + (-w) + "Z";
-  },
-  toString: function() {
+  }
+  rect(x, y, w, h) {
+    this._append`M${this._x0 = this._x1 = +x},${this._y0 = this._y1 = +y}h${w = +w}v${+h}h${-w}Z`;
+  }
+  toString() {
     return this._;
   }
 };
 
-function defaultSource(d) {
+function path() {
+  return new Path$1;
+}
+
+// Allow instanceof d3.path
+path.prototype = Path$1.prototype;
+
+function pathRound(digits = 3) {
+  return new Path$1(+digits);
+}
+
+var slice$2 = Array.prototype.slice;
+
+function constant$6(x) {
+  return function() {
+    return x;
+  };
+}
+
+function defaultSource$1(d) {
   return d.source;
 }
 
@@ -5196,7 +6207,7 @@
   return d.target;
 }
 
-function defaultRadius(d) {
+function defaultRadius$1(d) {
   return d.radius;
 }
 
@@ -5208,52 +6219,91 @@
   return d.endAngle;
 }
 
-function ribbon() {
-  var source = defaultSource,
+function defaultPadAngle() {
+  return 0;
+}
+
+function defaultArrowheadRadius() {
+  return 10;
+}
+
+function ribbon(headRadius) {
+  var source = defaultSource$1,
       target = defaultTarget,
-      radius = defaultRadius,
+      sourceRadius = defaultRadius$1,
+      targetRadius = defaultRadius$1,
       startAngle = defaultStartAngle,
       endAngle = defaultEndAngle,
+      padAngle = defaultPadAngle,
       context = null;
 
   function ribbon() {
     var buffer,
+        s = source.apply(this, arguments),
+        t = target.apply(this, arguments),
+        ap = padAngle.apply(this, arguments) / 2,
         argv = slice$2.call(arguments),
-        s = source.apply(this, argv),
-        t = target.apply(this, argv),
-        sr = +radius.apply(this, (argv[0] = s, argv)),
-        sa0 = startAngle.apply(this, argv) - halfPi$1,
-        sa1 = endAngle.apply(this, argv) - halfPi$1,
-        sx0 = sr * cos(sa0),
-        sy0 = sr * sin(sa0),
-        tr = +radius.apply(this, (argv[0] = t, argv)),
-        ta0 = startAngle.apply(this, argv) - halfPi$1,
-        ta1 = endAngle.apply(this, argv) - halfPi$1;
+        sr = +sourceRadius.apply(this, (argv[0] = s, argv)),
+        sa0 = startAngle.apply(this, argv) - halfPi$2,
+        sa1 = endAngle.apply(this, argv) - halfPi$2,
+        tr = +targetRadius.apply(this, (argv[0] = t, argv)),
+        ta0 = startAngle.apply(this, argv) - halfPi$2,
+        ta1 = endAngle.apply(this, argv) - halfPi$2;
 
     if (!context) context = buffer = path();
 
-    context.moveTo(sx0, sy0);
-    context.arc(0, 0, sr, sa0, sa1);
-    if (sa0 !== ta0 || sa1 !== ta1) { // TODO sr !== tr?
-      context.quadraticCurveTo(0, 0, tr * cos(ta0), tr * sin(ta0));
-      context.arc(0, 0, tr, ta0, ta1);
+    if (ap > epsilon$5) {
+      if (abs$2(sa1 - sa0) > ap * 2 + epsilon$5) sa1 > sa0 ? (sa0 += ap, sa1 -= ap) : (sa0 -= ap, sa1 += ap);
+      else sa0 = sa1 = (sa0 + sa1) / 2;
+      if (abs$2(ta1 - ta0) > ap * 2 + epsilon$5) ta1 > ta0 ? (ta0 += ap, ta1 -= ap) : (ta0 -= ap, ta1 += ap);
+      else ta0 = ta1 = (ta0 + ta1) / 2;
     }
-    context.quadraticCurveTo(0, 0, sx0, sy0);
+
+    context.moveTo(sr * cos$2(sa0), sr * sin$2(sa0));
+    context.arc(0, 0, sr, sa0, sa1);
+    if (sa0 !== ta0 || sa1 !== ta1) {
+      if (headRadius) {
+        var hr = +headRadius.apply(this, arguments), tr2 = tr - hr, ta2 = (ta0 + ta1) / 2;
+        context.quadraticCurveTo(0, 0, tr2 * cos$2(ta0), tr2 * sin$2(ta0));
+        context.lineTo(tr * cos$2(ta2), tr * sin$2(ta2));
+        context.lineTo(tr2 * cos$2(ta1), tr2 * sin$2(ta1));
+      } else {
+        context.quadraticCurveTo(0, 0, tr * cos$2(ta0), tr * sin$2(ta0));
+        context.arc(0, 0, tr, ta0, ta1);
+      }
+    }
+    context.quadraticCurveTo(0, 0, sr * cos$2(sa0), sr * sin$2(sa0));
     context.closePath();
 
     if (buffer) return context = null, buffer + "" || null;
   }
 
+  if (headRadius) ribbon.headRadius = function(_) {
+    return arguments.length ? (headRadius = typeof _ === "function" ? _ : constant$6(+_), ribbon) : headRadius;
+  };
+
   ribbon.radius = function(_) {
-    return arguments.length ? (radius = typeof _ === "function" ? _ : constant$5(+_), ribbon) : radius;
+    return arguments.length ? (sourceRadius = targetRadius = typeof _ === "function" ? _ : constant$6(+_), ribbon) : sourceRadius;
+  };
+
+  ribbon.sourceRadius = function(_) {
+    return arguments.length ? (sourceRadius = typeof _ === "function" ? _ : constant$6(+_), ribbon) : sourceRadius;
+  };
+
+  ribbon.targetRadius = function(_) {
+    return arguments.length ? (targetRadius = typeof _ === "function" ? _ : constant$6(+_), ribbon) : targetRadius;
   };
 
   ribbon.startAngle = function(_) {
-    return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$5(+_), ribbon) : startAngle;
+    return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$6(+_), ribbon) : startAngle;
   };
 
   ribbon.endAngle = function(_) {
-    return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$5(+_), ribbon) : endAngle;
+    return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$6(+_), ribbon) : endAngle;
+  };
+
+  ribbon.padAngle = function(_) {
+    return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$6(+_), ribbon) : padAngle;
   };
 
   ribbon.source = function(_) {
@@ -5271,227 +6321,31 @@
   return ribbon;
 }
 
-var prefix = "$";
-
-function Map() {}
-
-Map.prototype = map$1.prototype = {
-  constructor: Map,
-  has: function(key) {
-    return (prefix + key) in this;
-  },
-  get: function(key) {
-    return this[prefix + key];
-  },
-  set: function(key, value) {
-    this[prefix + key] = value;
-    return this;
-  },
-  remove: function(key) {
-    var property = prefix + key;
-    return property in this && delete this[property];
-  },
-  clear: function() {
-    for (var property in this) if (property[0] === prefix) delete this[property];
-  },
-  keys: function() {
-    var keys = [];
-    for (var property in this) if (property[0] === prefix) keys.push(property.slice(1));
-    return keys;
-  },
-  values: function() {
-    var values = [];
-    for (var property in this) if (property[0] === prefix) values.push(this[property]);
-    return values;
-  },
-  entries: function() {
-    var entries = [];
-    for (var property in this) if (property[0] === prefix) entries.push({key: property.slice(1), value: this[property]});
-    return entries;
-  },
-  size: function() {
-    var size = 0;
-    for (var property in this) if (property[0] === prefix) ++size;
-    return size;
-  },
-  empty: function() {
-    for (var property in this) if (property[0] === prefix) return false;
-    return true;
-  },
-  each: function(f) {
-    for (var property in this) if (property[0] === prefix) f(this[property], property.slice(1), this);
-  }
-};
-
-function map$1(object, f) {
-  var map = new Map;
-
-  // Copy constructor.
-  if (object instanceof Map) object.each(function(value, key) { map.set(key, value); });
-
-  // Index array by numeric index or specified key function.
-  else if (Array.isArray(object)) {
-    var i = -1,
-        n = object.length,
-        o;
-
-    if (f == null) while (++i < n) map.set(i, object[i]);
-    else while (++i < n) map.set(f(o = object[i], i, object), o);
-  }
-
-  // Convert object to map.
-  else if (object) for (var key in object) map.set(key, object[key]);
-
-  return map;
+function ribbon$1() {
+  return ribbon();
 }
 
-function nest() {
-  var keys = [],
-      sortKeys = [],
-      sortValues,
-      rollup,
-      nest;
-
-  function apply(array, depth, createResult, setResult) {
-    if (depth >= keys.length) {
-      if (sortValues != null) array.sort(sortValues);
-      return rollup != null ? rollup(array) : array;
-    }
-
-    var i = -1,
-        n = array.length,
-        key = keys[depth++],
-        keyValue,
-        value,
-        valuesByKey = map$1(),
-        values,
-        result = createResult();
-
-    while (++i < n) {
-      if (values = valuesByKey.get(keyValue = key(value = array[i]) + "")) {
-        values.push(value);
-      } else {
-        valuesByKey.set(keyValue, [value]);
-      }
-    }
-
-    valuesByKey.each(function(values, key) {
-      setResult(result, key, apply(values, depth, createResult, setResult));
-    });
-
-    return result;
-  }
-
-  function entries(map, depth) {
-    if (++depth > keys.length) return map;
-    var array, sortKey = sortKeys[depth - 1];
-    if (rollup != null && depth >= keys.length) array = map.entries();
-    else array = [], map.each(function(v, k) { array.push({key: k, values: entries(v, depth)}); });
-    return sortKey != null ? array.sort(function(a, b) { return sortKey(a.key, b.key); }) : array;
-  }
-
-  return nest = {
-    object: function(array) { return apply(array, 0, createObject, setObject); },
-    map: function(array) { return apply(array, 0, createMap, setMap); },
-    entries: function(array) { return entries(apply(array, 0, createMap, setMap), 0); },
-    key: function(d) { keys.push(d); return nest; },
-    sortKeys: function(order) { sortKeys[keys.length - 1] = order; return nest; },
-    sortValues: function(order) { sortValues = order; return nest; },
-    rollup: function(f) { rollup = f; return nest; }
-  };
-}
-
-function createObject() {
-  return {};
-}
-
-function setObject(object, key, value) {
-  object[key] = value;
-}
-
-function createMap() {
-  return map$1();
-}
-
-function setMap(map, key, value) {
-  map.set(key, value);
-}
-
-function Set() {}
-
-var proto = map$1.prototype;
-
-Set.prototype = set$2.prototype = {
-  constructor: Set,
-  has: proto.has,
-  add: function(value) {
-    value += "";
-    this[prefix + value] = value;
-    return this;
-  },
-  remove: proto.remove,
-  clear: proto.clear,
-  values: proto.keys,
-  size: proto.size,
-  empty: proto.empty,
-  each: proto.each
-};
-
-function set$2(object, f) {
-  var set = new Set;
-
-  // Copy constructor.
-  if (object instanceof Set) object.each(function(value) { set.add(value); });
-
-  // Otherwise, assume it’s an array.
-  else if (object) {
-    var i = -1, n = object.length;
-    if (f == null) while (++i < n) set.add(object[i]);
-    else while (++i < n) set.add(f(object[i], i, object));
-  }
-
-  return set;
-}
-
-function keys(map) {
-  var keys = [];
-  for (var key in map) keys.push(key);
-  return keys;
-}
-
-function values(map) {
-  var values = [];
-  for (var key in map) values.push(map[key]);
-  return values;
-}
-
-function entries(map) {
-  var entries = [];
-  for (var key in map) entries.push({key: key, value: map[key]});
-  return entries;
+function ribbonArrow() {
+  return ribbon(defaultArrowheadRadius);
 }
 
 var array$2 = Array.prototype;
 
-var slice$3 = array$2.slice;
+var slice$1 = array$2.slice;
 
-function ascending$2(a, b) {
+function ascending$1(a, b) {
   return a - b;
 }
 
-function area(ring) {
+function area$3(ring) {
   var i = 0, n = ring.length, area = ring[n - 1][1] * ring[0][0] - ring[n - 1][0] * ring[0][1];
   while (++i < n) area += ring[i - 1][1] * ring[i][0] - ring[i - 1][0] * ring[i][1];
   return area;
 }
 
-function constant$6(x) {
-  return function() {
-    return x;
-  };
-}
+var constant$5 = x => () => x;
 
-function contains(ring, hole) {
+function contains$2(ring, hole) {
   var i = -1, n = hole.length, c;
   while (++i < n) if (c = ringContains(ring, hole[i])) return c;
   return 0;
@@ -5508,10 +6362,10 @@
 }
 
 function segmentContains(a, b, c) {
-  var i; return collinear(a, b, c) && within(a[i = +(a[0] === b[0])], c[i], b[i]);
+  var i; return collinear$1(a, b, c) && within(a[i = +(a[0] === b[0])], c[i], b[i]);
 }
 
-function collinear(a, b, c) {
+function collinear$1(a, b, c) {
   return (b[0] - a[0]) * (c[1] - a[1]) === (c[0] - a[0]) * (b[1] - a[1]);
 }
 
@@ -5519,7 +6373,7 @@
   return p <= q && q <= r || r <= q && q <= p;
 }
 
-function noop$1() {}
+function noop$2() {}
 
 var cases = [
   [],
@@ -5540,7 +6394,7 @@
   []
 ];
 
-function contours() {
+function Contours() {
   var dx = 1,
       dy = 1,
       threshold = thresholdSturges,
@@ -5551,33 +6405,35 @@
 
     // Convert number of thresholds into uniform thresholds.
     if (!Array.isArray(tz)) {
-      var domain = extent(values), start = domain[0], stop = domain[1];
-      tz = tickStep(start, stop, tz);
-      tz = sequence(Math.floor(start / tz) * tz, Math.floor(stop / tz) * tz, tz);
+      const e = extent$1(values, finite);
+      tz = ticks(...nice$1(e[0], e[1], tz), tz);
+      while (tz[tz.length - 1] >= e[1]) tz.pop();
+      while (tz[1] < e[0]) tz.shift();
     } else {
-      tz = tz.slice().sort(ascending$2);
+      tz = tz.slice().sort(ascending$1);
     }
 
-    return tz.map(function(value) {
-      return contour(values, value);
-    });
+    return tz.map(value => contour(values, value));
   }
 
   // Accumulate, smooth contour rings, assign holes to exterior rings.
   // Based on https://github.com/mbostock/shapefile/blob/v0.6.2/shp/polygon.js
   function contour(values, value) {
+    const v = value == null ? NaN : +value;
+    if (isNaN(v)) throw new Error(`invalid value: ${value}`);
+
     var polygons = [],
         holes = [];
 
-    isorings(values, value, function(ring) {
-      smooth(ring, values, value);
-      if (area(ring) > 0) polygons.push([ring]);
+    isorings(values, v, function(ring) {
+      smooth(ring, values, v);
+      if (area$3(ring) > 0) polygons.push([ring]);
       else holes.push(ring);
     });
 
     holes.forEach(function(hole) {
       for (var i = 0, n = polygons.length, polygon; i < n; ++i) {
-        if (contains((polygon = polygons[i])[0], hole) !== -1) {
+        if (contains$2((polygon = polygons[i])[0], hole) !== -1) {
           polygon.push(hole);
           return;
         }
@@ -5600,10 +6456,10 @@
 
     // Special case for the first row (y = -1, t2 = t3 = 0).
     x = y = -1;
-    t1 = values[0] >= value;
+    t1 = above(values[0], value);
     cases[t1 << 1].forEach(stitch);
     while (++x < dx - 1) {
-      t0 = t1, t1 = values[x + 1] >= value;
+      t0 = t1, t1 = above(values[x + 1], value);
       cases[t0 | t1 << 1].forEach(stitch);
     }
     cases[t1 << 0].forEach(stitch);
@@ -5611,12 +6467,12 @@
     // General case for the intermediate rows.
     while (++y < dy - 1) {
       x = -1;
-      t1 = values[y * dx + dx] >= value;
-      t2 = values[y * dx] >= value;
+      t1 = above(values[y * dx + dx], value);
+      t2 = above(values[y * dx], value);
       cases[t1 << 1 | t2 << 2].forEach(stitch);
       while (++x < dx - 1) {
-        t0 = t1, t1 = values[y * dx + dx + x + 1] >= value;
-        t3 = t2, t2 = values[y * dx + x + 1] >= value;
+        t0 = t1, t1 = above(values[y * dx + dx + x + 1], value);
+        t3 = t2, t2 = above(values[y * dx + x + 1], value);
         cases[t0 | t1 << 1 | t2 << 2 | t3 << 3].forEach(stitch);
       }
       cases[t1 | t2 << 3].forEach(stitch);
@@ -5627,7 +6483,7 @@
     t2 = values[y * dx] >= value;
     cases[t2 << 2].forEach(stitch);
     while (++x < dx - 1) {
-      t3 = t2, t2 = values[y * dx + x + 1] >= value;
+      t3 = t2, t2 = above(values[y * dx + x + 1], value);
       cases[t2 << 2 | t3 << 3].forEach(stitch);
     }
     cases[t2 << 3].forEach(stitch);
@@ -5684,15 +6540,12 @@
           y = point[1],
           xt = x | 0,
           yt = y | 0,
-          v0,
-          v1 = values[yt * dx + xt];
+          v1 = valid(values[yt * dx + xt]);
       if (x > 0 && x < dx && xt === x) {
-        v0 = values[yt * dx + xt - 1];
-        point[0] = x + (value - v0) / (v1 - v0) - 0.5;
+        point[0] = smooth1(x, valid(values[yt * dx + xt - 1]), v1, value);
       }
       if (y > 0 && y < dy && yt === y) {
-        v0 = values[(yt - 1) * dx + xt];
-        point[1] = y + (value - v0) / (v1 - v0) - 0.5;
+        point[1] = smooth1(y, valid(values[(yt - 1) * dx + xt]), v1, value);
       }
     });
   }
@@ -5701,71 +6554,50 @@
 
   contours.size = function(_) {
     if (!arguments.length) return [dx, dy];
-    var _0 = Math.ceil(_[0]), _1 = Math.ceil(_[1]);
-    if (!(_0 > 0) || !(_1 > 0)) throw new Error("invalid size");
+    var _0 = Math.floor(_[0]), _1 = Math.floor(_[1]);
+    if (!(_0 >= 0 && _1 >= 0)) throw new Error("invalid size");
     return dx = _0, dy = _1, contours;
   };
 
   contours.thresholds = function(_) {
-    return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant$6(slice$3.call(_)) : constant$6(_), contours) : threshold;
+    return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant$5(slice$1.call(_)) : constant$5(_), contours) : threshold;
   };
 
   contours.smooth = function(_) {
-    return arguments.length ? (smooth = _ ? smoothLinear : noop$1, contours) : smooth === smoothLinear;
+    return arguments.length ? (smooth = _ ? smoothLinear : noop$2, contours) : smooth === smoothLinear;
   };
 
   return contours;
 }
 
-// TODO Optimize edge cases.
-// TODO Optimize index calculation.
-// TODO Optimize arguments.
-function blurX(source, target, r) {
-  var n = source.width,
-      m = source.height,
-      w = (r << 1) + 1;
-  for (var j = 0; j < m; ++j) {
-    for (var i = 0, sr = 0; i < n + r; ++i) {
-      if (i < n) {
-        sr += source.data[i + j * n];
-      }
-      if (i >= r) {
-        if (i >= w) {
-          sr -= source.data[i - w + j * n];
-        }
-        target.data[i - r + j * n] = sr / Math.min(i + 1, n - 1 + w - i, w);
-      }
-    }
-  }
+// When computing the extent, ignore infinite values (as well as invalid ones).
+function finite(x) {
+  return isFinite(x) ? x : NaN;
 }
 
-// TODO Optimize edge cases.
-// TODO Optimize index calculation.
-// TODO Optimize arguments.
-function blurY(source, target, r) {
-  var n = source.width,
-      m = source.height,
-      w = (r << 1) + 1;
-  for (var i = 0; i < n; ++i) {
-    for (var j = 0, sr = 0; j < m + r; ++j) {
-      if (j < m) {
-        sr += source.data[i + j * n];
-      }
-      if (j >= r) {
-        if (j >= w) {
-          sr -= source.data[i + (j - w) * n];
-        }
-        target.data[i + (j - r) * n] = sr / Math.min(j + 1, m - 1 + w - j, w);
-      }
-    }
-  }
+// Is the (possibly invalid) x greater than or equal to the (known valid) value?
+// Treat any invalid value as below negative infinity.
+function above(x, value) {
+  return x == null ? false : +x >= value;
 }
 
-function defaultX(d) {
+// During smoothing, treat any invalid value as negative infinity.
+function valid(v) {
+  return v == null || isNaN(v = +v) ? -Infinity : v;
+}
+
+function smooth1(x, v0, v1, value) {
+  const a = value - v0;
+  const b = v1 - v0;
+  const d = isFinite(a) || isFinite(b) ? a / b : Math.sign(a) / Math.sign(b);
+  return isNaN(d) ? x : x + d - 0.5;
+}
+
+function defaultX$1(d) {
   return d[0];
 }
 
-function defaultY(d) {
+function defaultY$1(d) {
   return d[1];
 }
 
@@ -5774,8 +6606,8 @@
 }
 
 function density() {
-  var x = defaultX,
-      y = defaultY,
+  var x = defaultX$1,
+      y = defaultY$1,
       weight = defaultWeight,
       dx = 960,
       dy = 500,
@@ -5784,48 +6616,65 @@
       o = r * 3, // grid offset, to pad for blur
       n = (dx + o * 2) >> k, // grid width
       m = (dy + o * 2) >> k, // grid height
-      threshold = constant$6(20);
+      threshold = constant$5(20);
+
+  function grid(data) {
+    var values = new Float32Array(n * m),
+        pow2k = Math.pow(2, -k),
+        i = -1;
+
+    for (const d of data) {
+      var xi = (x(d, ++i, data) + o) * pow2k,
+          yi = (y(d, i, data) + o) * pow2k,
+          wi = +weight(d, i, data);
+      if (wi && xi >= 0 && xi < n && yi >= 0 && yi < m) {
+        var x0 = Math.floor(xi),
+            y0 = Math.floor(yi),
+            xt = xi - x0 - 0.5,
+            yt = yi - y0 - 0.5;
+        values[x0 + y0 * n] += (1 - xt) * (1 - yt) * wi;
+        values[x0 + 1 + y0 * n] += xt * (1 - yt) * wi;
+        values[x0 + 1 + (y0 + 1) * n] += xt * yt * wi;
+        values[x0 + (y0 + 1) * n] += (1 - xt) * yt * wi;
+      }
+    }
+
+    blur2({data: values, width: n, height: m}, r * pow2k);
+    return values;
+  }
 
   function density(data) {
-    var values0 = new Float32Array(n * m),
-        values1 = new Float32Array(n * m);
-
-    data.forEach(function(d, i, data) {
-      var xi = (+x(d, i, data) + o) >> k,
-          yi = (+y(d, i, data) + o) >> k,
-          wi = +weight(d, i, data);
-      if (xi >= 0 && xi < n && yi >= 0 && yi < m) {
-        values0[xi + yi * n] += wi;
-      }
-    });
-
-    // TODO Optimize.
-    blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k);
-    blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k);
-    blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k);
-    blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k);
-    blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k);
-    blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k);
-
-    var tz = threshold(values0);
+    var values = grid(data),
+        tz = threshold(values),
+        pow4k = Math.pow(2, 2 * k);
 
     // Convert number of thresholds into uniform thresholds.
     if (!Array.isArray(tz)) {
-      var stop = max(values0);
-      tz = tickStep(0, stop, tz);
-      tz = sequence(0, Math.floor(stop / tz) * tz, tz);
-      tz.shift();
+      tz = ticks(Number.MIN_VALUE, max$3(values) / pow4k, tz);
     }
 
-    return contours()
-        .thresholds(tz)
+    return Contours()
         .size([n, m])
-      (values0)
-        .map(transform);
+        .thresholds(tz.map(d => d * pow4k))
+      (values)
+        .map((c, i) => (c.value = +tz[i], transform(c)));
   }
 
+  density.contours = function(data) {
+    var values = grid(data),
+        contours = Contours().size([n, m]),
+        pow4k = Math.pow(2, 2 * k),
+        contour = value => {
+          value = +value;
+          var c = transform(contours.contour(values, value * pow4k));
+          c.value = value; // preserve exact threshold value
+          return c;
+        };
+    Object.defineProperty(contour, "max", {get: () => max$3(values) / pow4k});
+    return contour;
+  };
+
   function transform(geometry) {
-    geometry.value *= Math.pow(2, -2 * k); // Density in points per square pixel.
     geometry.coordinates.forEach(transformPolygon);
     return geometry;
   }
@@ -5852,21 +6701,21 @@
   }
 
   density.x = function(_) {
-    return arguments.length ? (x = typeof _ === "function" ? _ : constant$6(+_), density) : x;
+    return arguments.length ? (x = typeof _ === "function" ? _ : constant$5(+_), density) : x;
   };
 
   density.y = function(_) {
-    return arguments.length ? (y = typeof _ === "function" ? _ : constant$6(+_), density) : y;
+    return arguments.length ? (y = typeof _ === "function" ? _ : constant$5(+_), density) : y;
   };
 
   density.weight = function(_) {
-    return arguments.length ? (weight = typeof _ === "function" ? _ : constant$6(+_), density) : weight;
+    return arguments.length ? (weight = typeof _ === "function" ? _ : constant$5(+_), density) : weight;
   };
 
   density.size = function(_) {
     if (!arguments.length) return [dx, dy];
-    var _0 = Math.ceil(_[0]), _1 = Math.ceil(_[1]);
-    if (!(_0 >= 0) && !(_0 >= 0)) throw new Error("invalid size");
+    var _0 = +_[0], _1 = +_[1];
+    if (!(_0 >= 0 && _1 >= 0)) throw new Error("invalid size");
     return dx = _0, dy = _1, resize();
   };
 
@@ -5877,18 +6726,1396 @@
   };
 
   density.thresholds = function(_) {
-    return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant$6(slice$3.call(_)) : constant$6(_), density) : threshold;
+    return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant$5(slice$1.call(_)) : constant$5(_), density) : threshold;
   };
 
   density.bandwidth = function(_) {
     if (!arguments.length) return Math.sqrt(r * (r + 1));
     if (!((_ = +_) >= 0)) throw new Error("invalid bandwidth");
-    return r = Math.round((Math.sqrt(4 * _ * _ + 1) - 1) / 2), resize();
+    return r = (Math.sqrt(4 * _ * _ + 1) - 1) / 2, resize();
   };
 
   return density;
 }
 
+const epsilon$3 = 1.1102230246251565e-16;
+const splitter = 134217729;
+const resulterrbound = (3 + 8 * epsilon$3) * epsilon$3;
+
+// fast_expansion_sum_zeroelim routine from oritinal code
+function sum$1(elen, e, flen, f, h) {
+    let Q, Qnew, hh, bvirt;
+    let enow = e[0];
+    let fnow = f[0];
+    let eindex = 0;
+    let findex = 0;
+    if ((fnow > enow) === (fnow > -enow)) {
+        Q = enow;
+        enow = e[++eindex];
+    } else {
+        Q = fnow;
+        fnow = f[++findex];
+    }
+    let hindex = 0;
+    if (eindex < elen && findex < flen) {
+        if ((fnow > enow) === (fnow > -enow)) {
+            Qnew = enow + Q;
+            hh = Q - (Qnew - enow);
+            enow = e[++eindex];
+        } else {
+            Qnew = fnow + Q;
+            hh = Q - (Qnew - fnow);
+            fnow = f[++findex];
+        }
+        Q = Qnew;
+        if (hh !== 0) {
+            h[hindex++] = hh;
+        }
+        while (eindex < elen && findex < flen) {
+            if ((fnow > enow) === (fnow > -enow)) {
+                Qnew = Q + enow;
+                bvirt = Qnew - Q;
+                hh = Q - (Qnew - bvirt) + (enow - bvirt);
+                enow = e[++eindex];
+            } else {
+                Qnew = Q + fnow;
+                bvirt = Qnew - Q;
+                hh = Q - (Qnew - bvirt) + (fnow - bvirt);
+                fnow = f[++findex];
+            }
+            Q = Qnew;
+            if (hh !== 0) {
+                h[hindex++] = hh;
+            }
+        }
+    }
+    while (eindex < elen) {
+        Qnew = Q + enow;
+        bvirt = Qnew - Q;
+        hh = Q - (Qnew - bvirt) + (enow - bvirt);
+        enow = e[++eindex];
+        Q = Qnew;
+        if (hh !== 0) {
+            h[hindex++] = hh;
+        }
+    }
+    while (findex < flen) {
+        Qnew = Q + fnow;
+        bvirt = Qnew - Q;
+        hh = Q - (Qnew - bvirt) + (fnow - bvirt);
+        fnow = f[++findex];
+        Q = Qnew;
+        if (hh !== 0) {
+            h[hindex++] = hh;
+        }
+    }
+    if (Q !== 0 || hindex === 0) {
+        h[hindex++] = Q;
+    }
+    return hindex;
+}
+
+function estimate(elen, e) {
+    let Q = e[0];
+    for (let i = 1; i < elen; i++) Q += e[i];
+    return Q;
+}
+
+function vec(n) {
+    return new Float64Array(n);
+}
+
+const ccwerrboundA = (3 + 16 * epsilon$3) * epsilon$3;
+const ccwerrboundB = (2 + 12 * epsilon$3) * epsilon$3;
+const ccwerrboundC = (9 + 64 * epsilon$3) * epsilon$3 * epsilon$3;
+
+const B = vec(4);
+const C1 = vec(8);
+const C2 = vec(12);
+const D = vec(16);
+const u = vec(4);
+
+function orient2dadapt(ax, ay, bx, by, cx, cy, detsum) {
+    let acxtail, acytail, bcxtail, bcytail;
+    let bvirt, c, ahi, alo, bhi, blo, _i, _j, _0, s1, s0, t1, t0, u3;
+
+    const acx = ax - cx;
+    const bcx = bx - cx;
+    const acy = ay - cy;
+    const bcy = by - cy;
+
+    s1 = acx * bcy;
+    c = splitter * acx;
+    ahi = c - (c - acx);
+    alo = acx - ahi;
+    c = splitter * bcy;
+    bhi = c - (c - bcy);
+    blo = bcy - bhi;
+    s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
+    t1 = acy * bcx;
+    c = splitter * acy;
+    ahi = c - (c - acy);
+    alo = acy - ahi;
+    c = splitter * bcx;
+    bhi = c - (c - bcx);
+    blo = bcx - bhi;
+    t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
+    _i = s0 - t0;
+    bvirt = s0 - _i;
+    B[0] = s0 - (_i + bvirt) + (bvirt - t0);
+    _j = s1 + _i;
+    bvirt = _j - s1;
+    _0 = s1 - (_j - bvirt) + (_i - bvirt);
+    _i = _0 - t1;
+    bvirt = _0 - _i;
+    B[1] = _0 - (_i + bvirt) + (bvirt - t1);
+    u3 = _j + _i;
+    bvirt = u3 - _j;
+    B[2] = _j - (u3 - bvirt) + (_i - bvirt);
+    B[3] = u3;
+
+    let det = estimate(4, B);
+    let errbound = ccwerrboundB * detsum;
+    if (det >= errbound || -det >= errbound) {
+        return det;
+    }
+
+    bvirt = ax - acx;
+    acxtail = ax - (acx + bvirt) + (bvirt - cx);
+    bvirt = bx - bcx;
+    bcxtail = bx - (bcx + bvirt) + (bvirt - cx);
+    bvirt = ay - acy;
+    acytail = ay - (acy + bvirt) + (bvirt - cy);
+    bvirt = by - bcy;
+    bcytail = by - (bcy + bvirt) + (bvirt - cy);
+
+    if (acxtail === 0 && acytail === 0 && bcxtail === 0 && bcytail === 0) {
+        return det;
+    }
+
+    errbound = ccwerrboundC * detsum + resulterrbound * Math.abs(det);
+    det += (acx * bcytail + bcy * acxtail) - (acy * bcxtail + bcx * acytail);
+    if (det >= errbound || -det >= errbound) return det;
+
+    s1 = acxtail * bcy;
+    c = splitter * acxtail;
+    ahi = c - (c - acxtail);
+    alo = acxtail - ahi;
+    c = splitter * bcy;
+    bhi = c - (c - bcy);
+    blo = bcy - bhi;
+    s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
+    t1 = acytail * bcx;
+    c = splitter * acytail;
+    ahi = c - (c - acytail);
+    alo = acytail - ahi;
+    c = splitter * bcx;
+    bhi = c - (c - bcx);
+    blo = bcx - bhi;
+    t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
+    _i = s0 - t0;
+    bvirt = s0 - _i;
+    u[0] = s0 - (_i + bvirt) + (bvirt - t0);
+    _j = s1 + _i;
+    bvirt = _j - s1;
+    _0 = s1 - (_j - bvirt) + (_i - bvirt);
+    _i = _0 - t1;
+    bvirt = _0 - _i;
+    u[1] = _0 - (_i + bvirt) + (bvirt - t1);
+    u3 = _j + _i;
+    bvirt = u3 - _j;
+    u[2] = _j - (u3 - bvirt) + (_i - bvirt);
+    u[3] = u3;
+    const C1len = sum$1(4, B, 4, u, C1);
+
+    s1 = acx * bcytail;
+    c = splitter * acx;
+    ahi = c - (c - acx);
+    alo = acx - ahi;
+    c = splitter * bcytail;
+    bhi = c - (c - bcytail);
+    blo = bcytail - bhi;
+    s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
+    t1 = acy * bcxtail;
+    c = splitter * acy;
+    ahi = c - (c - acy);
+    alo = acy - ahi;
+    c = splitter * bcxtail;
+    bhi = c - (c - bcxtail);
+    blo = bcxtail - bhi;
+    t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
+    _i = s0 - t0;
+    bvirt = s0 - _i;
+    u[0] = s0 - (_i + bvirt) + (bvirt - t0);
+    _j = s1 + _i;
+    bvirt = _j - s1;
+    _0 = s1 - (_j - bvirt) + (_i - bvirt);
+    _i = _0 - t1;
+    bvirt = _0 - _i;
+    u[1] = _0 - (_i + bvirt) + (bvirt - t1);
+    u3 = _j + _i;
+    bvirt = u3 - _j;
+    u[2] = _j - (u3 - bvirt) + (_i - bvirt);
+    u[3] = u3;
+    const C2len = sum$1(C1len, C1, 4, u, C2);
+
+    s1 = acxtail * bcytail;
+    c = splitter * acxtail;
+    ahi = c - (c - acxtail);
+    alo = acxtail - ahi;
+    c = splitter * bcytail;
+    bhi = c - (c - bcytail);
+    blo = bcytail - bhi;
+    s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
+    t1 = acytail * bcxtail;
+    c = splitter * acytail;
+    ahi = c - (c - acytail);
+    alo = acytail - ahi;
+    c = splitter * bcxtail;
+    bhi = c - (c - bcxtail);
+    blo = bcxtail - bhi;
+    t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
+    _i = s0 - t0;
+    bvirt = s0 - _i;
+    u[0] = s0 - (_i + bvirt) + (bvirt - t0);
+    _j = s1 + _i;
+    bvirt = _j - s1;
+    _0 = s1 - (_j - bvirt) + (_i - bvirt);
+    _i = _0 - t1;
+    bvirt = _0 - _i;
+    u[1] = _0 - (_i + bvirt) + (bvirt - t1);
+    u3 = _j + _i;
+    bvirt = u3 - _j;
+    u[2] = _j - (u3 - bvirt) + (_i - bvirt);
+    u[3] = u3;
+    const Dlen = sum$1(C2len, C2, 4, u, D);
+
+    return D[Dlen - 1];
+}
+
+function orient2d(ax, ay, bx, by, cx, cy) {
+    const detleft = (ay - cy) * (bx - cx);
+    const detright = (ax - cx) * (by - cy);
+    const det = detleft - detright;
+
+    if (detleft === 0 || detright === 0 || (detleft > 0) !== (detright > 0)) return det;
+
+    const detsum = Math.abs(detleft + detright);
+    if (Math.abs(det) >= ccwerrboundA * detsum) return det;
+
+    return -orient2dadapt(ax, ay, bx, by, cx, cy, detsum);
+}
+
+const EPSILON = Math.pow(2, -52);
+const EDGE_STACK = new Uint32Array(512);
+
+class Delaunator {
+
+    static from(points, getX = defaultGetX, getY = defaultGetY) {
+        const n = points.length;
+        const coords = new Float64Array(n * 2);
+
+        for (let i = 0; i < n; i++) {
+            const p = points[i];
+            coords[2 * i] = getX(p);
+            coords[2 * i + 1] = getY(p);
+        }
+
+        return new Delaunator(coords);
+    }
+
+    constructor(coords) {
+        const n = coords.length >> 1;
+        if (n > 0 && typeof coords[0] !== 'number') throw new Error('Expected coords to contain numbers.');
+
+        this.coords = coords;
+
+        // arrays that will store the triangulation graph
+        const maxTriangles = Math.max(2 * n - 5, 0);
+        this._triangles = new Uint32Array(maxTriangles * 3);
+        this._halfedges = new Int32Array(maxTriangles * 3);
+
+        // temporary arrays for tracking the edges of the advancing convex hull
+        this._hashSize = Math.ceil(Math.sqrt(n));
+        this._hullPrev = new Uint32Array(n); // edge to prev edge
+        this._hullNext = new Uint32Array(n); // edge to next edge
+        this._hullTri = new Uint32Array(n); // edge to adjacent triangle
+        this._hullHash = new Int32Array(this._hashSize).fill(-1); // angular edge hash
+
+        // temporary arrays for sorting points
+        this._ids = new Uint32Array(n);
+        this._dists = new Float64Array(n);
+
+        this.update();
+    }
+
+    update() {
+        const {coords, _hullPrev: hullPrev, _hullNext: hullNext, _hullTri: hullTri, _hullHash: hullHash} =  this;
+        const n = coords.length >> 1;
+
+        // populate an array of point indices; calculate input data bbox
+        let minX = Infinity;
+        let minY = Infinity;
+        let maxX = -Infinity;
+        let maxY = -Infinity;
+
+        for (let i = 0; i < n; i++) {
+            const x = coords[2 * i];
+            const y = coords[2 * i + 1];
+            if (x < minX) minX = x;
+            if (y < minY) minY = y;
+            if (x > maxX) maxX = x;
+            if (y > maxY) maxY = y;
+            this._ids[i] = i;
+        }
+        const cx = (minX + maxX) / 2;
+        const cy = (minY + maxY) / 2;
+
+        let minDist = Infinity;
+        let i0, i1, i2;
+
+        // pick a seed point close to the center
+        for (let i = 0; i < n; i++) {
+            const d = dist(cx, cy, coords[2 * i], coords[2 * i + 1]);
+            if (d < minDist) {
+                i0 = i;
+                minDist = d;
+            }
+        }
+        const i0x = coords[2 * i0];
+        const i0y = coords[2 * i0 + 1];
+
+        minDist = Infinity;
+
+        // find the point closest to the seed
+        for (let i = 0; i < n; i++) {
+            if (i === i0) continue;
+            const d = dist(i0x, i0y, coords[2 * i], coords[2 * i + 1]);
+            if (d < minDist && d > 0) {
+                i1 = i;
+                minDist = d;
+            }
+        }
+        let i1x = coords[2 * i1];
+        let i1y = coords[2 * i1 + 1];
+
+        let minRadius = Infinity;
+
+        // find the third point which forms the smallest circumcircle with the first two
+        for (let i = 0; i < n; i++) {
+            if (i === i0 || i === i1) continue;
+            const r = circumradius(i0x, i0y, i1x, i1y, coords[2 * i], coords[2 * i + 1]);
+            if (r < minRadius) {
+                i2 = i;
+                minRadius = r;
+            }
+        }
+        let i2x = coords[2 * i2];
+        let i2y = coords[2 * i2 + 1];
+
+        if (minRadius === Infinity) {
+            // order collinear points by dx (or dy if all x are identical)
+            // and return the list as a hull
+            for (let i = 0; i < n; i++) {
+                this._dists[i] = (coords[2 * i] - coords[0]) || (coords[2 * i + 1] - coords[1]);
+            }
+            quicksort(this._ids, this._dists, 0, n - 1);
+            const hull = new Uint32Array(n);
+            let j = 0;
+            for (let i = 0, d0 = -Infinity; i < n; i++) {
+                const id = this._ids[i];
+                if (this._dists[id] > d0) {
+                    hull[j++] = id;
+                    d0 = this._dists[id];
+                }
+            }
+            this.hull = hull.subarray(0, j);
+            this.triangles = new Uint32Array(0);
+            this.halfedges = new Uint32Array(0);
+            return;
+        }
+
+        // swap the order of the seed points for counter-clockwise orientation
+        if (orient2d(i0x, i0y, i1x, i1y, i2x, i2y) < 0) {
+            const i = i1;
+            const x = i1x;
+            const y = i1y;
+            i1 = i2;
+            i1x = i2x;
+            i1y = i2y;
+            i2 = i;
+            i2x = x;
+            i2y = y;
+        }
+
+        const center = circumcenter(i0x, i0y, i1x, i1y, i2x, i2y);
+        this._cx = center.x;
+        this._cy = center.y;
+
+        for (let i = 0; i < n; i++) {
+            this._dists[i] = dist(coords[2 * i], coords[2 * i + 1], center.x, center.y);
+        }
+
+        // sort the points by distance from the seed triangle circumcenter
+        quicksort(this._ids, this._dists, 0, n - 1);
+
+        // set up the seed triangle as the starting hull
+        this._hullStart = i0;
+        let hullSize = 3;
+
+        hullNext[i0] = hullPrev[i2] = i1;
+        hullNext[i1] = hullPrev[i0] = i2;
+        hullNext[i2] = hullPrev[i1] = i0;
+
+        hullTri[i0] = 0;
+        hullTri[i1] = 1;
+        hullTri[i2] = 2;
+
+        hullHash.fill(-1);
+        hullHash[this._hashKey(i0x, i0y)] = i0;
+        hullHash[this._hashKey(i1x, i1y)] = i1;
+        hullHash[this._hashKey(i2x, i2y)] = i2;
+
+        this.trianglesLen = 0;
+        this._addTriangle(i0, i1, i2, -1, -1, -1);
+
+        for (let k = 0, xp, yp; k < this._ids.length; k++) {
+            const i = this._ids[k];
+            const x = coords[2 * i];
+            const y = coords[2 * i + 1];
+
+            // skip near-duplicate points
+            if (k > 0 && Math.abs(x - xp) <= EPSILON && Math.abs(y - yp) <= EPSILON) continue;
+            xp = x;
+            yp = y;
+
+            // skip seed triangle points
+            if (i === i0 || i === i1 || i === i2) continue;
+
+            // find a visible edge on the convex hull using edge hash
+            let start = 0;
+            for (let j = 0, key = this._hashKey(x, y); j < this._hashSize; j++) {
+                start = hullHash[(key + j) % this._hashSize];
+                if (start !== -1 && start !== hullNext[start]) break;
+            }
+
+            start = hullPrev[start];
+            let e = start, q;
+            while (q = hullNext[e], orient2d(x, y, coords[2 * e], coords[2 * e + 1], coords[2 * q], coords[2 * q + 1]) >= 0) {
+                e = q;
+                if (e === start) {
+                    e = -1;
+                    break;
+                }
+            }
+            if (e === -1) continue; // likely a near-duplicate point; skip it
+
+            // add the first triangle from the point
+            let t = this._addTriangle(e, i, hullNext[e], -1, -1, hullTri[e]);
+
+            // recursively flip triangles from the point until they satisfy the Delaunay condition
+            hullTri[i] = this._legalize(t + 2);
+            hullTri[e] = t; // keep track of boundary triangles on the hull
+            hullSize++;
+
+            // walk forward through the hull, adding more triangles and flipping recursively
+            let n = hullNext[e];
+            while (q = hullNext[n], orient2d(x, y, coords[2 * n], coords[2 * n + 1], coords[2 * q], coords[2 * q + 1]) < 0) {
+                t = this._addTriangle(n, i, q, hullTri[i], -1, hullTri[n]);
+                hullTri[i] = this._legalize(t + 2);
+                hullNext[n] = n; // mark as removed
+                hullSize--;
+                n = q;
+            }
+
+            // walk backward from the other side, adding more triangles and flipping
+            if (e === start) {
+                while (q = hullPrev[e], orient2d(x, y, coords[2 * q], coords[2 * q + 1], coords[2 * e], coords[2 * e + 1]) < 0) {
+                    t = this._addTriangle(q, i, e, -1, hullTri[e], hullTri[q]);
+                    this._legalize(t + 2);
+                    hullTri[q] = t;
+                    hullNext[e] = e; // mark as removed
+                    hullSize--;
+                    e = q;
+                }
+            }
+
+            // update the hull indices
+            this._hullStart = hullPrev[i] = e;
+            hullNext[e] = hullPrev[n] = i;
+            hullNext[i] = n;
+
+            // save the two new edges in the hash table
+            hullHash[this._hashKey(x, y)] = i;
+            hullHash[this._hashKey(coords[2 * e], coords[2 * e + 1])] = e;
+        }
+
+        this.hull = new Uint32Array(hullSize);
+        for (let i = 0, e = this._hullStart; i < hullSize; i++) {
+            this.hull[i] = e;
+            e = hullNext[e];
+        }
+
+        // trim typed triangle mesh arrays
+        this.triangles = this._triangles.subarray(0, this.trianglesLen);
+        this.halfedges = this._halfedges.subarray(0, this.trianglesLen);
+    }
+
+    _hashKey(x, y) {
+        return Math.floor(pseudoAngle(x - this._cx, y - this._cy) * this._hashSize) % this._hashSize;
+    }
+
+    _legalize(a) {
+        const {_triangles: triangles, _halfedges: halfedges, coords} = this;
+
+        let i = 0;
+        let ar = 0;
+
+        // recursion eliminated with a fixed-size stack
+        while (true) {
+            const b = halfedges[a];
+
+            /* if the pair of triangles doesn't satisfy the Delaunay condition
+             * (p1 is inside the circumcircle of [p0, pl, pr]), flip them,
+             * then do the same check/flip recursively for the new pair of triangles
+             *
+             *           pl                    pl
+             *          /||\                  /  \
+             *       al/ || \bl            al/    \a
+             *        /  ||  \              /      \
+             *       /  a||b  \    flip    /___ar___\
+             *     p0\   ||   /p1   =>   p0\---bl---/p1
+             *        \  ||  /              \      /
+             *       ar\ || /br             b\    /br
+             *          \||/                  \  /
+             *           pr                    pr
+             */
+            const a0 = a - a % 3;
+            ar = a0 + (a + 2) % 3;
+
+            if (b === -1) { // convex hull edge
+                if (i === 0) break;
+                a = EDGE_STACK[--i];
+                continue;
+            }
+
+            const b0 = b - b % 3;
+            const al = a0 + (a + 1) % 3;
+            const bl = b0 + (b + 2) % 3;
+
+            const p0 = triangles[ar];
+            const pr = triangles[a];
+            const pl = triangles[al];
+            const p1 = triangles[bl];
+
+            const illegal = inCircle(
+                coords[2 * p0], coords[2 * p0 + 1],
+                coords[2 * pr], coords[2 * pr + 1],
+                coords[2 * pl], coords[2 * pl + 1],
+                coords[2 * p1], coords[2 * p1 + 1]);
+
+            if (illegal) {
+                triangles[a] = p1;
+                triangles[b] = p0;
+
+                const hbl = halfedges[bl];
+
+                // edge swapped on the other side of the hull (rare); fix the halfedge reference
+                if (hbl === -1) {
+                    let e = this._hullStart;
+                    do {
+                        if (this._hullTri[e] === bl) {
+                            this._hullTri[e] = a;
+                            break;
+                        }
+                        e = this._hullPrev[e];
+                    } while (e !== this._hullStart);
+                }
+                this._link(a, hbl);
+                this._link(b, halfedges[ar]);
+                this._link(ar, bl);
+
+                const br = b0 + (b + 1) % 3;
+
+                // don't worry about hitting the cap: it can only happen on extremely degenerate input
+                if (i < EDGE_STACK.length) {
+                    EDGE_STACK[i++] = br;
+                }
+            } else {
+                if (i === 0) break;
+                a = EDGE_STACK[--i];
+            }
+        }
+
+        return ar;
+    }
+
+    _link(a, b) {
+        this._halfedges[a] = b;
+        if (b !== -1) this._halfedges[b] = a;
+    }
+
+    // add a new triangle given vertex indices and adjacent half-edge ids
+    _addTriangle(i0, i1, i2, a, b, c) {
+        const t = this.trianglesLen;
+
+        this._triangles[t] = i0;
+        this._triangles[t + 1] = i1;
+        this._triangles[t + 2] = i2;
+
+        this._link(t, a);
+        this._link(t + 1, b);
+        this._link(t + 2, c);
+
+        this.trianglesLen += 3;
+
+        return t;
+    }
+}
+
+// monotonically increases with real angle, but doesn't need expensive trigonometry
+function pseudoAngle(dx, dy) {
+    const p = dx / (Math.abs(dx) + Math.abs(dy));
+    return (dy > 0 ? 3 - p : 1 + p) / 4; // [0..1]
+}
+
+function dist(ax, ay, bx, by) {
+    const dx = ax - bx;
+    const dy = ay - by;
+    return dx * dx + dy * dy;
+}
+
+function inCircle(ax, ay, bx, by, cx, cy, px, py) {
+    const dx = ax - px;
+    const dy = ay - py;
+    const ex = bx - px;
+    const ey = by - py;
+    const fx = cx - px;
+    const fy = cy - py;
+
+    const ap = dx * dx + dy * dy;
+    const bp = ex * ex + ey * ey;
+    const cp = fx * fx + fy * fy;
+
+    return dx * (ey * cp - bp * fy) -
+           dy * (ex * cp - bp * fx) +
+           ap * (ex * fy - ey * fx) < 0;
+}
+
+function circumradius(ax, ay, bx, by, cx, cy) {
+    const dx = bx - ax;
+    const dy = by - ay;
+    const ex = cx - ax;
+    const ey = cy - ay;
+
+    const bl = dx * dx + dy * dy;
+    const cl = ex * ex + ey * ey;
+    const d = 0.5 / (dx * ey - dy * ex);
+
+    const x = (ey * bl - dy * cl) * d;
+    const y = (dx * cl - ex * bl) * d;
+
+    return x * x + y * y;
+}
+
+function circumcenter(ax, ay, bx, by, cx, cy) {
+    const dx = bx - ax;
+    const dy = by - ay;
+    const ex = cx - ax;
+    const ey = cy - ay;
+
+    const bl = dx * dx + dy * dy;
+    const cl = ex * ex + ey * ey;
+    const d = 0.5 / (dx * ey - dy * ex);
+
+    const x = ax + (ey * bl - dy * cl) * d;
+    const y = ay + (dx * cl - ex * bl) * d;
+
+    return {x, y};
+}
+
+function quicksort(ids, dists, left, right) {
+    if (right - left <= 20) {
+        for (let i = left + 1; i <= right; i++) {
+            const temp = ids[i];
+            const tempDist = dists[temp];
+            let j = i - 1;
+            while (j >= left && dists[ids[j]] > tempDist) ids[j + 1] = ids[j--];
+            ids[j + 1] = temp;
+        }
+    } else {
+        const median = (left + right) >> 1;
+        let i = left + 1;
+        let j = right;
+        swap(ids, median, i);
+        if (dists[ids[left]] > dists[ids[right]]) swap(ids, left, right);
+        if (dists[ids[i]] > dists[ids[right]]) swap(ids, i, right);
+        if (dists[ids[left]] > dists[ids[i]]) swap(ids, left, i);
+
+        const temp = ids[i];
+        const tempDist = dists[temp];
+        while (true) {
+            do i++; while (dists[ids[i]] < tempDist);
+            do j--; while (dists[ids[j]] > tempDist);
+            if (j < i) break;
+            swap(ids, i, j);
+        }
+        ids[left + 1] = ids[j];
+        ids[j] = temp;
+
+        if (right - i + 1 >= j - left) {
+            quicksort(ids, dists, i, right);
+            quicksort(ids, dists, left, j - 1);
+        } else {
+            quicksort(ids, dists, left, j - 1);
+            quicksort(ids, dists, i, right);
+        }
+    }
+}
+
+function swap(arr, i, j) {
+    const tmp = arr[i];
+    arr[i] = arr[j];
+    arr[j] = tmp;
+}
+
+function defaultGetX(p) {
+    return p[0];
+}
+function defaultGetY(p) {
+    return p[1];
+}
+
+const epsilon$2 = 1e-6;
+
+class Path {
+  constructor() {
+    this._x0 = this._y0 = // start of current subpath
+    this._x1 = this._y1 = null; // end of current subpath
+    this._ = "";
+  }
+  moveTo(x, y) {
+    this._ += `M${this._x0 = this._x1 = +x},${this._y0 = this._y1 = +y}`;
+  }
+  closePath() {
+    if (this._x1 !== null) {
+      this._x1 = this._x0, this._y1 = this._y0;
+      this._ += "Z";
+    }
+  }
+  lineTo(x, y) {
+    this._ += `L${this._x1 = +x},${this._y1 = +y}`;
+  }
+  arc(x, y, r) {
+    x = +x, y = +y, r = +r;
+    const x0 = x + r;
+    const y0 = y;
+    if (r < 0) throw new Error("negative radius");
+    if (this._x1 === null) this._ += `M${x0},${y0}`;
+    else if (Math.abs(this._x1 - x0) > epsilon$2 || Math.abs(this._y1 - y0) > epsilon$2) this._ += "L" + x0 + "," + y0;
+    if (!r) return;
+    this._ += `A${r},${r},0,1,1,${x - r},${y}A${r},${r},0,1,1,${this._x1 = x0},${this._y1 = y0}`;
+  }
+  rect(x, y, w, h) {
+    this._ += `M${this._x0 = this._x1 = +x},${this._y0 = this._y1 = +y}h${+w}v${+h}h${-w}Z`;
+  }
+  value() {
+    return this._ || null;
+  }
+}
+
+class Polygon {
+  constructor() {
+    this._ = [];
+  }
+  moveTo(x, y) {
+    this._.push([x, y]);
+  }
+  closePath() {
+    this._.push(this._[0].slice());
+  }
+  lineTo(x, y) {
+    this._.push([x, y]);
+  }
+  value() {
+    return this._.length ? this._ : null;
+  }
+}
+
+class Voronoi {
+  constructor(delaunay, [xmin, ymin, xmax, ymax] = [0, 0, 960, 500]) {
+    if (!((xmax = +xmax) >= (xmin = +xmin)) || !((ymax = +ymax) >= (ymin = +ymin))) throw new Error("invalid bounds");
+    this.delaunay = delaunay;
+    this._circumcenters = new Float64Array(delaunay.points.length * 2);
+    this.vectors = new Float64Array(delaunay.points.length * 2);
+    this.xmax = xmax, this.xmin = xmin;
+    this.ymax = ymax, this.ymin = ymin;
+    this._init();
+  }
+  update() {
+    this.delaunay.update();
+    this._init();
+    return this;
+  }
+  _init() {
+    const {delaunay: {points, hull, triangles}, vectors} = this;
+    let bx, by; // lazily computed barycenter of the hull
+
+    // Compute circumcenters.
+    const circumcenters = this.circumcenters = this._circumcenters.subarray(0, triangles.length / 3 * 2);
+    for (let i = 0, j = 0, n = triangles.length, x, y; i < n; i += 3, j += 2) {
+      const t1 = triangles[i] * 2;
+      const t2 = triangles[i + 1] * 2;
+      const t3 = triangles[i + 2] * 2;
+      const x1 = points[t1];
+      const y1 = points[t1 + 1];
+      const x2 = points[t2];
+      const y2 = points[t2 + 1];
+      const x3 = points[t3];
+      const y3 = points[t3 + 1];
+
+      const dx = x2 - x1;
+      const dy = y2 - y1;
+      const ex = x3 - x1;
+      const ey = y3 - y1;
+      const ab = (dx * ey - dy * ex) * 2;
+
+      if (Math.abs(ab) < 1e-9) {
+        // For a degenerate triangle, the circumcenter is at the infinity, in a
+        // direction orthogonal to the halfedge and away from the “center” of
+        // the diagram <bx, by>, defined as the hull’s barycenter.
+        if (bx === undefined) {
+          bx = by = 0;
+          for (const i of hull) bx += points[i * 2], by += points[i * 2 + 1];
+          bx /= hull.length, by /= hull.length;
+        }
+        const a = 1e9 * Math.sign((bx - x1) * ey - (by - y1) * ex);
+        x = (x1 + x3) / 2 - a * ey;
+        y = (y1 + y3) / 2 + a * ex;
+      } else {
+        const d = 1 / ab;
+        const bl = dx * dx + dy * dy;
+        const cl = ex * ex + ey * ey;
+        x = x1 + (ey * bl - dy * cl) * d;
+        y = y1 + (dx * cl - ex * bl) * d;
+      }
+      circumcenters[j] = x;
+      circumcenters[j + 1] = y;
+    }
+
+    // Compute exterior cell rays.
+    let h = hull[hull.length - 1];
+    let p0, p1 = h * 4;
+    let x0, x1 = points[2 * h];
+    let y0, y1 = points[2 * h + 1];
+    vectors.fill(0);
+    for (let i = 0; i < hull.length; ++i) {
+      h = hull[i];
+      p0 = p1, x0 = x1, y0 = y1;
+      p1 = h * 4, x1 = points[2 * h], y1 = points[2 * h + 1];
+      vectors[p0 + 2] = vectors[p1] = y0 - y1;
+      vectors[p0 + 3] = vectors[p1 + 1] = x1 - x0;
+    }
+  }
+  render(context) {
+    const buffer = context == null ? context = new Path : undefined;
+    const {delaunay: {halfedges, inedges, hull}, circumcenters, vectors} = this;
+    if (hull.length <= 1) return null;
+    for (let i = 0, n = halfedges.length; i < n; ++i) {
+      const j = halfedges[i];
+      if (j < i) continue;
+      const ti = Math.floor(i / 3) * 2;
+      const tj = Math.floor(j / 3) * 2;
+      const xi = circumcenters[ti];
+      const yi = circumcenters[ti + 1];
+      const xj = circumcenters[tj];
+      const yj = circumcenters[tj + 1];
+      this._renderSegment(xi, yi, xj, yj, context);
+    }
+    let h0, h1 = hull[hull.length - 1];
+    for (let i = 0; i < hull.length; ++i) {
+      h0 = h1, h1 = hull[i];
+      const t = Math.floor(inedges[h1] / 3) * 2;
+      const x = circumcenters[t];
+      const y = circumcenters[t + 1];
+      const v = h0 * 4;
+      const p = this._project(x, y, vectors[v + 2], vectors[v + 3]);
+      if (p) this._renderSegment(x, y, p[0], p[1], context);
+    }
+    return buffer && buffer.value();
+  }
+  renderBounds(context) {
+    const buffer = context == null ? context = new Path : undefined;
+    context.rect(this.xmin, this.ymin, this.xmax - this.xmin, this.ymax - this.ymin);
+    return buffer && buffer.value();
+  }
+  renderCell(i, context) {
+    const buffer = context == null ? context = new Path : undefined;
+    const points = this._clip(i);
+    if (points === null || !points.length) return;
+    context.moveTo(points[0], points[1]);
+    let n = points.length;
+    while (points[0] === points[n-2] && points[1] === points[n-1] && n > 1) n -= 2;
+    for (let i = 2; i < n; i += 2) {
+      if (points[i] !== points[i-2] || points[i+1] !== points[i-1])
+        context.lineTo(points[i], points[i + 1]);
+    }
+    context.closePath();
+    return buffer && buffer.value();
+  }
+  *cellPolygons() {
+    const {delaunay: {points}} = this;
+    for (let i = 0, n = points.length / 2; i < n; ++i) {
+      const cell = this.cellPolygon(i);
+      if (cell) cell.index = i, yield cell;
+    }
+  }
+  cellPolygon(i) {
+    const polygon = new Polygon;
+    this.renderCell(i, polygon);
+    return polygon.value();
+  }
+  _renderSegment(x0, y0, x1, y1, context) {
+    let S;
+    const c0 = this._regioncode(x0, y0);
+    const c1 = this._regioncode(x1, y1);
+    if (c0 === 0 && c1 === 0) {
+      context.moveTo(x0, y0);
+      context.lineTo(x1, y1);
+    } else if (S = this._clipSegment(x0, y0, x1, y1, c0, c1)) {
+      context.moveTo(S[0], S[1]);
+      context.lineTo(S[2], S[3]);
+    }
+  }
+  contains(i, x, y) {
+    if ((x = +x, x !== x) || (y = +y, y !== y)) return false;
+    return this.delaunay._step(i, x, y) === i;
+  }
+  *neighbors(i) {
+    const ci = this._clip(i);
+    if (ci) for (const j of this.delaunay.neighbors(i)) {
+      const cj = this._clip(j);
+      // find the common edge
+      if (cj) loop: for (let ai = 0, li = ci.length; ai < li; ai += 2) {
+        for (let aj = 0, lj = cj.length; aj < lj; aj += 2) {
+          if (ci[ai] === cj[aj]
+              && ci[ai + 1] === cj[aj + 1]
+              && ci[(ai + 2) % li] === cj[(aj + lj - 2) % lj]
+              && ci[(ai + 3) % li] === cj[(aj + lj - 1) % lj]) {
+            yield j;
+            break loop;
+          }
+        }
+      }
+    }
+  }
+  _cell(i) {
+    const {circumcenters, delaunay: {inedges, halfedges, triangles}} = this;
+    const e0 = inedges[i];
+    if (e0 === -1) return null; // coincident point
+    const points = [];
+    let e = e0;
+    do {
+      const t = Math.floor(e / 3);
+      points.push(circumcenters[t * 2], circumcenters[t * 2 + 1]);
+      e = e % 3 === 2 ? e - 2 : e + 1;
+      if (triangles[e] !== i) break; // bad triangulation
+      e = halfedges[e];
+    } while (e !== e0 && e !== -1);
+    return points;
+  }
+  _clip(i) {
+    // degenerate case (1 valid point: return the box)
+    if (i === 0 && this.delaunay.hull.length === 1) {
+      return [this.xmax, this.ymin, this.xmax, this.ymax, this.xmin, this.ymax, this.xmin, this.ymin];
+    }
+    const points = this._cell(i);
+    if (points === null) return null;
+    const {vectors: V} = this;
+    const v = i * 4;
+    return this._simplify(V[v] || V[v + 1]
+        ? this._clipInfinite(i, points, V[v], V[v + 1], V[v + 2], V[v + 3])
+        : this._clipFinite(i, points));
+  }
+  _clipFinite(i, points) {
+    const n = points.length;
+    let P = null;
+    let x0, y0, x1 = points[n - 2], y1 = points[n - 1];
+    let c0, c1 = this._regioncode(x1, y1);
+    let e0, e1 = 0;
+    for (let j = 0; j < n; j += 2) {
+      x0 = x1, y0 = y1, x1 = points[j], y1 = points[j + 1];
+      c0 = c1, c1 = this._regioncode(x1, y1);
+      if (c0 === 0 && c1 === 0) {
+        e0 = e1, e1 = 0;
+        if (P) P.push(x1, y1);
+        else P = [x1, y1];
+      } else {
+        let S, sx0, sy0, sx1, sy1;
+        if (c0 === 0) {
+          if ((S = this._clipSegment(x0, y0, x1, y1, c0, c1)) === null) continue;
+          [sx0, sy0, sx1, sy1] = S;
+        } else {
+          if ((S = this._clipSegment(x1, y1, x0, y0, c1, c0)) === null) continue;
+          [sx1, sy1, sx0, sy0] = S;
+          e0 = e1, e1 = this._edgecode(sx0, sy0);
+          if (e0 && e1) this._edge(i, e0, e1, P, P.length);
+          if (P) P.push(sx0, sy0);
+          else P = [sx0, sy0];
+        }
+        e0 = e1, e1 = this._edgecode(sx1, sy1);
+        if (e0 && e1) this._edge(i, e0, e1, P, P.length);
+        if (P) P.push(sx1, sy1);
+        else P = [sx1, sy1];
+      }
+    }
+    if (P) {
+      e0 = e1, e1 = this._edgecode(P[0], P[1]);
+      if (e0 && e1) this._edge(i, e0, e1, P, P.length);
+    } else if (this.contains(i, (this.xmin + this.xmax) / 2, (this.ymin + this.ymax) / 2)) {
+      return [this.xmax, this.ymin, this.xmax, this.ymax, this.xmin, this.ymax, this.xmin, this.ymin];
+    }
+    return P;
+  }
+  _clipSegment(x0, y0, x1, y1, c0, c1) {
+    // for more robustness, always consider the segment in the same order
+    const flip = c0 < c1;
+    if (flip) [x0, y0, x1, y1, c0, c1] = [x1, y1, x0, y0, c1, c0];
+    while (true) {
+      if (c0 === 0 && c1 === 0) return flip ? [x1, y1, x0, y0] : [x0, y0, x1, y1];
+      if (c0 & c1) return null;
+      let x, y, c = c0 || c1;
+      if (c & 0b1000) x = x0 + (x1 - x0) * (this.ymax - y0) / (y1 - y0), y = this.ymax;
+      else if (c & 0b0100) x = x0 + (x1 - x0) * (this.ymin - y0) / (y1 - y0), y = this.ymin;
+      else if (c & 0b0010) y = y0 + (y1 - y0) * (this.xmax - x0) / (x1 - x0), x = this.xmax;
+      else y = y0 + (y1 - y0) * (this.xmin - x0) / (x1 - x0), x = this.xmin;
+      if (c0) x0 = x, y0 = y, c0 = this._regioncode(x0, y0);
+      else x1 = x, y1 = y, c1 = this._regioncode(x1, y1);
+    }
+  }
+  _clipInfinite(i, points, vx0, vy0, vxn, vyn) {
+    let P = Array.from(points), p;
+    if (p = this._project(P[0], P[1], vx0, vy0)) P.unshift(p[0], p[1]);
+    if (p = this._project(P[P.length - 2], P[P.length - 1], vxn, vyn)) P.push(p[0], p[1]);
+    if (P = this._clipFinite(i, P)) {
+      for (let j = 0, n = P.length, c0, c1 = this._edgecode(P[n - 2], P[n - 1]); j < n; j += 2) {
+        c0 = c1, c1 = this._edgecode(P[j], P[j + 1]);
+        if (c0 && c1) j = this._edge(i, c0, c1, P, j), n = P.length;
+      }
+    } else if (this.contains(i, (this.xmin + this.xmax) / 2, (this.ymin + this.ymax) / 2)) {
+      P = [this.xmin, this.ymin, this.xmax, this.ymin, this.xmax, this.ymax, this.xmin, this.ymax];
+    }
+    return P;
+  }
+  _edge(i, e0, e1, P, j) {
+    while (e0 !== e1) {
+      let x, y;
+      switch (e0) {
+        case 0b0101: e0 = 0b0100; continue; // top-left
+        case 0b0100: e0 = 0b0110, x = this.xmax, y = this.ymin; break; // top
+        case 0b0110: e0 = 0b0010; continue; // top-right
+        case 0b0010: e0 = 0b1010, x = this.xmax, y = this.ymax; break; // right
+        case 0b1010: e0 = 0b1000; continue; // bottom-right
+        case 0b1000: e0 = 0b1001, x = this.xmin, y = this.ymax; break; // bottom
+        case 0b1001: e0 = 0b0001; continue; // bottom-left
+        case 0b0001: e0 = 0b0101, x = this.xmin, y = this.ymin; break; // left
+      }
+      // Note: this implicitly checks for out of bounds: if P[j] or P[j+1] are
+      // undefined, the conditional statement will be executed.
+      if ((P[j] !== x || P[j + 1] !== y) && this.contains(i, x, y)) {
+        P.splice(j, 0, x, y), j += 2;
+      }
+    }
+    return j;
+  }
+  _project(x0, y0, vx, vy) {
+    let t = Infinity, c, x, y;
+    if (vy < 0) { // top
+      if (y0 <= this.ymin) return null;
+      if ((c = (this.ymin - y0) / vy) < t) y = this.ymin, x = x0 + (t = c) * vx;
+    } else if (vy > 0) { // bottom
+      if (y0 >= this.ymax) return null;
+      if ((c = (this.ymax - y0) / vy) < t) y = this.ymax, x = x0 + (t = c) * vx;
+    }
+    if (vx > 0) { // right
+      if (x0 >= this.xmax) return null;
+      if ((c = (this.xmax - x0) / vx) < t) x = this.xmax, y = y0 + (t = c) * vy;
+    } else if (vx < 0) { // left
+      if (x0 <= this.xmin) return null;
+      if ((c = (this.xmin - x0) / vx) < t) x = this.xmin, y = y0 + (t = c) * vy;
+    }
+    return [x, y];
+  }
+  _edgecode(x, y) {
+    return (x === this.xmin ? 0b0001
+        : x === this.xmax ? 0b0010 : 0b0000)
+        | (y === this.ymin ? 0b0100
+        : y === this.ymax ? 0b1000 : 0b0000);
+  }
+  _regioncode(x, y) {
+    return (x < this.xmin ? 0b0001
+        : x > this.xmax ? 0b0010 : 0b0000)
+        | (y < this.ymin ? 0b0100
+        : y > this.ymax ? 0b1000 : 0b0000);
+  }
+  _simplify(P) {
+    if (P && P.length > 4) {
+      for (let i = 0; i < P.length; i+= 2) {
+        const j = (i + 2) % P.length, k = (i + 4) % P.length;
+        if (P[i] === P[j] && P[j] === P[k] || P[i + 1] === P[j + 1] && P[j + 1] === P[k + 1]) {
+          P.splice(j, 2), i -= 2;
+        }
+      }
+      if (!P.length) P = null;
+    }
+    return P;
+  }
+}
+
+const tau$2 = 2 * Math.PI, pow$2 = Math.pow;
+
+function pointX(p) {
+  return p[0];
+}
+
+function pointY(p) {
+  return p[1];
+}
+
+// A triangulation is collinear if all its triangles have a non-null area
+function collinear(d) {
+  const {triangles, coords} = d;
+  for (let i = 0; i < triangles.length; i += 3) {
+    const a = 2 * triangles[i],
+          b = 2 * triangles[i + 1],
+          c = 2 * triangles[i + 2],
+          cross = (coords[c] - coords[a]) * (coords[b + 1] - coords[a + 1])
+                - (coords[b] - coords[a]) * (coords[c + 1] - coords[a + 1]);
+    if (cross > 1e-10) return false;
+  }
+  return true;
+}
+
+function jitter(x, y, r) {
+  return [x + Math.sin(x + y) * r, y + Math.cos(x - y) * r];
+}
+
+class Delaunay {
+  static from(points, fx = pointX, fy = pointY, that) {
+    return new Delaunay("length" in points
+        ? flatArray(points, fx, fy, that)
+        : Float64Array.from(flatIterable(points, fx, fy, that)));
+  }
+  constructor(points) {
+    this._delaunator = new Delaunator(points);
+    this.inedges = new Int32Array(points.length / 2);
+    this._hullIndex = new Int32Array(points.length / 2);
+    this.points = this._delaunator.coords;
+    this._init();
+  }
+  update() {
+    this._delaunator.update();
+    this._init();
+    return this;
+  }
+  _init() {
+    const d = this._delaunator, points = this.points;
+
+    // check for collinear
+    if (d.hull && d.hull.length > 2 && collinear(d)) {
+      this.collinear = Int32Array.from({length: points.length/2}, (_,i) => i)
+        .sort((i, j) => points[2 * i] - points[2 * j] || points[2 * i + 1] - points[2 * j + 1]); // for exact neighbors
+      const e = this.collinear[0], f = this.collinear[this.collinear.length - 1],
+        bounds = [ points[2 * e], points[2 * e + 1], points[2 * f], points[2 * f + 1] ],
+        r = 1e-8 * Math.hypot(bounds[3] - bounds[1], bounds[2] - bounds[0]);
+      for (let i = 0, n = points.length / 2; i < n; ++i) {
+        const p = jitter(points[2 * i], points[2 * i + 1], r);
+        points[2 * i] = p[0];
+        points[2 * i + 1] = p[1];
+      }
+      this._delaunator = new Delaunator(points);
+    } else {
+      delete this.collinear;
+    }
+
+    const halfedges = this.halfedges = this._delaunator.halfedges;
+    const hull = this.hull = this._delaunator.hull;
+    const triangles = this.triangles = this._delaunator.triangles;
+    const inedges = this.inedges.fill(-1);
+    const hullIndex = this._hullIndex.fill(-1);
+
+    // Compute an index from each point to an (arbitrary) incoming halfedge
+    // Used to give the first neighbor of each point; for this reason,
+    // on the hull we give priority to exterior halfedges
+    for (let e = 0, n = halfedges.length; e < n; ++e) {
+      const p = triangles[e % 3 === 2 ? e - 2 : e + 1];
+      if (halfedges[e] === -1 || inedges[p] === -1) inedges[p] = e;
+    }
+    for (let i = 0, n = hull.length; i < n; ++i) {
+      hullIndex[hull[i]] = i;
+    }
+
+    // degenerate case: 1 or 2 (distinct) points
+    if (hull.length <= 2 && hull.length > 0) {
+      this.triangles = new Int32Array(3).fill(-1);
+      this.halfedges = new Int32Array(3).fill(-1);
+      this.triangles[0] = hull[0];
+      inedges[hull[0]] = 1;
+      if (hull.length === 2) {
+        inedges[hull[1]] = 0;
+        this.triangles[1] = hull[1];
+        this.triangles[2] = hull[1];
+      }
+    }
+  }
+  voronoi(bounds) {
+    return new Voronoi(this, bounds);
+  }
+  *neighbors(i) {
+    const {inedges, hull, _hullIndex, halfedges, triangles, collinear} = this;
+
+    // degenerate case with several collinear points
+    if (collinear) {
+      const l = collinear.indexOf(i);
+      if (l > 0) yield collinear[l - 1];
+      if (l < collinear.length - 1) yield collinear[l + 1];
+      return;
+    }
+
+    const e0 = inedges[i];
+    if (e0 === -1) return; // coincident point
+    let e = e0, p0 = -1;
+    do {
+      yield p0 = triangles[e];
+      e = e % 3 === 2 ? e - 2 : e + 1;
+      if (triangles[e] !== i) return; // bad triangulation
+      e = halfedges[e];
+      if (e === -1) {
+        const p = hull[(_hullIndex[i] + 1) % hull.length];
+        if (p !== p0) yield p;
+        return;
+      }
+    } while (e !== e0);
+  }
+  find(x, y, i = 0) {
+    if ((x = +x, x !== x) || (y = +y, y !== y)) return -1;
+    const i0 = i;
+    let c;
+    while ((c = this._step(i, x, y)) >= 0 && c !== i && c !== i0) i = c;
+    return c;
+  }
+  _step(i, x, y) {
+    const {inedges, hull, _hullIndex, halfedges, triangles, points} = this;
+    if (inedges[i] === -1 || !points.length) return (i + 1) % (points.length >> 1);
+    let c = i;
+    let dc = pow$2(x - points[i * 2], 2) + pow$2(y - points[i * 2 + 1], 2);
+    const e0 = inedges[i];
+    let e = e0;
+    do {
+      let t = triangles[e];
+      const dt = pow$2(x - points[t * 2], 2) + pow$2(y - points[t * 2 + 1], 2);
+      if (dt < dc) dc = dt, c = t;
+      e = e % 3 === 2 ? e - 2 : e + 1;
+      if (triangles[e] !== i) break; // bad triangulation
+      e = halfedges[e];
+      if (e === -1) {
+        e = hull[(_hullIndex[i] + 1) % hull.length];
+        if (e !== t) {
+          if (pow$2(x - points[e * 2], 2) + pow$2(y - points[e * 2 + 1], 2) < dc) return e;
+        }
+        break;
+      }
+    } while (e !== e0);
+    return c;
+  }
+  render(context) {
+    const buffer = context == null ? context = new Path : undefined;
+    const {points, halfedges, triangles} = this;
+    for (let i = 0, n = halfedges.length; i < n; ++i) {
+      const j = halfedges[i];
+      if (j < i) continue;
+      const ti = triangles[i] * 2;
+      const tj = triangles[j] * 2;
+      context.moveTo(points[ti], points[ti + 1]);
+      context.lineTo(points[tj], points[tj + 1]);
+    }
+    this.renderHull(context);
+    return buffer && buffer.value();
+  }
+  renderPoints(context, r) {
+    if (r === undefined && (!context || typeof context.moveTo !== "function")) r = context, context = null;
+    r = r == undefined ? 2 : +r;
+    const buffer = context == null ? context = new Path : undefined;
+    const {points} = this;
+    for (let i = 0, n = points.length; i < n; i += 2) {
+      const x = points[i], y = points[i + 1];
+      context.moveTo(x + r, y);
+      context.arc(x, y, r, 0, tau$2);
+    }
+    return buffer && buffer.value();
+  }
+  renderHull(context) {
+    const buffer = context == null ? context = new Path : undefined;
+    const {hull, points} = this;
+    const h = hull[0] * 2, n = hull.length;
+    context.moveTo(points[h], points[h + 1]);
+    for (let i = 1; i < n; ++i) {
+      const h = 2 * hull[i];
+      context.lineTo(points[h], points[h + 1]);
+    }
+    context.closePath();
+    return buffer && buffer.value();
+  }
+  hullPolygon() {
+    const polygon = new Polygon;
+    this.renderHull(polygon);
+    return polygon.value();
+  }
+  renderTriangle(i, context) {
+    const buffer = context == null ? context = new Path : undefined;
+    const {points, triangles} = this;
+    const t0 = triangles[i *= 3] * 2;
+    const t1 = triangles[i + 1] * 2;
+    const t2 = triangles[i + 2] * 2;
+    context.moveTo(points[t0], points[t0 + 1]);
+    context.lineTo(points[t1], points[t1 + 1]);
+    context.lineTo(points[t2], points[t2 + 1]);
+    context.closePath();
+    return buffer && buffer.value();
+  }
+  *trianglePolygons() {
+    const {triangles} = this;
+    for (let i = 0, n = triangles.length / 3; i < n; ++i) {
+      yield this.trianglePolygon(i);
+    }
+  }
+  trianglePolygon(i) {
+    const polygon = new Polygon;
+    this.renderTriangle(i, polygon);
+    return polygon.value();
+  }
+}
+
+function flatArray(points, fx, fy, that) {
+  const n = points.length;
+  const array = new Float64Array(n * 2);
+  for (let i = 0; i < n; ++i) {
+    const p = points[i];
+    array[i * 2] = fx.call(that, p, i, points);
+    array[i * 2 + 1] = fy.call(that, p, i, points);
+  }
+  return array;
+}
+
+function* flatIterable(points, fx, fy, that) {
+  let i = 0;
+  for (const p of points) {
+    yield fx.call(that, p, i, points);
+    yield fy.call(that, p, i, points);
+    ++i;
+  }
+}
+
 var EOL = {},
     EOF = {},
     QUOTE = 34,
@@ -5924,15 +8151,15 @@
   return columns;
 }
 
-function pad(value, width) {
+function pad$1(value, width) {
   var s = value + "", length = s.length;
   return length < width ? new Array(width - length + 1).join(0) + s : s;
 }
 
-function formatYear(year) {
-  return year < 0 ? "-" + pad(-year, 6)
-    : year > 9999 ? "+" + pad(year, 6)
-    : pad(year, 4);
+function formatYear$1(year) {
+  return year < 0 ? "-" + pad$1(-year, 6)
+    : year > 9999 ? "+" + pad$1(year, 6)
+    : pad$1(year, 4);
 }
 
 function formatDate(date) {
@@ -5941,10 +8168,10 @@
       seconds = date.getUTCSeconds(),
       milliseconds = date.getUTCMilliseconds();
   return isNaN(date) ? "Invalid Date"
-      : formatYear(date.getUTCFullYear()) + "-" + pad(date.getUTCMonth() + 1, 2) + "-" + pad(date.getUTCDate(), 2)
-      + (milliseconds ? "T" + pad(hours, 2) + ":" + pad(minutes, 2) + ":" + pad(seconds, 2) + "." + pad(milliseconds, 3) + "Z"
-      : seconds ? "T" + pad(hours, 2) + ":" + pad(minutes, 2) + ":" + pad(seconds, 2) + "Z"
-      : minutes || hours ? "T" + pad(hours, 2) + ":" + pad(minutes, 2) + "Z"
+      : formatYear$1(date.getUTCFullYear()) + "-" + pad$1(date.getUTCMonth() + 1, 2) + "-" + pad$1(date.getUTCDate(), 2)
+      + (milliseconds ? "T" + pad$1(hours, 2) + ":" + pad$1(minutes, 2) + ":" + pad$1(seconds, 2) + "." + pad$1(milliseconds, 3) + "Z"
+      : seconds ? "T" + pad$1(hours, 2) + ":" + pad$1(minutes, 2) + ":" + pad$1(seconds, 2) + "Z"
+      : minutes || hours ? "T" + pad$1(hours, 2) + ":" + pad$1(minutes, 2) + "Z"
       : "");
 }
 
@@ -6054,25 +8281,25 @@
   };
 }
 
-var csv = dsvFormat(",");
+var csv$1 = dsvFormat(",");
 
-var csvParse = csv.parse;
-var csvParseRows = csv.parseRows;
-var csvFormat = csv.format;
-var csvFormatBody = csv.formatBody;
-var csvFormatRows = csv.formatRows;
-var csvFormatRow = csv.formatRow;
-var csvFormatValue = csv.formatValue;
+var csvParse = csv$1.parse;
+var csvParseRows = csv$1.parseRows;
+var csvFormat = csv$1.format;
+var csvFormatBody = csv$1.formatBody;
+var csvFormatRows = csv$1.formatRows;
+var csvFormatRow = csv$1.formatRow;
+var csvFormatValue = csv$1.formatValue;
 
-var tsv = dsvFormat("\t");
+var tsv$1 = dsvFormat("\t");
 
-var tsvParse = tsv.parse;
-var tsvParseRows = tsv.parseRows;
-var tsvFormat = tsv.format;
-var tsvFormatBody = tsv.formatBody;
-var tsvFormatRows = tsv.formatRows;
-var tsvFormatRow = tsv.formatRow;
-var tsvFormatValue = tsv.formatValue;
+var tsvParse = tsv$1.parse;
+var tsvParseRows = tsv$1.parseRows;
+var tsvFormat = tsv$1.format;
+var tsvFormatBody = tsv$1.formatBody;
+var tsvFormatRows = tsv$1.formatRows;
+var tsvFormatRow = tsv$1.formatRow;
+var tsvFormatValue = tsv$1.formatValue;
 
 function autoType(object) {
   for (var key in object) {
@@ -6093,7 +8320,7 @@
 }
 
 // https://github.com/d3/d3-dsv/issues/45
-var fixtz = new Date("2019-01-01T00:00").getHours() || new Date("2019-07-01T00:00").getHours();
+const fixtz = new Date("2019-01-01T00:00").getHours() || new Date("2019-07-01T00:00").getHours();
 
 function responseBlob(response) {
   if (!response.ok) throw new Error(response.status + " " + response.statusText);
@@ -6139,8 +8366,8 @@
   });
 }
 
-var csv$1 = dsvParse(csvParse);
-var tsv$1 = dsvParse(tsvParse);
+var csv = dsvParse(csvParse);
+var tsv = dsvParse(tsvParse);
 
 function image(input, init) {
   return new Promise(function(resolve, reject) {
@@ -6154,6 +8381,7 @@
 
 function responseJson(response) {
   if (!response.ok) throw new Error(response.status + " " + response.statusText);
+  if (response.status === 204 || response.status === 205) return;
   return response.json();
 }
 
@@ -6162,11 +8390,8 @@
 }
 
 function parser(type) {
-  return function(input, init)  {
-    return text(input, init).then(function(text) {
-      return (new DOMParser).parseFromString(text, type);
-    });
-  };
+  return (input, init) => text(input, init)
+    .then(text => (new DOMParser).parseFromString(text, type));
 }
 
 var xml = parser("application/xml");
@@ -6175,8 +8400,8 @@
 
 var svg = parser("image/svg+xml");
 
-function center$1(x, y) {
-  var nodes;
+function center(x, y) {
+  var nodes, strength = 1;
 
   if (x == null) x = 0;
   if (y == null) y = 0;
@@ -6192,7 +8417,7 @@
       node = nodes[i], sx += node.x, sy += node.y;
     }
 
-    for (sx = sx / n - x, sy = sy / n - y, i = 0; i < n; ++i) {
+    for (sx = (sx / n - x) * strength, sy = (sy / n - y) * strength, i = 0; i < n; ++i) {
       node = nodes[i], node.x -= sx, node.y -= sy;
     }
   }
@@ -6209,21 +8434,15 @@
     return arguments.length ? (y = +_, force) : y;
   };
 
+  force.strength = function(_) {
+    return arguments.length ? (strength = +_, force) : strength;
+  };
+
   return force;
 }
 
-function constant$7(x) {
-  return function() {
-    return x;
-  };
-}
-
-function jiggle() {
-  return (Math.random() - 0.5) * 1e-6;
-}
-
 function tree_add(d) {
-  var x = +this._x.call(null, d),
+  const x = +this._x.call(null, d),
       y = +this._y.call(null, d);
   return add(this.cover(x, y), x, y, d);
 }
@@ -6325,7 +8544,7 @@
 
   // Otherwise, double repeatedly to cover.
   else {
-    var z = x1 - x0,
+    var z = x1 - x0 || 1,
         node = this._root,
         parent,
         i;
@@ -6552,7 +8771,7 @@
   return this;
 }
 
-function defaultX$1(d) {
+function defaultX(d) {
   return d[0];
 }
 
@@ -6560,7 +8779,7 @@
   return arguments.length ? (this._x = _, this) : this._x;
 }
 
-function defaultY$1(d) {
+function defaultY(d) {
   return d[1];
 }
 
@@ -6569,7 +8788,7 @@
 }
 
 function quadtree(nodes, x, y) {
-  var tree = new Quadtree(x == null ? defaultX$1 : x, y == null ? defaultY$1 : y, NaN, NaN, NaN, NaN);
+  var tree = new Quadtree(x == null ? defaultX : x, y == null ? defaultY : y, NaN, NaN, NaN, NaN);
   return nodes == null ? tree : tree.addAll(nodes);
 }
 
@@ -6629,21 +8848,32 @@
 treeProto.x = tree_x;
 treeProto.y = tree_y;
 
-function x(d) {
+function constant$4(x) {
+  return function() {
+    return x;
+  };
+}
+
+function jiggle(random) {
+  return (random() - 0.5) * 1e-6;
+}
+
+function x$3(d) {
   return d.x + d.vx;
 }
 
-function y(d) {
+function y$3(d) {
   return d.y + d.vy;
 }
 
 function collide(radius) {
   var nodes,
       radii,
+      random,
       strength = 1,
       iterations = 1;
 
-  if (typeof radius !== "function") radius = constant$7(radius == null ? 1 : +radius);
+  if (typeof radius !== "function") radius = constant$4(radius == null ? 1 : +radius);
 
   function force() {
     var i, n = nodes.length,
@@ -6655,7 +8885,7 @@
         ri2;
 
     for (var k = 0; k < iterations; ++k) {
-      tree = quadtree(nodes, x, y).visitAfter(prepare);
+      tree = quadtree(nodes, x$3, y$3).visitAfter(prepare);
       for (i = 0; i < n; ++i) {
         node = nodes[i];
         ri = radii[node.index], ri2 = ri * ri;
@@ -6673,8 +8903,8 @@
               y = yi - data.y - data.vy,
               l = x * x + y * y;
           if (l < r * r) {
-            if (x === 0) x = jiggle(), l += x * x;
-            if (y === 0) y = jiggle(), l += y * y;
+            if (x === 0) x = jiggle(random), l += x * x;
+            if (y === 0) y = jiggle(random), l += y * y;
             l = (r - (l = Math.sqrt(l))) / l * strength;
             node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj));
             node.vy += (y *= l) * r;
@@ -6704,8 +8934,9 @@
     for (i = 0; i < n; ++i) node = nodes[i], radii[node.index] = +radius(node, i, nodes);
   }
 
-  force.initialize = function(_) {
-    nodes = _;
+  force.initialize = function(_nodes, _random) {
+    nodes = _nodes;
+    random = _random;
     initialize();
   };
 
@@ -6718,31 +8949,32 @@
   };
 
   force.radius = function(_) {
-    return arguments.length ? (radius = typeof _ === "function" ? _ : constant$7(+_), initialize(), force) : radius;
+    return arguments.length ? (radius = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : radius;
   };
 
   return force;
 }
 
-function index(d) {
+function index$3(d) {
   return d.index;
 }
 
 function find(nodeById, nodeId) {
   var node = nodeById.get(nodeId);
-  if (!node) throw new Error("missing: " + nodeId);
+  if (!node) throw new Error("node not found: " + nodeId);
   return node;
 }
 
-function link(links) {
-  var id = index,
+function link$2(links) {
+  var id = index$3,
       strength = defaultStrength,
       strengths,
-      distance = constant$7(30),
+      distance = constant$4(30),
       distances,
       nodes,
       count,
       bias,
+      random,
       iterations = 1;
 
   if (links == null) links = [];
@@ -6755,8 +8987,8 @@
     for (var k = 0, n = links.length; k < iterations; ++k) {
       for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) {
         link = links[i], source = link.source, target = link.target;
-        x = target.x + target.vx - source.x - source.vx || jiggle();
-        y = target.y + target.vy - source.y - source.vy || jiggle();
+        x = target.x + target.vx - source.x - source.vx || jiggle(random);
+        y = target.y + target.vy - source.y - source.vy || jiggle(random);
         l = Math.sqrt(x * x + y * y);
         l = (l - distances[i]) / l * alpha * strengths[i];
         x *= l, y *= l;
@@ -6774,7 +9006,7 @@
     var i,
         n = nodes.length,
         m = links.length,
-        nodeById = map$1(nodes, id),
+        nodeById = new Map(nodes.map((d, i) => [id(d, i, nodes), d])),
         link;
 
     for (i = 0, count = new Array(n); i < m; ++i) {
@@ -6809,8 +9041,9 @@
     }
   }
 
-  force.initialize = function(_) {
-    nodes = _;
+  force.initialize = function(_nodes, _random) {
+    nodes = _nodes;
+    random = _random;
     initialize();
   };
 
@@ -6827,21 +9060,31 @@
   };
 
   force.strength = function(_) {
-    return arguments.length ? (strength = typeof _ === "function" ? _ : constant$7(+_), initializeStrength(), force) : strength;
+    return arguments.length ? (strength = typeof _ === "function" ? _ : constant$4(+_), initializeStrength(), force) : strength;
   };
 
   force.distance = function(_) {
-    return arguments.length ? (distance = typeof _ === "function" ? _ : constant$7(+_), initializeDistance(), force) : distance;
+    return arguments.length ? (distance = typeof _ === "function" ? _ : constant$4(+_), initializeDistance(), force) : distance;
   };
 
   return force;
 }
 
-function x$1(d) {
+// https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use
+const a$2 = 1664525;
+const c$4 = 1013904223;
+const m$1 = 4294967296; // 2^32
+
+function lcg$2() {
+  let s = 1;
+  return () => (s = (a$2 * s + c$4) % m$1) / m$1;
+}
+
+function x$2(d) {
   return d.x;
 }
 
-function y$1(d) {
+function y$2(d) {
   return d.y;
 }
 
@@ -6855,9 +9098,10 @@
       alphaDecay = 1 - Math.pow(alphaMin, 1 / 300),
       alphaTarget = 0,
       velocityDecay = 0.6,
-      forces = map$1(),
+      forces = new Map(),
       stepper = timer(step),
-      event = dispatch("tick", "end");
+      event = dispatch("tick", "end"),
+      random = lcg$2();
 
   if (nodes == null) nodes = [];
 
@@ -6878,7 +9122,7 @@
     for (var k = 0; k < iterations; ++k) {
       alpha += (alphaTarget - alpha) * alphaDecay;
 
-      forces.each(function (force) {
+      forces.forEach(function(force) {
         force(alpha);
       });
 
@@ -6900,7 +9144,7 @@
       if (node.fx != null) node.x = node.fx;
       if (node.fy != null) node.y = node.fy;
       if (isNaN(node.x) || isNaN(node.y)) {
-        var radius = initialRadius * Math.sqrt(i), angle = i * initialAngle;
+        var radius = initialRadius * Math.sqrt(0.5 + i), angle = i * initialAngle;
         node.x = radius * Math.cos(angle);
         node.y = radius * Math.sin(angle);
       }
@@ -6911,7 +9155,7 @@
   }
 
   function initializeForce(force) {
-    if (force.initialize) force.initialize(nodes);
+    if (force.initialize) force.initialize(nodes, random);
     return force;
   }
 
@@ -6929,7 +9173,7 @@
     },
 
     nodes: function(_) {
-      return arguments.length ? (nodes = _, initializeNodes(), forces.each(initializeForce), simulation) : nodes;
+      return arguments.length ? (nodes = _, initializeNodes(), forces.forEach(initializeForce), simulation) : nodes;
     },
 
     alpha: function(_) {
@@ -6952,8 +9196,12 @@
       return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay;
     },
 
+    randomSource: function(_) {
+      return arguments.length ? (random = _, forces.forEach(initializeForce), simulation) : random;
+    },
+
     force: function(name, _) {
-      return arguments.length > 1 ? ((_ == null ? forces.remove(name) : forces.set(name, initializeForce(_))), simulation) : forces.get(name);
+      return arguments.length > 1 ? ((_ == null ? forces.delete(name) : forces.set(name, initializeForce(_))), simulation) : forces.get(name);
     },
 
     find: function(x, y, radius) {
@@ -6988,15 +9236,16 @@
 function manyBody() {
   var nodes,
       node,
+      random,
       alpha,
-      strength = constant$7(-30),
+      strength = constant$4(-30),
       strengths,
       distanceMin2 = 1,
       distanceMax2 = Infinity,
       theta2 = 0.81;
 
   function force(_) {
-    var i, n = nodes.length, tree = quadtree(nodes, x$1, y$1).visitAfter(accumulate);
+    var i, n = nodes.length, tree = quadtree(nodes, x$2, y$2).visitAfter(accumulate);
     for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply);
   }
 
@@ -7045,8 +9294,8 @@
     // Limit forces for very close nodes; randomize direction if coincident.
     if (w * w / theta2 < l) {
       if (l < distanceMax2) {
-        if (x === 0) x = jiggle(), l += x * x;
-        if (y === 0) y = jiggle(), l += y * y;
+        if (x === 0) x = jiggle(random), l += x * x;
+        if (y === 0) y = jiggle(random), l += y * y;
         if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
         node.vx += x * quad.value * alpha / l;
         node.vy += y * quad.value * alpha / l;
@@ -7059,8 +9308,8 @@
 
     // Limit forces for very close nodes; randomize direction if coincident.
     if (quad.data !== node || quad.next) {
-      if (x === 0) x = jiggle(), l += x * x;
-      if (y === 0) y = jiggle(), l += y * y;
+      if (x === 0) x = jiggle(random), l += x * x;
+      if (y === 0) y = jiggle(random), l += y * y;
       if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
     }
 
@@ -7071,13 +9320,14 @@
     } while (quad = quad.next);
   }
 
-  force.initialize = function(_) {
-    nodes = _;
+  force.initialize = function(_nodes, _random) {
+    nodes = _nodes;
+    random = _random;
     initialize();
   };
 
   force.strength = function(_) {
-    return arguments.length ? (strength = typeof _ === "function" ? _ : constant$7(+_), initialize(), force) : strength;
+    return arguments.length ? (strength = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : strength;
   };
 
   force.distanceMin = function(_) {
@@ -7095,13 +9345,13 @@
   return force;
 }
 
-function radial(radius, x, y) {
+function radial$1(radius, x, y) {
   var nodes,
-      strength = constant$7(0.1),
+      strength = constant$4(0.1),
       strengths,
       radiuses;
 
-  if (typeof radius !== "function") radius = constant$7(+radius);
+  if (typeof radius !== "function") radius = constant$4(+radius);
   if (x == null) x = 0;
   if (y == null) y = 0;
 
@@ -7133,11 +9383,11 @@
   };
 
   force.strength = function(_) {
-    return arguments.length ? (strength = typeof _ === "function" ? _ : constant$7(+_), initialize(), force) : strength;
+    return arguments.length ? (strength = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : strength;
   };
 
   force.radius = function(_) {
-    return arguments.length ? (radius = typeof _ === "function" ? _ : constant$7(+_), initialize(), force) : radius;
+    return arguments.length ? (radius = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : radius;
   };
 
   force.x = function(_) {
@@ -7151,13 +9401,13 @@
   return force;
 }
 
-function x$2(x) {
-  var strength = constant$7(0.1),
+function x$1(x) {
+  var strength = constant$4(0.1),
       nodes,
       strengths,
       xz;
 
-  if (typeof x !== "function") x = constant$7(x == null ? 0 : +x);
+  if (typeof x !== "function") x = constant$4(x == null ? 0 : +x);
 
   function force(alpha) {
     for (var i = 0, n = nodes.length, node; i < n; ++i) {
@@ -7181,23 +9431,23 @@
   };
 
   force.strength = function(_) {
-    return arguments.length ? (strength = typeof _ === "function" ? _ : constant$7(+_), initialize(), force) : strength;
+    return arguments.length ? (strength = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : strength;
   };
 
   force.x = function(_) {
-    return arguments.length ? (x = typeof _ === "function" ? _ : constant$7(+_), initialize(), force) : x;
+    return arguments.length ? (x = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : x;
   };
 
   return force;
 }
 
-function y$2(y) {
-  var strength = constant$7(0.1),
+function y$1(y) {
+  var strength = constant$4(0.1),
       nodes,
       strengths,
       yz;
 
-  if (typeof y !== "function") y = constant$7(y == null ? 0 : +y);
+  if (typeof y !== "function") y = constant$4(y == null ? 0 : +y);
 
   function force(alpha) {
     for (var i = 0, n = nodes.length, node; i < n; ++i) {
@@ -7221,20 +9471,26 @@
   };
 
   force.strength = function(_) {
-    return arguments.length ? (strength = typeof _ === "function" ? _ : constant$7(+_), initialize(), force) : strength;
+    return arguments.length ? (strength = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : strength;
   };
 
   force.y = function(_) {
-    return arguments.length ? (y = typeof _ === "function" ? _ : constant$7(+_), initialize(), force) : y;
+    return arguments.length ? (y = typeof _ === "function" ? _ : constant$4(+_), initialize(), force) : y;
   };
 
   return force;
 }
 
+function formatDecimal(x) {
+  return Math.abs(x = Math.round(x)) >= 1e21
+      ? x.toLocaleString("en").replace(/,/g, "")
+      : x.toString(10);
+}
+
 // Computes the decimal coefficient and exponent of the specified number x with
 // significant digits p, where x is positive and p is in [1, 21] or undefined.
-// For example, formatDecimal(1.23) returns ["123", 0].
-function formatDecimal(x, p) {
+// For example, formatDecimalParts(1.23) returns ["123", 0].
+function formatDecimalParts(x, p) {
   if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
   var i, coefficient = x.slice(0, i);
 
@@ -7246,8 +9502,8 @@
   ];
 }
 
-function exponent$1(x) {
-  return x = formatDecimal(Math.abs(x)), x ? x[1] : NaN;
+function exponent(x) {
+  return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;
 }
 
 function formatGroup(grouping, thousands) {
@@ -7340,7 +9596,7 @@
 var prefixExponent;
 
 function formatPrefixAuto(x, p) {
-  var d = formatDecimal(x, p);
+  var d = formatDecimalParts(x, p);
   if (!d) return x + "";
   var coefficient = d[0],
       exponent = d[1],
@@ -7349,11 +9605,11 @@
   return i === n ? coefficient
       : i > n ? coefficient + new Array(i - n + 1).join("0")
       : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i)
-      : "0." + new Array(1 - i).join("0") + formatDecimal(x, Math.max(0, p + i - 1))[0]; // less than 1y!
+      : "0." + new Array(1 - i).join("0") + formatDecimalParts(x, Math.max(0, p + i - 1))[0]; // less than 1y!
 }
 
 function formatRounded(x, p) {
-  var d = formatDecimal(x, p);
+  var d = formatDecimalParts(x, p);
   if (!d) return x + "";
   var coefficient = d[0],
       exponent = d[1];
@@ -7363,36 +9619,36 @@
 }
 
 var formatTypes = {
-  "%": function(x, p) { return (x * 100).toFixed(p); },
-  "b": function(x) { return Math.round(x).toString(2); },
-  "c": function(x) { return x + ""; },
-  "d": function(x) { return Math.round(x).toString(10); },
-  "e": function(x, p) { return x.toExponential(p); },
-  "f": function(x, p) { return x.toFixed(p); },
-  "g": function(x, p) { return x.toPrecision(p); },
-  "o": function(x) { return Math.round(x).toString(8); },
-  "p": function(x, p) { return formatRounded(x * 100, p); },
+  "%": (x, p) => (x * 100).toFixed(p),
+  "b": (x) => Math.round(x).toString(2),
+  "c": (x) => x + "",
+  "d": formatDecimal,
+  "e": (x, p) => x.toExponential(p),
+  "f": (x, p) => x.toFixed(p),
+  "g": (x, p) => x.toPrecision(p),
+  "o": (x) => Math.round(x).toString(8),
+  "p": (x, p) => formatRounded(x * 100, p),
   "r": formatRounded,
   "s": formatPrefixAuto,
-  "X": function(x) { return Math.round(x).toString(16).toUpperCase(); },
-  "x": function(x) { return Math.round(x).toString(16); }
+  "X": (x) => Math.round(x).toString(16).toUpperCase(),
+  "x": (x) => Math.round(x).toString(16)
 };
 
-function identity$3(x) {
+function identity$6(x) {
   return x;
 }
 
-var map$2 = Array.prototype.map,
-    prefixes = ["y","z","a","f","p","n","\xB5","m","","k","M","G","T","P","E","Z","Y"];
+var map = Array.prototype.map,
+    prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];
 
-function formatLocale(locale) {
-  var group = locale.grouping === undefined || locale.thousands === undefined ? identity$3 : formatGroup(map$2.call(locale.grouping, Number), locale.thousands + ""),
+function formatLocale$1(locale) {
+  var group = locale.grouping === undefined || locale.thousands === undefined ? identity$6 : formatGroup(map.call(locale.grouping, Number), locale.thousands + ""),
       currencyPrefix = locale.currency === undefined ? "" : locale.currency[0] + "",
       currencySuffix = locale.currency === undefined ? "" : locale.currency[1] + "",
       decimal = locale.decimal === undefined ? "." : locale.decimal + "",
-      numerals = locale.numerals === undefined ? identity$3 : formatNumerals(map$2.call(locale.numerals, String)),
+      numerals = locale.numerals === undefined ? identity$6 : formatNumerals(map.call(locale.numerals, String)),
       percent = locale.percent === undefined ? "%" : locale.percent + "",
-      minus = locale.minus === undefined ? "-" : locale.minus + "",
+      minus = locale.minus === undefined ? "−" : locale.minus + "",
       nan = locale.nan === undefined ? "NaN" : locale.nan + "";
 
   function newFormat(specifier) {
@@ -7508,7 +9764,7 @@
 
   function formatPrefix(specifier, value) {
     var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
-        e = Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3,
+        e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
         k = Math.pow(10, -e),
         prefix = prefixes[8 + e / 3];
     return function(value) {
@@ -7522,113 +9778,73 @@
   };
 }
 
-var locale;
+var locale$1;
+exports.format = void 0;
+exports.formatPrefix = void 0;
 
-defaultLocale({
-  decimal: ".",
+defaultLocale$1({
   thousands: ",",
   grouping: [3],
-  currency: ["$", ""],
-  minus: "-"
+  currency: ["$", ""]
 });
 
-function defaultLocale(definition) {
-  locale = formatLocale(definition);
-  exports.format = locale.format;
-  exports.formatPrefix = locale.formatPrefix;
-  return locale;
+function defaultLocale$1(definition) {
+  locale$1 = formatLocale$1(definition);
+  exports.format = locale$1.format;
+  exports.formatPrefix = locale$1.formatPrefix;
+  return locale$1;
 }
 
 function precisionFixed(step) {
-  return Math.max(0, -exponent$1(Math.abs(step)));
+  return Math.max(0, -exponent(Math.abs(step)));
 }
 
 function precisionPrefix(step, value) {
-  return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3 - exponent$1(Math.abs(step)));
+  return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));
 }
 
 function precisionRound(step, max) {
   step = Math.abs(step), max = Math.abs(max) - step;
-  return Math.max(0, exponent$1(max) - exponent$1(step)) + 1;
+  return Math.max(0, exponent(max) - exponent(step)) + 1;
 }
 
-// Adds floating point numbers with twice the normal precision.
-// Reference: J. R. Shewchuk, Adaptive Precision Floating-Point Arithmetic and
-// Fast Robust Geometric Predicates, Discrete & Computational Geometry 18(3)
-// 305–363 (1997).
-// Code adapted from GeographicLib by Charles F. F. Karney,
-// http://geographiclib.sourceforge.net/
+var epsilon$1 = 1e-6;
+var epsilon2 = 1e-12;
+var pi$1 = Math.PI;
+var halfPi$1 = pi$1 / 2;
+var quarterPi = pi$1 / 4;
+var tau$1 = pi$1 * 2;
 
-function adder() {
-  return new Adder;
-}
+var degrees = 180 / pi$1;
+var radians = pi$1 / 180;
 
-function Adder() {
-  this.reset();
-}
-
-Adder.prototype = {
-  constructor: Adder,
-  reset: function() {
-    this.s = // rounded value
-    this.t = 0; // exact error
-  },
-  add: function(y) {
-    add$1(temp, y, this.t);
-    add$1(this, temp.s, this.s);
-    if (this.s) this.t += temp.t;
-    else this.s = temp.t;
-  },
-  valueOf: function() {
-    return this.s;
-  }
-};
-
-var temp = new Adder;
-
-function add$1(adder, a, b) {
-  var x = adder.s = a + b,
-      bv = x - a,
-      av = x - bv;
-  adder.t = (a - av) + (b - bv);
-}
-
-var epsilon$2 = 1e-6;
-var epsilon2$1 = 1e-12;
-var pi$3 = Math.PI;
-var halfPi$2 = pi$3 / 2;
-var quarterPi = pi$3 / 4;
-var tau$3 = pi$3 * 2;
-
-var degrees$1 = 180 / pi$3;
-var radians = pi$3 / 180;
-
-var abs = Math.abs;
+var abs$1 = Math.abs;
 var atan = Math.atan;
-var atan2 = Math.atan2;
+var atan2$1 = Math.atan2;
 var cos$1 = Math.cos;
 var ceil = Math.ceil;
 var exp = Math.exp;
-var log = Math.log;
-var pow = Math.pow;
+var hypot = Math.hypot;
+var log$1 = Math.log;
+var pow$1 = Math.pow;
 var sin$1 = Math.sin;
-var sign = Math.sign || function(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; };
-var sqrt = Math.sqrt;
+var sign$1 = Math.sign || function(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; };
+var sqrt$2 = Math.sqrt;
 var tan = Math.tan;
 
-function acos(x) {
-  return x > 1 ? 0 : x < -1 ? pi$3 : Math.acos(x);
+function acos$1(x) {
+  return x > 1 ? 0 : x < -1 ? pi$1 : Math.acos(x);
 }
 
-function asin(x) {
-  return x > 1 ? halfPi$2 : x < -1 ? -halfPi$2 : Math.asin(x);
+function asin$1(x) {
+  return x > 1 ? halfPi$1 : x < -1 ? -halfPi$1 : Math.asin(x);
 }
 
 function haversin(x) {
   return (x = sin$1(x / 2)) * x;
 }
 
-function noop$2() {}
+function noop$1() {}
 
 function streamGeometry(geometry, stream) {
   if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
@@ -7700,78 +9916,80 @@
   }
 }
 
-var areaRingSum = adder();
+var areaRingSum$1 = new Adder();
 
-var areaSum = adder(),
-    lambda00,
-    phi00,
-    lambda0,
-    cosPhi0,
-    sinPhi0;
+// hello?
 
-var areaStream = {
-  point: noop$2,
-  lineStart: noop$2,
-  lineEnd: noop$2,
+var areaSum$1 = new Adder(),
+    lambda00$2,
+    phi00$2,
+    lambda0$2,
+    cosPhi0$1,
+    sinPhi0$1;
+
+var areaStream$1 = {
+  point: noop$1,
+  lineStart: noop$1,
+  lineEnd: noop$1,
   polygonStart: function() {
-    areaRingSum.reset();
-    areaStream.lineStart = areaRingStart;
-    areaStream.lineEnd = areaRingEnd;
+    areaRingSum$1 = new Adder();
+    areaStream$1.lineStart = areaRingStart$1;
+    areaStream$1.lineEnd = areaRingEnd$1;
   },
   polygonEnd: function() {
-    var areaRing = +areaRingSum;
-    areaSum.add(areaRing < 0 ? tau$3 + areaRing : areaRing);
-    this.lineStart = this.lineEnd = this.point = noop$2;
+    var areaRing = +areaRingSum$1;
+    areaSum$1.add(areaRing < 0 ? tau$1 + areaRing : areaRing);
+    this.lineStart = this.lineEnd = this.point = noop$1;
   },
   sphere: function() {
-    areaSum.add(tau$3);
+    areaSum$1.add(tau$1);
   }
 };
 
-function areaRingStart() {
-  areaStream.point = areaPointFirst;
+function areaRingStart$1() {
+  areaStream$1.point = areaPointFirst$1;
 }
 
-function areaRingEnd() {
-  areaPoint(lambda00, phi00);
+function areaRingEnd$1() {
+  areaPoint$1(lambda00$2, phi00$2);
 }
 
-function areaPointFirst(lambda, phi) {
-  areaStream.point = areaPoint;
-  lambda00 = lambda, phi00 = phi;
+function areaPointFirst$1(lambda, phi) {
+  areaStream$1.point = areaPoint$1;
+  lambda00$2 = lambda, phi00$2 = phi;
   lambda *= radians, phi *= radians;
-  lambda0 = lambda, cosPhi0 = cos$1(phi = phi / 2 + quarterPi), sinPhi0 = sin$1(phi);
+  lambda0$2 = lambda, cosPhi0$1 = cos$1(phi = phi / 2 + quarterPi), sinPhi0$1 = sin$1(phi);
 }
 
-function areaPoint(lambda, phi) {
+function areaPoint$1(lambda, phi) {
   lambda *= radians, phi *= radians;
   phi = phi / 2 + quarterPi; // half the angular distance from south pole
 
   // Spherical excess E for a spherical triangle with vertices: south pole,
   // previous point, current point.  Uses a formula derived from Cagnoli’s
   // theorem.  See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
-  var dLambda = lambda - lambda0,
+  var dLambda = lambda - lambda0$2,
       sdLambda = dLambda >= 0 ? 1 : -1,
       adLambda = sdLambda * dLambda,
       cosPhi = cos$1(phi),
       sinPhi = sin$1(phi),
-      k = sinPhi0 * sinPhi,
-      u = cosPhi0 * cosPhi + k * cos$1(adLambda),
+      k = sinPhi0$1 * sinPhi,
+      u = cosPhi0$1 * cosPhi + k * cos$1(adLambda),
       v = k * sdLambda * sin$1(adLambda);
-  areaRingSum.add(atan2(v, u));
+  areaRingSum$1.add(atan2$1(v, u));
 
   // Advance the previous points.
-  lambda0 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
+  lambda0$2 = lambda, cosPhi0$1 = cosPhi, sinPhi0$1 = sinPhi;
 }
 
-function area$1(object) {
-  areaSum.reset();
-  geoStream(object, areaStream);
-  return areaSum * 2;
+function area$2(object) {
+  areaSum$1 = new Adder();
+  geoStream(object, areaStream$1);
+  return areaSum$1 * 2;
 }
 
 function spherical(cartesian) {
-  return [atan2(cartesian[1], cartesian[0]), asin(cartesian[2])];
+  return [atan2$1(cartesian[1], cartesian[0]), asin$1(cartesian[2])];
 }
 
 function cartesian(spherical) {
@@ -7798,7 +10016,7 @@
 
 // TODO return d
 function cartesianNormalizeInPlace(d) {
-  var l = sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
+  var l = sqrt$2(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
   d[0] /= l, d[1] /= l, d[2] /= l;
 }
 
@@ -7806,29 +10024,29 @@
     lambda2, // previous lambda-coordinate
     lambda00$1, phi00$1, // first point
     p0, // previous 3D point
-    deltaSum = adder(),
+    deltaSum,
     ranges,
     range;
 
-var boundsStream = {
-  point: boundsPoint,
+var boundsStream$2 = {
+  point: boundsPoint$1,
   lineStart: boundsLineStart,
   lineEnd: boundsLineEnd,
   polygonStart: function() {
-    boundsStream.point = boundsRingPoint;
-    boundsStream.lineStart = boundsRingStart;
-    boundsStream.lineEnd = boundsRingEnd;
-    deltaSum.reset();
-    areaStream.polygonStart();
+    boundsStream$2.point = boundsRingPoint;
+    boundsStream$2.lineStart = boundsRingStart;
+    boundsStream$2.lineEnd = boundsRingEnd;
+    deltaSum = new Adder();
+    areaStream$1.polygonStart();
   },
   polygonEnd: function() {
-    areaStream.polygonEnd();
-    boundsStream.point = boundsPoint;
-    boundsStream.lineStart = boundsLineStart;
-    boundsStream.lineEnd = boundsLineEnd;
-    if (areaRingSum < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
-    else if (deltaSum > epsilon$2) phi1 = 90;
-    else if (deltaSum < -epsilon$2) phi0 = -90;
+    areaStream$1.polygonEnd();
+    boundsStream$2.point = boundsPoint$1;
+    boundsStream$2.lineStart = boundsLineStart;
+    boundsStream$2.lineEnd = boundsLineEnd;
+    if (areaRingSum$1 < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
+    else if (deltaSum > epsilon$1) phi1 = 90;
+    else if (deltaSum < -epsilon$1) phi0 = -90;
     range[0] = lambda0$1, range[1] = lambda1;
   },
   sphere: function() {
@@ -7836,7 +10054,7 @@
   }
 };
 
-function boundsPoint(lambda, phi) {
+function boundsPoint$1(lambda, phi) {
   ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
   if (phi < phi0) phi0 = phi;
   if (phi > phi1) phi1 = phi;
@@ -7852,14 +10070,14 @@
     inflection = spherical(inflection);
     var delta = lambda - lambda2,
         sign = delta > 0 ? 1 : -1,
-        lambdai = inflection[0] * degrees$1 * sign,
+        lambdai = inflection[0] * degrees * sign,
         phii,
-        antimeridian = abs(delta) > 180;
+        antimeridian = abs$1(delta) > 180;
     if (antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
-      phii = inflection[1] * degrees$1;
+      phii = inflection[1] * degrees;
       if (phii > phi1) phi1 = phii;
     } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
-      phii = -inflection[1] * degrees$1;
+      phii = -inflection[1] * degrees;
       if (phii < phi0) phi0 = phii;
     } else {
       if (phi < phi0) phi0 = phi;
@@ -7892,34 +10110,34 @@
 }
 
 function boundsLineStart() {
-  boundsStream.point = linePoint;
+  boundsStream$2.point = linePoint;
 }
 
 function boundsLineEnd() {
   range[0] = lambda0$1, range[1] = lambda1;
-  boundsStream.point = boundsPoint;
+  boundsStream$2.point = boundsPoint$1;
   p0 = null;
 }
 
 function boundsRingPoint(lambda, phi) {
   if (p0) {
     var delta = lambda - lambda2;
-    deltaSum.add(abs(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
+    deltaSum.add(abs$1(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
   } else {
     lambda00$1 = lambda, phi00$1 = phi;
   }
-  areaStream.point(lambda, phi);
+  areaStream$1.point(lambda, phi);
   linePoint(lambda, phi);
 }
 
 function boundsRingStart() {
-  areaStream.lineStart();
+  areaStream$1.lineStart();
 }
 
 function boundsRingEnd() {
   boundsRingPoint(lambda00$1, phi00$1);
-  areaStream.lineEnd();
-  if (abs(deltaSum) > epsilon$2) lambda0$1 = -(lambda1 = 180);
+  areaStream$1.lineEnd();
+  if (abs$1(deltaSum) > epsilon$1) lambda0$1 = -(lambda1 = 180);
   range[0] = lambda0$1, range[1] = lambda1;
   p0 = null;
 }
@@ -7944,7 +10162,7 @@
 
   phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
   ranges = [];
-  geoStream(feature, boundsStream);
+  geoStream(feature, boundsStream$2);
 
   // First, sort ranges by their minimum longitudes.
   if (n = ranges.length) {
@@ -7977,29 +10195,29 @@
 }
 
 var W0, W1,
-    X0, Y0, Z0,
-    X1, Y1, Z1,
-    X2, Y2, Z2,
-    lambda00$2, phi00$2, // first point
-    x0, y0, z0; // previous point
+    X0$1, Y0$1, Z0$1,
+    X1$1, Y1$1, Z1$1,
+    X2$1, Y2$1, Z2$1,
+    lambda00, phi00, // first point
+    x0$4, y0$4, z0; // previous point
 
-var centroidStream = {
-  sphere: noop$2,
-  point: centroidPoint,
-  lineStart: centroidLineStart,
-  lineEnd: centroidLineEnd,
+var centroidStream$1 = {
+  sphere: noop$1,
+  point: centroidPoint$1,
+  lineStart: centroidLineStart$1,
+  lineEnd: centroidLineEnd$1,
   polygonStart: function() {
-    centroidStream.lineStart = centroidRingStart;
-    centroidStream.lineEnd = centroidRingEnd;
+    centroidStream$1.lineStart = centroidRingStart$1;
+    centroidStream$1.lineEnd = centroidRingEnd$1;
   },
   polygonEnd: function() {
-    centroidStream.lineStart = centroidLineStart;
-    centroidStream.lineEnd = centroidLineEnd;
+    centroidStream$1.lineStart = centroidLineStart$1;
+    centroidStream$1.lineEnd = centroidLineEnd$1;
   }
 };
 
 // Arithmetic mean of Cartesian vectors.
-function centroidPoint(lambda, phi) {
+function centroidPoint$1(lambda, phi) {
   lambda *= radians, phi *= radians;
   var cosPhi = cos$1(phi);
   centroidPointCartesian(cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi));
@@ -8007,23 +10225,23 @@
 
 function centroidPointCartesian(x, y, z) {
   ++W0;
-  X0 += (x - X0) / W0;
-  Y0 += (y - Y0) / W0;
-  Z0 += (z - Z0) / W0;
+  X0$1 += (x - X0$1) / W0;
+  Y0$1 += (y - Y0$1) / W0;
+  Z0$1 += (z - Z0$1) / W0;
 }
 
-function centroidLineStart() {
-  centroidStream.point = centroidLinePointFirst;
+function centroidLineStart$1() {
+  centroidStream$1.point = centroidLinePointFirst;
 }
 
 function centroidLinePointFirst(lambda, phi) {
   lambda *= radians, phi *= radians;
   var cosPhi = cos$1(phi);
-  x0 = cosPhi * cos$1(lambda);
-  y0 = cosPhi * sin$1(lambda);
+  x0$4 = cosPhi * cos$1(lambda);
+  y0$4 = cosPhi * sin$1(lambda);
   z0 = sin$1(phi);
-  centroidStream.point = centroidLinePoint;
-  centroidPointCartesian(x0, y0, z0);
+  centroidStream$1.point = centroidLinePoint;
+  centroidPointCartesian(x0$4, y0$4, z0);
 }
 
 function centroidLinePoint(lambda, phi) {
@@ -8032,38 +10250,38 @@
       x = cosPhi * cos$1(lambda),
       y = cosPhi * sin$1(lambda),
       z = sin$1(phi),
-      w = atan2(sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
+      w = atan2$1(sqrt$2((w = y0$4 * z - z0 * y) * w + (w = z0 * x - x0$4 * z) * w + (w = x0$4 * y - y0$4 * x) * w), x0$4 * x + y0$4 * y + z0 * z);
   W1 += w;
-  X1 += w * (x0 + (x0 = x));
-  Y1 += w * (y0 + (y0 = y));
-  Z1 += w * (z0 + (z0 = z));
-  centroidPointCartesian(x0, y0, z0);
+  X1$1 += w * (x0$4 + (x0$4 = x));
+  Y1$1 += w * (y0$4 + (y0$4 = y));
+  Z1$1 += w * (z0 + (z0 = z));
+  centroidPointCartesian(x0$4, y0$4, z0);
 }
 
-function centroidLineEnd() {
-  centroidStream.point = centroidPoint;
+function centroidLineEnd$1() {
+  centroidStream$1.point = centroidPoint$1;
 }
 
 // See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
 // J. Applied Mechanics 42, 239 (1975).
-function centroidRingStart() {
-  centroidStream.point = centroidRingPointFirst;
+function centroidRingStart$1() {
+  centroidStream$1.point = centroidRingPointFirst;
 }
 
-function centroidRingEnd() {
-  centroidRingPoint(lambda00$2, phi00$2);
-  centroidStream.point = centroidPoint;
+function centroidRingEnd$1() {
+  centroidRingPoint(lambda00, phi00);
+  centroidStream$1.point = centroidPoint$1;
 }
 
 function centroidRingPointFirst(lambda, phi) {
-  lambda00$2 = lambda, phi00$2 = phi;
+  lambda00 = lambda, phi00 = phi;
   lambda *= radians, phi *= radians;
-  centroidStream.point = centroidRingPoint;
+  centroidStream$1.point = centroidRingPoint;
   var cosPhi = cos$1(phi);
-  x0 = cosPhi * cos$1(lambda);
-  y0 = cosPhi * sin$1(lambda);
+  x0$4 = cosPhi * cos$1(lambda);
+  y0$4 = cosPhi * sin$1(lambda);
   z0 = sin$1(phi);
-  centroidPointCartesian(x0, y0, z0);
+  centroidPointCartesian(x0$4, y0$4, z0);
 }
 
 function centroidRingPoint(lambda, phi) {
@@ -8072,48 +10290,50 @@
       x = cosPhi * cos$1(lambda),
       y = cosPhi * sin$1(lambda),
       z = sin$1(phi),
-      cx = y0 * z - z0 * y,
-      cy = z0 * x - x0 * z,
-      cz = x0 * y - y0 * x,
-      m = sqrt(cx * cx + cy * cy + cz * cz),
-      w = asin(m), // line weight = angle
+      cx = y0$4 * z - z0 * y,
+      cy = z0 * x - x0$4 * z,
+      cz = x0$4 * y - y0$4 * x,
+      m = hypot(cx, cy, cz),
+      w = asin$1(m), // line weight = angle
       v = m && -w / m; // area weight multiplier
-  X2 += v * cx;
-  Y2 += v * cy;
-  Z2 += v * cz;
+  X2$1.add(v * cx);
+  Y2$1.add(v * cy);
+  Z2$1.add(v * cz);
   W1 += w;
-  X1 += w * (x0 + (x0 = x));
-  Y1 += w * (y0 + (y0 = y));
-  Z1 += w * (z0 + (z0 = z));
-  centroidPointCartesian(x0, y0, z0);
+  X1$1 += w * (x0$4 + (x0$4 = x));
+  Y1$1 += w * (y0$4 + (y0$4 = y));
+  Z1$1 += w * (z0 + (z0 = z));
+  centroidPointCartesian(x0$4, y0$4, z0);
 }
 
-function centroid(object) {
+function centroid$1(object) {
   W0 = W1 =
-  X0 = Y0 = Z0 =
-  X1 = Y1 = Z1 =
-  X2 = Y2 = Z2 = 0;
-  geoStream(object, centroidStream);
+  X0$1 = Y0$1 = Z0$1 =
+  X1$1 = Y1$1 = Z1$1 = 0;
+  X2$1 = new Adder();
+  Y2$1 = new Adder();
+  Z2$1 = new Adder();
+  geoStream(object, centroidStream$1);
 
-  var x = X2,
-      y = Y2,
-      z = Z2,
-      m = x * x + y * y + z * z;
+  var x = +X2$1,
+      y = +Y2$1,
+      z = +Z2$1,
+      m = hypot(x, y, z);
 
   // If the area-weighted ccentroid is undefined, fall back to length-weighted ccentroid.
-  if (m < epsilon2$1) {
-    x = X1, y = Y1, z = Z1;
+  if (m < epsilon2) {
+    x = X1$1, y = Y1$1, z = Z1$1;
     // If the feature has zero length, fall back to arithmetic mean of point vectors.
-    if (W1 < epsilon$2) x = X0, y = Y0, z = Z0;
-    m = x * x + y * y + z * z;
+    if (W1 < epsilon$1) x = X0$1, y = Y0$1, z = Z0$1;
+    m = hypot(x, y, z);
     // If the feature still has an undefined ccentroid, then return.
-    if (m < epsilon2$1) return [NaN, NaN];
+    if (m < epsilon2) return [NaN, NaN];
   }
 
-  return [atan2(y, x) * degrees$1, asin(z / sqrt(m)) * degrees$1];
+  return [atan2$1(y, x) * degrees, asin$1(z / m) * degrees];
 }
 
-function constant$8(x) {
+function constant$3(x) {
   return function() {
     return x;
   };
@@ -8133,13 +10353,14 @@
 }
 
 function rotationIdentity(lambda, phi) {
-  return [abs(lambda) > pi$3 ? lambda + Math.round(-lambda / tau$3) * tau$3 : lambda, phi];
+  if (abs$1(lambda) > pi$1) lambda -= Math.round(lambda / tau$1) * tau$1;
+  return [lambda, phi];
 }
 
 rotationIdentity.invert = rotationIdentity;
 
 function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
-  return (deltaLambda %= tau$3) ? (deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma))
+  return (deltaLambda %= tau$1) ? (deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma))
     : rotationLambda(deltaLambda))
     : (deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma)
     : rotationIdentity);
@@ -8147,7 +10368,9 @@
 
 function forwardRotationLambda(deltaLambda) {
   return function(lambda, phi) {
-    return lambda += deltaLambda, [lambda > pi$3 ? lambda - tau$3 : lambda < -pi$3 ? lambda + tau$3 : lambda, phi];
+    lambda += deltaLambda;
+    if (abs$1(lambda) > pi$1) lambda -= Math.round(lambda / tau$1) * tau$1;
+    return [lambda, phi];
   };
 }
 
@@ -8170,8 +10393,8 @@
         z = sin$1(phi),
         k = z * cosDeltaPhi + x * sinDeltaPhi;
     return [
-      atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi),
-      asin(k * cosDeltaGamma + y * sinDeltaGamma)
+      atan2$1(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi),
+      asin$1(k * cosDeltaGamma + y * sinDeltaGamma)
     ];
   }
 
@@ -8182,8 +10405,8 @@
         z = sin$1(phi),
         k = z * cosDeltaGamma - y * sinDeltaGamma;
     return [
-      atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi),
-      asin(k * cosDeltaPhi - x * sinDeltaPhi)
+      atan2$1(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi),
+      asin$1(k * cosDeltaPhi - x * sinDeltaPhi)
     ];
   };
 
@@ -8195,12 +10418,12 @@
 
   function forward(coordinates) {
     coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
-    return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
+    return coordinates[0] *= degrees, coordinates[1] *= degrees, coordinates;
   }
 
   forward.invert = function(coordinates) {
     coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
-    return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
+    return coordinates[0] *= degrees, coordinates[1] *= degrees, coordinates;
   };
 
   return forward;
@@ -8213,12 +10436,12 @@
       sinRadius = sin$1(radius),
       step = direction * delta;
   if (t0 == null) {
-    t0 = radius + direction * tau$3;
+    t0 = radius + direction * tau$1;
     t1 = radius - step / 2;
   } else {
     t0 = circleRadius(cosRadius, t0);
     t1 = circleRadius(cosRadius, t1);
-    if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau$3;
+    if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau$1;
   }
   for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
     point = spherical([cosRadius, -sinRadius * cos$1(t), -sinRadius * sin$1(t)]);
@@ -8230,21 +10453,21 @@
 function circleRadius(cosRadius, point) {
   point = cartesian(point), point[0] -= cosRadius;
   cartesianNormalizeInPlace(point);
-  var radius = acos(-point[1]);
-  return ((-point[2] < 0 ? -radius : radius) + tau$3 - epsilon$2) % tau$3;
+  var radius = acos$1(-point[1]);
+  return ((-point[2] < 0 ? -radius : radius) + tau$1 - epsilon$1) % tau$1;
 }
 
-function circle() {
-  var center = constant$8([0, 0]),
-      radius = constant$8(90),
-      precision = constant$8(6),
+function circle$1() {
+  var center = constant$3([0, 0]),
+      radius = constant$3(90),
+      precision = constant$3(6),
       ring,
       rotate,
       stream = {point: point};
 
   function point(x, y) {
     ring.push(x = rotate(x, y));
-    x[0] *= degrees$1, x[1] *= degrees$1;
+    x[0] *= degrees, x[1] *= degrees;
   }
 
   function circle() {
@@ -8260,15 +10483,15 @@
   }
 
   circle.center = function(_) {
-    return arguments.length ? (center = typeof _ === "function" ? _ : constant$8([+_[0], +_[1]]), circle) : center;
+    return arguments.length ? (center = typeof _ === "function" ? _ : constant$3([+_[0], +_[1]]), circle) : center;
   };
 
   circle.radius = function(_) {
-    return arguments.length ? (radius = typeof _ === "function" ? _ : constant$8(+_), circle) : radius;
+    return arguments.length ? (radius = typeof _ === "function" ? _ : constant$3(+_), circle) : radius;
   };
 
   circle.precision = function(_) {
-    return arguments.length ? (precision = typeof _ === "function" ? _ : constant$8(+_), circle) : precision;
+    return arguments.length ? (precision = typeof _ === "function" ? _ : constant$3(+_), circle) : precision;
   };
 
   return circle;
@@ -8278,13 +10501,13 @@
   var lines = [],
       line;
   return {
-    point: function(x, y) {
-      line.push([x, y]);
+    point: function(x, y, m) {
+      line.push([x, y, m]);
     },
     lineStart: function() {
       lines.push(line = []);
     },
-    lineEnd: noop$2,
+    lineEnd: noop$1,
     rejoin: function() {
       if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
     },
@@ -8298,7 +10521,7 @@
 }
 
 function pointEqual(a, b) {
-  return abs(a[0] - b[0]) < epsilon$2 && abs(a[1] - b[1]) < epsilon$2;
+  return abs$1(a[0] - b[0]) < epsilon$1 && abs$1(a[1] - b[1]) < epsilon$1;
 }
 
 function Intersection(point, points, other, entry) {
@@ -8323,14 +10546,15 @@
     if ((n = segment.length - 1) <= 0) return;
     var n, p0 = segment[0], p1 = segment[n], x;
 
-    // If the first and last points of a segment are coincident, then treat as a
-    // closed ring. TODO if all rings are closed, then the winding order of the
-    // exterior ring should be checked.
     if (pointEqual(p0, p1)) {
-      stream.lineStart();
-      for (i = 0; i < n; ++i) stream.point((p0 = segment[i])[0], p0[1]);
-      stream.lineEnd();
-      return;
+      if (!p0[2] && !p1[2]) {
+        stream.lineStart();
+        for (i = 0; i < n; ++i) stream.point((p0 = segment[i])[0], p0[1]);
+        stream.lineEnd();
+        return;
+      }
+      // handle degenerate cases by moving the point
+      p1[0] += 2 * epsilon$1;
     }
 
     subject.push(x = new Intersection(p0, segment, null, true));
@@ -8401,13 +10625,8 @@
   b.p = a;
 }
 
-var sum$1 = adder();
-
 function longitude(point) {
-  if (abs(point[0]) <= pi$3)
-    return point[0];
-  else
-    return sign(point[0]) * ((abs(point[0]) + pi$3) % tau$3 - pi$3);
+  return abs$1(point[0]) <= pi$1 ? point[0] : sign$1(point[0]) * ((abs$1(point[0]) + pi$1) % tau$1 - pi$1);
 }
 
 function polygonContains(polygon, point) {
@@ -8418,10 +10637,10 @@
       angle = 0,
       winding = 0;
 
-  sum$1.reset();
+  var sum = new Adder();
 
-  if (sinPhi === 1) phi = halfPi$2 + epsilon$2;
-  else if (sinPhi === -1) phi = -halfPi$2 - epsilon$2;
+  if (sinPhi === 1) phi = halfPi$1 + epsilon$1;
+  else if (sinPhi === -1) phi = -halfPi$1 - epsilon$1;
 
   for (var i = 0, n = polygon.length; i < n; ++i) {
     if (!(m = (ring = polygon[i]).length)) continue;
@@ -8442,11 +10661,11 @@
           delta = lambda1 - lambda0,
           sign = delta >= 0 ? 1 : -1,
           absDelta = sign * delta,
-          antimeridian = absDelta > pi$3,
+          antimeridian = absDelta > pi$1,
           k = sinPhi0 * sinPhi1;
 
-      sum$1.add(atan2(k * sign * sin$1(absDelta), cosPhi0 * cosPhi1 + k * cos$1(absDelta)));
-      angle += antimeridian ? delta + sign * tau$3 : delta;
+      sum.add(atan2$1(k * sign * sin$1(absDelta), cosPhi0 * cosPhi1 + k * cos$1(absDelta)));
+      angle += antimeridian ? delta + sign * tau$1 : delta;
 
       // Are the longitudes either side of the point’s meridian (lambda),
       // and are the latitudes smaller than the parallel (phi)?
@@ -8455,7 +10674,7 @@
         cartesianNormalizeInPlace(arc);
         var intersection = cartesianCross(normal, arc);
         cartesianNormalizeInPlace(intersection);
-        var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
+        var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin$1(intersection[2]);
         if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
           winding += antimeridian ^ delta >= 0 ? 1 : -1;
         }
@@ -8474,7 +10693,7 @@
   // from the point to the South pole.  If it is zero, then the point is the
   // same side as the South pole.
 
-  return (angle < -epsilon$2 || angle < epsilon$2 && sum$1 < -epsilon$2) ^ (winding & 1);
+  return (angle < -epsilon$1 || angle < epsilon$1 && sum < -epsilon2) ^ (winding & 1);
 }
 
 function clip(pointVisible, clipLine, interpolate, start) {
@@ -8599,15 +10818,15 @@
 // Intersections are sorted along the clip edge. For both antimeridian cutting
 // and circle clipping, the same comparison is used.
 function compareIntersection(a, b) {
-  return ((a = a.x)[0] < 0 ? a[1] - halfPi$2 - epsilon$2 : halfPi$2 - a[1])
-       - ((b = b.x)[0] < 0 ? b[1] - halfPi$2 - epsilon$2 : halfPi$2 - b[1]);
+  return ((a = a.x)[0] < 0 ? a[1] - halfPi$1 - epsilon$1 : halfPi$1 - a[1])
+       - ((b = b.x)[0] < 0 ? b[1] - halfPi$1 - epsilon$1 : halfPi$1 - b[1]);
 }
 
 var clipAntimeridian = clip(
   function() { return true; },
   clipAntimeridianLine,
   clipAntimeridianInterpolate,
-  [-pi$3, -halfPi$2]
+  [-pi$1, -halfPi$1]
 );
 
 // Takes a line and cuts into visible segments. Return values: 0 - there were
@@ -8625,19 +10844,19 @@
       clean = 1;
     },
     point: function(lambda1, phi1) {
-      var sign1 = lambda1 > 0 ? pi$3 : -pi$3,
-          delta = abs(lambda1 - lambda0);
-      if (abs(delta - pi$3) < epsilon$2) { // line crosses a pole
-        stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi$2 : -halfPi$2);
+      var sign1 = lambda1 > 0 ? pi$1 : -pi$1,
+          delta = abs$1(lambda1 - lambda0);
+      if (abs$1(delta - pi$1) < epsilon$1) { // line crosses a pole
+        stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi$1 : -halfPi$1);
         stream.point(sign0, phi0);
         stream.lineEnd();
         stream.lineStart();
         stream.point(sign1, phi0);
         stream.point(lambda1, phi0);
         clean = 0;
-      } else if (sign0 !== sign1 && delta >= pi$3) { // line crosses antimeridian
-        if (abs(lambda0 - sign0) < epsilon$2) lambda0 -= sign0 * epsilon$2; // handle degeneracies
-        if (abs(lambda1 - sign1) < epsilon$2) lambda1 -= sign1 * epsilon$2;
+      } else if (sign0 !== sign1 && delta >= pi$1) { // line crosses antimeridian
+        if (abs$1(lambda0 - sign0) < epsilon$1) lambda0 -= sign0 * epsilon$1; // handle degeneracies
+        if (abs$1(lambda1 - sign1) < epsilon$1) lambda1 -= sign1 * epsilon$1;
         phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
         stream.point(sign0, phi0);
         stream.lineEnd();
@@ -8662,7 +10881,7 @@
   var cosPhi0,
       cosPhi1,
       sinLambda0Lambda1 = sin$1(lambda0 - lambda1);
-  return abs(sinLambda0Lambda1) > epsilon$2
+  return abs$1(sinLambda0Lambda1) > epsilon$1
       ? atan((sin$1(phi0) * (cosPhi1 = cos$1(phi1)) * sin$1(lambda1)
           - sin$1(phi1) * (cosPhi0 = cos$1(phi0)) * sin$1(lambda0))
           / (cosPhi0 * cosPhi1 * sinLambda0Lambda1))
@@ -8672,18 +10891,18 @@
 function clipAntimeridianInterpolate(from, to, direction, stream) {
   var phi;
   if (from == null) {
-    phi = direction * halfPi$2;
-    stream.point(-pi$3, phi);
+    phi = direction * halfPi$1;
+    stream.point(-pi$1, phi);
     stream.point(0, phi);
-    stream.point(pi$3, phi);
-    stream.point(pi$3, 0);
-    stream.point(pi$3, -phi);
+    stream.point(pi$1, phi);
+    stream.point(pi$1, 0);
+    stream.point(pi$1, -phi);
     stream.point(0, -phi);
-    stream.point(-pi$3, -phi);
-    stream.point(-pi$3, 0);
-    stream.point(-pi$3, phi);
-  } else if (abs(from[0] - to[0]) > epsilon$2) {
-    var lambda = from[0] < to[0] ? pi$3 : -pi$3;
+    stream.point(-pi$1, -phi);
+    stream.point(-pi$1, 0);
+    stream.point(-pi$1, phi);
+  } else if (abs$1(from[0] - to[0]) > epsilon$1) {
+    var lambda = from[0] < to[0] ? pi$1 : -pi$1;
     phi = direction * lambda / 2;
     stream.point(-lambda, phi);
     stream.point(0, phi);
@@ -8697,7 +10916,7 @@
   var cr = cos$1(radius),
       delta = 6 * radians,
       smallRadius = cr > 0,
-      notHemisphere = abs(cr) > epsilon$2; // TODO optimise for this common case
+      notHemisphere = abs$1(cr) > epsilon$1; // TODO optimise for this common case
 
   function interpolate(from, to, direction, stream) {
     circleStream(stream, radius, delta, direction, from, to);
@@ -8728,17 +10947,12 @@
             v = visible(lambda, phi),
             c = smallRadius
               ? v ? 0 : code(lambda, phi)
-              : v ? code(lambda + (lambda < 0 ? pi$3 : -pi$3), phi) : 0;
+              : v ? code(lambda + (lambda < 0 ? pi$1 : -pi$1), phi) : 0;
         if (!point0 && (v00 = v0 = v)) stream.lineStart();
-        // Handle degeneracies.
-        // TODO ignore if not clipping polygons.
         if (v !== v0) {
           point2 = intersect(point0, point1);
-          if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2)) {
-            point1[0] += epsilon$2;
-            point1[1] += epsilon$2;
-            v = visible(point1[0], point1[1]);
-          }
+          if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2))
+            point1[2] = 1;
         }
         if (v !== v0) {
           clean = 0;
@@ -8750,7 +10964,7 @@
           } else {
             // inside going out
             point2 = intersect(point0, point1);
-            stream.point(point2[0], point2[1]);
+            stream.point(point2[0], point2[1], 2);
             stream.lineEnd();
           }
           point0 = point2;
@@ -8769,7 +10983,7 @@
               stream.point(t[1][0], t[1][1]);
               stream.lineEnd();
               stream.lineStart();
-              stream.point(t[0][0], t[0][1]);
+              stream.point(t[0][0], t[0][1], 3);
             }
           }
         }
@@ -8821,7 +11035,7 @@
 
     if (t2 < 0) return;
 
-    var t = sqrt(t2),
+    var t = sqrt$2(t2),
         q = cartesianScale(u, (-w - t) / uu);
     cartesianAddInPlace(q, A);
     q = spherical(q);
@@ -8838,17 +11052,17 @@
     if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
 
     var delta = lambda1 - lambda0,
-        polar = abs(delta - pi$3) < epsilon$2,
-        meridian = polar || delta < epsilon$2;
+        polar = abs$1(delta - pi$1) < epsilon$1,
+        meridian = polar || delta < epsilon$1;
 
     if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z;
 
     // Check that the first point is between a and b.
     if (meridian
         ? polar
-          ? phi0 + phi1 > 0 ^ q[1] < (abs(q[0] - lambda0) < epsilon$2 ? phi0 : phi1)
+          ? phi0 + phi1 > 0 ^ q[1] < (abs$1(q[0] - lambda0) < epsilon$1 ? phi0 : phi1)
           : phi0 <= q[1] && q[1] <= phi1
-        : delta > pi$3 ^ (lambda0 <= q[0] && q[0] <= lambda1)) {
+        : delta > pi$1 ^ (lambda0 <= q[0] && q[0] <= lambda1)) {
       var q1 = cartesianScale(u, (-w + t) / uu);
       cartesianAddInPlace(q1, A);
       return [q, spherical(q1)];
@@ -8858,7 +11072,7 @@
   // Generates a 4-bit vector representing the location of a point relative to
   // the small circle's bounding box.
   function code(lambda, phi) {
-    var r = smallRadius ? radius : pi$3 - radius,
+    var r = smallRadius ? radius : pi$1 - radius,
         code = 0;
     if (lambda < -r) code |= 1; // left
     else if (lambda > r) code |= 2; // right
@@ -8867,7 +11081,7 @@
     return code;
   }
 
-  return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi$3, radius - pi$3]);
+  return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi$1, radius - pi$1]);
 }
 
 function clipLine(a, b, x0, y0, x1, y1) {
@@ -8954,9 +11168,9 @@
   }
 
   function corner(p, direction) {
-    return abs(p[0] - x0) < epsilon$2 ? direction > 0 ? 0 : 3
-        : abs(p[0] - x1) < epsilon$2 ? direction > 0 ? 2 : 1
-        : abs(p[1] - y0) < epsilon$2 ? direction > 0 ? 1 : 0
+    return abs$1(p[0] - x0) < epsilon$1 ? direction > 0 ? 0 : 3
+        : abs$1(p[0] - x1) < epsilon$1 ? direction > 0 ? 2 : 1
+        : abs$1(p[1] - y0) < epsilon$1 ? direction > 0 ? 1 : 0
         : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
   }
 
@@ -9093,7 +11307,7 @@
   };
 }
 
-function extent$1() {
+function extent() {
   var x0 = 0,
       y0 = 0,
       x1 = 960,
@@ -9112,62 +11326,62 @@
   };
 }
 
-var lengthSum = adder(),
-    lambda0$2,
-    sinPhi0$1,
-    cosPhi0$1;
+var lengthSum$1,
+    lambda0,
+    sinPhi0,
+    cosPhi0;
 
-var lengthStream = {
-  sphere: noop$2,
-  point: noop$2,
+var lengthStream$1 = {
+  sphere: noop$1,
+  point: noop$1,
   lineStart: lengthLineStart,
-  lineEnd: noop$2,
-  polygonStart: noop$2,
-  polygonEnd: noop$2
+  lineEnd: noop$1,
+  polygonStart: noop$1,
+  polygonEnd: noop$1
 };
 
 function lengthLineStart() {
-  lengthStream.point = lengthPointFirst;
-  lengthStream.lineEnd = lengthLineEnd;
+  lengthStream$1.point = lengthPointFirst$1;
+  lengthStream$1.lineEnd = lengthLineEnd;
 }
 
 function lengthLineEnd() {
-  lengthStream.point = lengthStream.lineEnd = noop$2;
+  lengthStream$1.point = lengthStream$1.lineEnd = noop$1;
 }
 
-function lengthPointFirst(lambda, phi) {
+function lengthPointFirst$1(lambda, phi) {
   lambda *= radians, phi *= radians;
-  lambda0$2 = lambda, sinPhi0$1 = sin$1(phi), cosPhi0$1 = cos$1(phi);
-  lengthStream.point = lengthPoint;
+  lambda0 = lambda, sinPhi0 = sin$1(phi), cosPhi0 = cos$1(phi);
+  lengthStream$1.point = lengthPoint$1;
 }
 
-function lengthPoint(lambda, phi) {
+function lengthPoint$1(lambda, phi) {
   lambda *= radians, phi *= radians;
   var sinPhi = sin$1(phi),
       cosPhi = cos$1(phi),
-      delta = abs(lambda - lambda0$2),
+      delta = abs$1(lambda - lambda0),
       cosDelta = cos$1(delta),
       sinDelta = sin$1(delta),
       x = cosPhi * sinDelta,
-      y = cosPhi0$1 * sinPhi - sinPhi0$1 * cosPhi * cosDelta,
-      z = sinPhi0$1 * sinPhi + cosPhi0$1 * cosPhi * cosDelta;
-  lengthSum.add(atan2(sqrt(x * x + y * y), z));
-  lambda0$2 = lambda, sinPhi0$1 = sinPhi, cosPhi0$1 = cosPhi;
+      y = cosPhi0 * sinPhi - sinPhi0 * cosPhi * cosDelta,
+      z = sinPhi0 * sinPhi + cosPhi0 * cosPhi * cosDelta;
+  lengthSum$1.add(atan2$1(sqrt$2(x * x + y * y), z));
+  lambda0 = lambda, sinPhi0 = sinPhi, cosPhi0 = cosPhi;
 }
 
 function length$1(object) {
-  lengthSum.reset();
-  geoStream(object, lengthStream);
-  return +lengthSum;
+  lengthSum$1 = new Adder();
+  geoStream(object, lengthStream$1);
+  return +lengthSum$1;
 }
 
 var coordinates = [null, null],
-    object$1 = {type: "LineString", coordinates: coordinates};
+    object = {type: "LineString", coordinates: coordinates};
 
 function distance(a, b) {
   coordinates[0] = a;
   coordinates[1] = b;
-  return length$1(object$1);
+  return length$1(object);
 }
 
 var containsObjectType = {
@@ -9237,7 +11451,7 @@
         ab > 0 &&
         ao <= ab &&
         bo <= ab &&
-        (ao + bo - ab) * (1 - Math.pow((ao - bo) / ab, 2)) < epsilon2$1 * ab
+        (ao + bo - ab) * (1 - Math.pow((ao - bo) / ab, 2)) < epsilon2 * ab
       )
         return true;
     }
@@ -9265,12 +11479,12 @@
 }
 
 function graticuleX(y0, y1, dy) {
-  var y = sequence(y0, y1 - epsilon$2, dy).concat(y1);
+  var y = range$2(y0, y1 - epsilon$1, dy).concat(y1);
   return function(x) { return y.map(function(y) { return [x, y]; }); };
 }
 
 function graticuleY(x0, x1, dx) {
-  var x = sequence(x0, x1 - epsilon$2, dx).concat(x1);
+  var x = range$2(x0, x1 - epsilon$1, dx).concat(x1);
   return function(y) { return x.map(function(x) { return [x, y]; }); };
 }
 
@@ -9286,10 +11500,10 @@
   }
 
   function lines() {
-    return sequence(ceil(X0 / DX) * DX, X1, DX).map(X)
-        .concat(sequence(ceil(Y0 / DY) * DY, Y1, DY).map(Y))
-        .concat(sequence(ceil(x0 / dx) * dx, x1, dx).filter(function(x) { return abs(x % DX) > epsilon$2; }).map(x))
-        .concat(sequence(ceil(y0 / dy) * dy, y1, dy).filter(function(y) { return abs(y % DY) > epsilon$2; }).map(y));
+    return range$2(ceil(X0 / DX) * DX, X1, DX).map(X)
+        .concat(range$2(ceil(Y0 / DY) * DY, Y1, DY).map(Y))
+        .concat(range$2(ceil(x0 / dx) * dx, x1, dx).filter(function(x) { return abs$1(x % DX) > epsilon$1; }).map(x))
+        .concat(range$2(ceil(y0 / dy) * dy, y1, dy).filter(function(y) { return abs$1(y % DY) > epsilon$1; }).map(y));
   }
 
   graticule.lines = function() {
@@ -9359,15 +11573,15 @@
   };
 
   return graticule
-      .extentMajor([[-180, -90 + epsilon$2], [180, 90 - epsilon$2]])
-      .extentMinor([[-180, -80 - epsilon$2], [180, 80 + epsilon$2]]);
+      .extentMajor([[-180, -90 + epsilon$1], [180, 90 - epsilon$1]])
+      .extentMinor([[-180, -80 - epsilon$1], [180, 80 + epsilon$1]]);
 }
 
 function graticule10() {
   return graticule()();
 }
 
-function interpolate$1(a, b) {
+function interpolate(a, b) {
   var x0 = a[0] * radians,
       y0 = a[1] * radians,
       x1 = b[0] * radians,
@@ -9380,7 +11594,7 @@
       ky0 = cy0 * sin$1(x0),
       kx1 = cy1 * cos$1(x1),
       ky1 = cy1 * sin$1(x1),
-      d = 2 * asin(sqrt(haversin(y1 - y0) + cy0 * cy1 * haversin(x1 - x0))),
+      d = 2 * asin$1(sqrt$2(haversin(y1 - y0) + cy0 * cy1 * haversin(x1 - x0))),
       k = sin$1(d);
 
   var interpolate = d ? function(t) {
@@ -9390,11 +11604,11 @@
         y = A * ky0 + B * ky1,
         z = A * sy0 + B * sy1;
     return [
-      atan2(y, x) * degrees$1,
-      atan2(z, sqrt(x * x + y * y)) * degrees$1
+      atan2$1(y, x) * degrees,
+      atan2$1(z, sqrt$2(x * x + y * y)) * degrees
     ];
   } : function() {
-    return [x0 * degrees$1, y0 * degrees$1];
+    return [x0 * degrees, y0 * degrees];
   };
 
   interpolate.distance = d;
@@ -9402,66 +11616,66 @@
   return interpolate;
 }
 
-function identity$4(x) {
-  return x;
-}
+var identity$5 = x => x;
 
-var areaSum$1 = adder(),
-    areaRingSum$1 = adder(),
-    x00,
-    y00,
-    x0$1,
-    y0$1;
+var areaSum = new Adder(),
+    areaRingSum = new Adder(),
+    x00$2,
+    y00$2,
+    x0$3,
+    y0$3;
 
-var areaStream$1 = {
-  point: noop$2,
-  lineStart: noop$2,
-  lineEnd: noop$2,
+var areaStream = {
+  point: noop$1,
+  lineStart: noop$1,
+  lineEnd: noop$1,
   polygonStart: function() {
-    areaStream$1.lineStart = areaRingStart$1;
-    areaStream$1.lineEnd = areaRingEnd$1;
+    areaStream.lineStart = areaRingStart;
+    areaStream.lineEnd = areaRingEnd;
   },
   polygonEnd: function() {
-    areaStream$1.lineStart = areaStream$1.lineEnd = areaStream$1.point = noop$2;
-    areaSum$1.add(abs(areaRingSum$1));
-    areaRingSum$1.reset();
+    areaStream.lineStart = areaStream.lineEnd = areaStream.point = noop$1;
+    areaSum.add(abs$1(areaRingSum));
+    areaRingSum = new Adder();
   },
   result: function() {
-    var area = areaSum$1 / 2;
-    areaSum$1.reset();
+    var area = areaSum / 2;
+    areaSum = new Adder();
     return area;
   }
 };
 
-function areaRingStart$1() {
-  areaStream$1.point = areaPointFirst$1;
+function areaRingStart() {
+  areaStream.point = areaPointFirst;
 }
 
-function areaPointFirst$1(x, y) {
-  areaStream$1.point = areaPoint$1;
-  x00 = x0$1 = x, y00 = y0$1 = y;
+function areaPointFirst(x, y) {
+  areaStream.point = areaPoint;
+  x00$2 = x0$3 = x, y00$2 = y0$3 = y;
 }
 
-function areaPoint$1(x, y) {
-  areaRingSum$1.add(y0$1 * x - x0$1 * y);
-  x0$1 = x, y0$1 = y;
+function areaPoint(x, y) {
+  areaRingSum.add(y0$3 * x - x0$3 * y);
+  x0$3 = x, y0$3 = y;
 }
 
-function areaRingEnd$1() {
-  areaPoint$1(x00, y00);
+function areaRingEnd() {
+  areaPoint(x00$2, y00$2);
 }
 
+var pathArea = areaStream;
+
 var x0$2 = Infinity,
     y0$2 = x0$2,
     x1 = -x0$2,
     y1 = x1;
 
-var boundsStream$1 = {
-  point: boundsPoint$1,
-  lineStart: noop$2,
-  lineEnd: noop$2,
-  polygonStart: noop$2,
-  polygonEnd: noop$2,
+var boundsStream = {
+  point: boundsPoint,
+  lineStart: noop$1,
+  lineEnd: noop$1,
+  polygonStart: noop$1,
+  polygonEnd: noop$1,
   result: function() {
     var bounds = [[x0$2, y0$2], [x1, y1]];
     x1 = y1 = -(y0$2 = x0$2 = Infinity);
@@ -9469,110 +11683,114 @@
   }
 };
 
-function boundsPoint$1(x, y) {
+function boundsPoint(x, y) {
   if (x < x0$2) x0$2 = x;
   if (x > x1) x1 = x;
   if (y < y0$2) y0$2 = y;
   if (y > y1) y1 = y;
 }
 
+var boundsStream$1 = boundsStream;
+
 // TODO Enforce positive area for exterior, negative area for interior?
 
-var X0$1 = 0,
-    Y0$1 = 0,
-    Z0$1 = 0,
-    X1$1 = 0,
-    Y1$1 = 0,
-    Z1$1 = 0,
-    X2$1 = 0,
-    Y2$1 = 0,
-    Z2$1 = 0,
+var X0 = 0,
+    Y0 = 0,
+    Z0 = 0,
+    X1 = 0,
+    Y1 = 0,
+    Z1 = 0,
+    X2 = 0,
+    Y2 = 0,
+    Z2 = 0,
     x00$1,
     y00$1,
-    x0$3,
-    y0$3;
+    x0$1,
+    y0$1;
 
-var centroidStream$1 = {
-  point: centroidPoint$1,
-  lineStart: centroidLineStart$1,
-  lineEnd: centroidLineEnd$1,
+var centroidStream = {
+  point: centroidPoint,
+  lineStart: centroidLineStart,
+  lineEnd: centroidLineEnd,
   polygonStart: function() {
-    centroidStream$1.lineStart = centroidRingStart$1;
-    centroidStream$1.lineEnd = centroidRingEnd$1;
+    centroidStream.lineStart = centroidRingStart;
+    centroidStream.lineEnd = centroidRingEnd;
   },
   polygonEnd: function() {
-    centroidStream$1.point = centroidPoint$1;
-    centroidStream$1.lineStart = centroidLineStart$1;
-    centroidStream$1.lineEnd = centroidLineEnd$1;
+    centroidStream.point = centroidPoint;
+    centroidStream.lineStart = centroidLineStart;
+    centroidStream.lineEnd = centroidLineEnd;
   },
   result: function() {
-    var centroid = Z2$1 ? [X2$1 / Z2$1, Y2$1 / Z2$1]
-        : Z1$1 ? [X1$1 / Z1$1, Y1$1 / Z1$1]
-        : Z0$1 ? [X0$1 / Z0$1, Y0$1 / Z0$1]
+    var centroid = Z2 ? [X2 / Z2, Y2 / Z2]
+        : Z1 ? [X1 / Z1, Y1 / Z1]
+        : Z0 ? [X0 / Z0, Y0 / Z0]
         : [NaN, NaN];
-    X0$1 = Y0$1 = Z0$1 =
-    X1$1 = Y1$1 = Z1$1 =
-    X2$1 = Y2$1 = Z2$1 = 0;
+    X0 = Y0 = Z0 =
+    X1 = Y1 = Z1 =
+    X2 = Y2 = Z2 = 0;
     return centroid;
   }
 };
 
-function centroidPoint$1(x, y) {
-  X0$1 += x;
-  Y0$1 += y;
-  ++Z0$1;
+function centroidPoint(x, y) {
+  X0 += x;
+  Y0 += y;
+  ++Z0;
 }
 
-function centroidLineStart$1() {
-  centroidStream$1.point = centroidPointFirstLine;
+function centroidLineStart() {
+  centroidStream.point = centroidPointFirstLine;
 }
 
 function centroidPointFirstLine(x, y) {
-  centroidStream$1.point = centroidPointLine;
-  centroidPoint$1(x0$3 = x, y0$3 = y);
+  centroidStream.point = centroidPointLine;
+  centroidPoint(x0$1 = x, y0$1 = y);
 }
 
 function centroidPointLine(x, y) {
-  var dx = x - x0$3, dy = y - y0$3, z = sqrt(dx * dx + dy * dy);
-  X1$1 += z * (x0$3 + x) / 2;
-  Y1$1 += z * (y0$3 + y) / 2;
-  Z1$1 += z;
-  centroidPoint$1(x0$3 = x, y0$3 = y);
+  var dx = x - x0$1, dy = y - y0$1, z = sqrt$2(dx * dx + dy * dy);
+  X1 += z * (x0$1 + x) / 2;
+  Y1 += z * (y0$1 + y) / 2;
+  Z1 += z;
+  centroidPoint(x0$1 = x, y0$1 = y);
 }
 
-function centroidLineEnd$1() {
-  centroidStream$1.point = centroidPoint$1;
+function centroidLineEnd() {
+  centroidStream.point = centroidPoint;
 }
 
-function centroidRingStart$1() {
-  centroidStream$1.point = centroidPointFirstRing;
+function centroidRingStart() {
+  centroidStream.point = centroidPointFirstRing;
 }
 
-function centroidRingEnd$1() {
+function centroidRingEnd() {
   centroidPointRing(x00$1, y00$1);
 }
 
 function centroidPointFirstRing(x, y) {
-  centroidStream$1.point = centroidPointRing;
-  centroidPoint$1(x00$1 = x0$3 = x, y00$1 = y0$3 = y);
+  centroidStream.point = centroidPointRing;
+  centroidPoint(x00$1 = x0$1 = x, y00$1 = y0$1 = y);
 }
 
 function centroidPointRing(x, y) {
-  var dx = x - x0$3,
-      dy = y - y0$3,
-      z = sqrt(dx * dx + dy * dy);
+  var dx = x - x0$1,
+      dy = y - y0$1,
+      z = sqrt$2(dx * dx + dy * dy);
 
-  X1$1 += z * (x0$3 + x) / 2;
-  Y1$1 += z * (y0$3 + y) / 2;
-  Z1$1 += z;
+  X1 += z * (x0$1 + x) / 2;
+  Y1 += z * (y0$1 + y) / 2;
+  Z1 += z;
 
-  z = y0$3 * x - x0$3 * y;
-  X2$1 += z * (x0$3 + x);
-  Y2$1 += z * (y0$3 + y);
-  Z2$1 += z * 3;
-  centroidPoint$1(x0$3 = x, y0$3 = y);
+  z = y0$1 * x - x0$1 * y;
+  X2 += z * (x0$1 + x);
+  Y2 += z * (y0$1 + y);
+  Z2 += z * 3;
+  centroidPoint(x0$1 = x, y0$1 = y);
 }
 
+var pathCentroid = centroidStream;
+
 function PathContext(context) {
   this._context = context;
 }
@@ -9608,29 +11826,29 @@
       }
       default: {
         this._context.moveTo(x + this._radius, y);
-        this._context.arc(x, y, this._radius, 0, tau$3);
+        this._context.arc(x, y, this._radius, 0, tau$1);
         break;
       }
     }
   },
-  result: noop$2
+  result: noop$1
 };
 
-var lengthSum$1 = adder(),
+var lengthSum = new Adder(),
     lengthRing,
-    x00$2,
-    y00$2,
-    x0$4,
-    y0$4;
+    x00,
+    y00,
+    x0,
+    y0;
 
-var lengthStream$1 = {
-  point: noop$2,
+var lengthStream = {
+  point: noop$1,
   lineStart: function() {
-    lengthStream$1.point = lengthPointFirst$1;
+    lengthStream.point = lengthPointFirst;
   },
   lineEnd: function() {
-    if (lengthRing) lengthPoint$1(x00$2, y00$2);
-    lengthStream$1.point = noop$2;
+    if (lengthRing) lengthPoint(x00, y00);
+    lengthStream.point = noop$1;
   },
   polygonStart: function() {
     lengthRing = true;
@@ -9639,85 +11857,115 @@
     lengthRing = null;
   },
   result: function() {
-    var length = +lengthSum$1;
-    lengthSum$1.reset();
+    var length = +lengthSum;
+    lengthSum = new Adder();
     return length;
   }
 };
 
-function lengthPointFirst$1(x, y) {
-  lengthStream$1.point = lengthPoint$1;
-  x00$2 = x0$4 = x, y00$2 = y0$4 = y;
+function lengthPointFirst(x, y) {
+  lengthStream.point = lengthPoint;
+  x00 = x0 = x, y00 = y0 = y;
 }
 
-function lengthPoint$1(x, y) {
-  x0$4 -= x, y0$4 -= y;
-  lengthSum$1.add(sqrt(x0$4 * x0$4 + y0$4 * y0$4));
-  x0$4 = x, y0$4 = y;
+function lengthPoint(x, y) {
+  x0 -= x, y0 -= y;
+  lengthSum.add(sqrt$2(x0 * x0 + y0 * y0));
+  x0 = x, y0 = y;
 }
 
-function PathString() {
-  this._string = [];
-}
+var pathMeasure = lengthStream;
 
-PathString.prototype = {
-  _radius: 4.5,
-  _circle: circle$1(4.5),
-  pointRadius: function(_) {
-    if ((_ = +_) !== this._radius) this._radius = _, this._circle = null;
+// Simple caching for constant-radius points.
+let cacheDigits, cacheAppend, cacheRadius, cacheCircle;
+
+class PathString {
+  constructor(digits) {
+    this._append = digits == null ? append : appendRound(digits);
+    this._radius = 4.5;
+    this._ = "";
+  }
+  pointRadius(_) {
+    this._radius = +_;
     return this;
-  },
-  polygonStart: function() {
+  }
+  polygonStart() {
     this._line = 0;
-  },
-  polygonEnd: function() {
+  }
+  polygonEnd() {
     this._line = NaN;
-  },
-  lineStart: function() {
+  }
+  lineStart() {
     this._point = 0;
-  },
-  lineEnd: function() {
-    if (this._line === 0) this._string.push("Z");
+  }
+  lineEnd() {
+    if (this._line === 0) this._ += "Z";
     this._point = NaN;
-  },
-  point: function(x, y) {
+  }
+  point(x, y) {
     switch (this._point) {
       case 0: {
-        this._string.push("M", x, ",", y);
+        this._append`M${x},${y}`;
         this._point = 1;
         break;
       }
       case 1: {
-        this._string.push("L", x, ",", y);
+        this._append`L${x},${y}`;
         break;
       }
       default: {
-        if (this._circle == null) this._circle = circle$1(this._radius);
-        this._string.push("M", x, ",", y, this._circle);
+        this._append`M${x},${y}`;
+        if (this._radius !== cacheRadius || this._append !== cacheAppend) {
+          const r = this._radius;
+          const s = this._;
+          this._ = ""; // stash the old string so we can cache the circle path fragment
+          this._append`m0,${r}a${r},${r} 0 1,1 0,${-2 * r}a${r},${r} 0 1,1 0,${2 * r}z`;
+          cacheRadius = r;
+          cacheAppend = this._append;
+          cacheCircle = this._;
+          this._ = s;
+        }
+        this._ += cacheCircle;
         break;
       }
     }
-  },
-  result: function() {
-    if (this._string.length) {
-      var result = this._string.join("");
-      this._string = [];
-      return result;
-    } else {
-      return null;
-    }
   }
-};
-
-function circle$1(radius) {
-  return "m0," + radius
-      + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius
-      + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius
-      + "z";
+  result() {
+    const result = this._;
+    this._ = "";
+    return result.length ? result : null;
+  }
 }
 
-function index$1(projection, context) {
-  var pointRadius = 4.5,
+function append(strings) {
+  let i = 1;
+  this._ += strings[0];
+  for (const j = strings.length; i < j; ++i) {
+    this._ += arguments[i] + strings[i];
+  }
+}
+
+function appendRound(digits) {
+  const d = Math.floor(digits);
+  if (!(d >= 0)) throw new RangeError(`invalid digits: ${digits}`);
+  if (d > 15) return append;
+  if (d !== cacheDigits) {
+    const k = 10 ** d;
+    cacheDigits = d;
+    cacheAppend = function append(strings) {
+      let i = 1;
+      this._ += strings[0];
+      for (const j = strings.length; i < j; ++i) {
+        this._ += Math.round(arguments[i] * k) / k + strings[i];
+      }
+    };
+  }
+  return cacheAppend;
+}
+
+function index$2(projection, context) {
+  let digits = 3,
+      pointRadius = 4.5,
       projectionStream,
       contextStream;
 
@@ -9730,13 +11978,13 @@
   }
 
   path.area = function(object) {
-    geoStream(object, projectionStream(areaStream$1));
-    return areaStream$1.result();
+    geoStream(object, projectionStream(pathArea));
+    return pathArea.result();
   };
 
   path.measure = function(object) {
-    geoStream(object, projectionStream(lengthStream$1));
-    return lengthStream$1.result();
+    geoStream(object, projectionStream(pathMeasure));
+    return pathMeasure.result();
   };
 
   path.bounds = function(object) {
@@ -9745,17 +11993,19 @@
   };
 
   path.centroid = function(object) {
-    geoStream(object, projectionStream(centroidStream$1));
-    return centroidStream$1.result();
+    geoStream(object, projectionStream(pathCentroid));
+    return pathCentroid.result();
   };
 
   path.projection = function(_) {
-    return arguments.length ? (projectionStream = _ == null ? (projection = null, identity$4) : (projection = _).stream, path) : projection;
+    if (!arguments.length) return projection;
+    projectionStream = _ == null ? (projection = null, identity$5) : (projection = _).stream;
+    return path;
   };
 
   path.context = function(_) {
     if (!arguments.length) return context;
-    contextStream = _ == null ? (context = null, new PathString) : new PathContext(context = _);
+    contextStream = _ == null ? (context = null, new PathString(digits)) : new PathContext(context = _);
     if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
     return path;
   };
@@ -9766,16 +12016,28 @@
     return path;
   };
 
-  return path.projection(projection).context(context);
+  path.digits = function(_) {
+    if (!arguments.length) return digits;
+    if (_ == null) digits = null;
+    else {
+      const d = Math.floor(_);
+      if (!(d >= 0)) throw new RangeError(`invalid digits: ${_}`);
+      digits = d;
+    }
+    if (context === null) contextStream = new PathString(digits);
+    return path;
+  };
+
+  return path.projection(projection).digits(digits).context(context);
 }
 
-function transform(methods) {
+function transform$1(methods) {
   return {
-    stream: transformer(methods)
+    stream: transformer$3(methods)
   };
 }
 
-function transformer(methods) {
+function transformer$3(methods) {
   return function(stream) {
     var s = new TransformStream;
     for (var key in methods) s[key] = methods[key];
@@ -9849,7 +12111,7 @@
 }
 
 function resampleNone(project) {
-  return transformer({
+  return transformer$3({
     point: function(x, y) {
       x = project(x, y);
       this.stream.point(x[0], x[1]);
@@ -9867,9 +12129,9 @@
       var a = a0 + a1,
           b = b0 + b1,
           c = c0 + c1,
-          m = sqrt(a * a + b * b + c * c),
-          phi2 = asin(c /= m),
-          lambda2 = abs(abs(c) - 1) < epsilon$2 || abs(lambda0 - lambda1) < epsilon$2 ? (lambda0 + lambda1) / 2 : atan2(b, a),
+          m = sqrt$2(a * a + b * b + c * c),
+          phi2 = asin$1(c /= m),
+          lambda2 = abs$1(abs$1(c) - 1) < epsilon$1 || abs$1(lambda0 - lambda1) < epsilon$1 ? (lambda0 + lambda1) / 2 : atan2$1(b, a),
           p = project(lambda2, phi2),
           x2 = p[0],
           y2 = p[1],
@@ -9877,7 +12139,7 @@
           dy2 = y2 - y0,
           dz = dy * dx2 - dx * dy2;
       if (dz * dz / d2 > delta2 // perpendicular projected distance
-          || abs((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
+          || abs$1((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
           || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance
         resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
         stream.point(x2, y2);
@@ -9940,14 +12202,14 @@
   };
 }
 
-var transformRadians = transformer({
+var transformRadians = transformer$3({
   point: function(x, y) {
     this.stream.point(x * radians, y * radians);
   }
 });
 
 function transformRotate(rotate) {
-  return transformer({
+  return transformer$3({
     point: function(x, y) {
       var r = rotate(x, y);
       return this.stream.point(r[0], r[1]);
@@ -9967,6 +12229,7 @@
 }
 
 function scaleTranslateRotate(k, dx, dy, sx, sy, alpha) {
+  if (!alpha) return scaleTranslate(k, dx, dy, sx, sy);
   var cosAlpha = cos$1(alpha),
       sinAlpha = sin$1(alpha),
       a = cosAlpha * k,
@@ -9999,7 +12262,7 @@
       sx = 1, // reflectX
       sy = 1, // reflectX
       theta = null, preclip = clipAntimeridian, // pre-clip angle
-      x0 = null, y0, x1, y1, postclip = identity$4, // post-clip extent
+      x0 = null, y0, x1, y1, postclip = identity$5, // post-clip extent
       delta2 = 0.5, // precision
       projectResample,
       projectTransform,
@@ -10013,7 +12276,7 @@
 
   function invert(point) {
     point = projectRotateTransform.invert(point[0], point[1]);
-    return point && [point[0] * degrees$1, point[1] * degrees$1];
+    return point && [point[0] * degrees, point[1] * degrees];
   }
 
   projection.stream = function(stream) {
@@ -10029,11 +12292,11 @@
   };
 
   projection.clipAngle = function(_) {
-    return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees$1;
+    return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees;
   };
 
   projection.clipExtent = function(_) {
-    return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$4) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
+    return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$5) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
   };
 
   projection.scale = function(_) {
@@ -10045,15 +12308,15 @@
   };
 
   projection.center = function(_) {
-    return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees$1, phi * degrees$1];
+    return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees, phi * degrees];
   };
 
   projection.rotate = function(_) {
-    return arguments.length ? (deltaLambda = _[0] % 360 * radians, deltaPhi = _[1] % 360 * radians, deltaGamma = _.length > 2 ? _[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees$1, deltaPhi * degrees$1, deltaGamma * degrees$1];
+    return arguments.length ? (deltaLambda = _[0] % 360 * radians, deltaPhi = _[1] % 360 * radians, deltaGamma = _.length > 2 ? _[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees, deltaPhi * degrees, deltaGamma * degrees];
   };
 
   projection.angle = function(_) {
-    return arguments.length ? (alpha = _ % 360 * radians, recenter()) : alpha * degrees$1;
+    return arguments.length ? (alpha = _ % 360 * radians, recenter()) : alpha * degrees;
   };
 
   projection.reflectX = function(_) {
@@ -10065,7 +12328,7 @@
   };
 
   projection.precision = function(_) {
-    return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt(delta2);
+    return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt$2(delta2);
   };
 
   projection.fitExtent = function(extent, object) {
@@ -10086,7 +12349,7 @@
 
   function recenter() {
     var center = scaleTranslateRotate(k, 0, 0, sx, sy, alpha).apply(null, project(lambda, phi)),
-        transform = (alpha ? scaleTranslateRotate : scaleTranslate)(k, x - center[0], y - center[1], sx, sy, alpha);
+        transform = scaleTranslateRotate(k, x - center[0], y - center[1], sx, sy, alpha);
     rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma);
     projectTransform = compose(project, transform);
     projectRotateTransform = compose(rotate, projectTransform);
@@ -10108,12 +12371,12 @@
 
 function conicProjection(projectAt) {
   var phi0 = 0,
-      phi1 = pi$3 / 3,
+      phi1 = pi$1 / 3,
       m = projectionMutator(projectAt),
       p = m(phi0, phi1);
 
   p.parallels = function(_) {
-    return arguments.length ? m(phi0 = _[0] * radians, phi1 = _[1] * radians) : [phi0 * degrees$1, phi1 * degrees$1];
+    return arguments.length ? m(phi0 = _[0] * radians, phi1 = _[1] * radians) : [phi0 * degrees, phi1 * degrees];
   };
 
   return p;
@@ -10127,7 +12390,7 @@
   }
 
   forward.invert = function(x, y) {
-    return [x / cosPhi0, asin(y * cosPhi0)];
+    return [x / cosPhi0, asin$1(y * cosPhi0)];
   };
 
   return forward;
@@ -10137,21 +12400,21 @@
   var sy0 = sin$1(y0), n = (sy0 + sin$1(y1)) / 2;
 
   // Are the parallels symmetrical around the Equator?
-  if (abs(n) < epsilon$2) return cylindricalEqualAreaRaw(y0);
+  if (abs$1(n) < epsilon$1) return cylindricalEqualAreaRaw(y0);
 
-  var c = 1 + sy0 * (2 * n - sy0), r0 = sqrt(c) / n;
+  var c = 1 + sy0 * (2 * n - sy0), r0 = sqrt$2(c) / n;
 
   function project(x, y) {
-    var r = sqrt(c - 2 * n * sin$1(y)) / n;
+    var r = sqrt$2(c - 2 * n * sin$1(y)) / n;
     return [r * sin$1(x *= n), r0 - r * cos$1(x)];
   }
 
   project.invert = function(x, y) {
     var r0y = r0 - y,
-        l = atan2(x, abs(r0y)) * sign(r0y);
+        l = atan2$1(x, abs$1(r0y)) * sign$1(r0y);
     if (r0y * n < 0)
-      l -= pi$3 * sign(x) * sign(r0y);
-    return [l / n, asin((c - (x * x + r0y * r0y) * n * n) / (2 * n))];
+      l -= pi$1 * sign$1(x) * sign$1(r0y);
+    return [l / n, asin$1((c - (x * x + r0y * r0y) * n * n) / (2 * n))];
   };
 
   return project;
@@ -10244,12 +12507,12 @@
 
     alaskaPoint = alaska
         .translate([x - 0.307 * k, y + 0.201 * k])
-        .clipExtent([[x - 0.425 * k + epsilon$2, y + 0.120 * k + epsilon$2], [x - 0.214 * k - epsilon$2, y + 0.234 * k - epsilon$2]])
+        .clipExtent([[x - 0.425 * k + epsilon$1, y + 0.120 * k + epsilon$1], [x - 0.214 * k - epsilon$1, y + 0.234 * k - epsilon$1]])
         .stream(pointStream);
 
     hawaiiPoint = hawaii
         .translate([x - 0.205 * k, y + 0.212 * k])
-        .clipExtent([[x - 0.214 * k + epsilon$2, y + 0.166 * k + epsilon$2], [x - 0.115 * k - epsilon$2, y + 0.234 * k - epsilon$2]])
+        .clipExtent([[x - 0.214 * k + epsilon$1, y + 0.166 * k + epsilon$1], [x - 0.115 * k - epsilon$1, y + 0.234 * k - epsilon$1]])
         .stream(pointStream);
 
     return reset();
@@ -10284,6 +12547,7 @@
     var cx = cos$1(x),
         cy = cos$1(y),
         k = scale(cx * cy);
+        if (k === Infinity) return [2, 0];
     return [
       k * cy * sin$1(x),
       k * sin$1(y)
@@ -10293,23 +12557,23 @@
 
 function azimuthalInvert(angle) {
   return function(x, y) {
-    var z = sqrt(x * x + y * y),
+    var z = sqrt$2(x * x + y * y),
         c = angle(z),
         sc = sin$1(c),
         cc = cos$1(c);
     return [
-      atan2(x * sc, z * cc),
-      asin(z && y * sc / z)
+      atan2$1(x * sc, z * cc),
+      asin$1(z && y * sc / z)
     ];
   }
 }
 
 var azimuthalEqualAreaRaw = azimuthalRaw(function(cxcy) {
-  return sqrt(2 / (1 + cxcy));
+  return sqrt$2(2 / (1 + cxcy));
 });
 
 azimuthalEqualAreaRaw.invert = azimuthalInvert(function(z) {
-  return 2 * asin(z / 2);
+  return 2 * asin$1(z / 2);
 });
 
 function azimuthalEqualArea() {
@@ -10319,7 +12583,7 @@
 }
 
 var azimuthalEquidistantRaw = azimuthalRaw(function(c) {
-  return (c = acos(c)) && c / sin$1(c);
+  return (c = acos$1(c)) && c / sin$1(c);
 });
 
 azimuthalEquidistantRaw.invert = azimuthalInvert(function(z) {
@@ -10333,16 +12597,16 @@
 }
 
 function mercatorRaw(lambda, phi) {
-  return [lambda, log(tan((halfPi$2 + phi) / 2))];
+  return [lambda, log$1(tan((halfPi$1 + phi) / 2))];
 }
 
 mercatorRaw.invert = function(x, y) {
-  return [x, 2 * atan(exp(y)) - halfPi$2];
+  return [x, 2 * atan(exp(y)) - halfPi$1];
 };
 
 function mercator() {
   return mercatorProjection(mercatorRaw)
-      .scale(961 / tau$3);
+      .scale(961 / tau$1);
 }
 
 function mercatorProjection(project) {
@@ -10370,7 +12634,7 @@
   };
 
   function reclip() {
-    var k = pi$3 * scale(),
+    var k = pi$1 * scale(),
         t = m(rotation(m.rotate()).invert([0, 0]));
     return clipExtent(x0 == null
         ? [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]] : project === mercatorRaw
@@ -10382,29 +12646,29 @@
 }
 
 function tany(y) {
-  return tan((halfPi$2 + y) / 2);
+  return tan((halfPi$1 + y) / 2);
 }
 
 function conicConformalRaw(y0, y1) {
   var cy0 = cos$1(y0),
-      n = y0 === y1 ? sin$1(y0) : log(cy0 / cos$1(y1)) / log(tany(y1) / tany(y0)),
-      f = cy0 * pow(tany(y0), n) / n;
+      n = y0 === y1 ? sin$1(y0) : log$1(cy0 / cos$1(y1)) / log$1(tany(y1) / tany(y0)),
+      f = cy0 * pow$1(tany(y0), n) / n;
 
   if (!n) return mercatorRaw;
 
   function project(x, y) {
-    if (f > 0) { if (y < -halfPi$2 + epsilon$2) y = -halfPi$2 + epsilon$2; }
-    else { if (y > halfPi$2 - epsilon$2) y = halfPi$2 - epsilon$2; }
-    var r = f / pow(tany(y), n);
+    if (f > 0) { if (y < -halfPi$1 + epsilon$1) y = -halfPi$1 + epsilon$1; }
+    else { if (y > halfPi$1 - epsilon$1) y = halfPi$1 - epsilon$1; }
+    var r = f / pow$1(tany(y), n);
     return [r * sin$1(n * x), f - r * cos$1(n * x)];
   }
 
   project.invert = function(x, y) {
-    var fy = f - y, r = sign(n) * sqrt(x * x + fy * fy),
-      l = atan2(x, abs(fy)) * sign(fy);
+    var fy = f - y, r = sign$1(n) * sqrt$2(x * x + fy * fy),
+      l = atan2$1(x, abs$1(fy)) * sign$1(fy);
     if (fy * n < 0)
-      l -= pi$3 * sign(x) * sign(fy);
-    return [l / n, 2 * atan(pow(f / r, 1 / n)) - halfPi$2];
+      l -= pi$1 * sign$1(x) * sign$1(fy);
+    return [l / n, 2 * atan(pow$1(f / r, 1 / n)) - halfPi$1];
   };
 
   return project;
@@ -10432,7 +12696,7 @@
       n = y0 === y1 ? sin$1(y0) : (cy0 - cos$1(y1)) / (y1 - y0),
       g = cy0 / n + y0;
 
-  if (abs(n) < epsilon$2) return equirectangularRaw;
+  if (abs$1(n) < epsilon$1) return equirectangularRaw;
 
   function project(x, y) {
     var gy = g - y, nx = n * x;
@@ -10441,10 +12705,10 @@
 
   project.invert = function(x, y) {
     var gy = g - y,
-        l = atan2(x, abs(gy)) * sign(gy);
+        l = atan2$1(x, abs$1(gy)) * sign$1(gy);
     if (gy * n < 0)
-      l -= pi$3 * sign(x) * sign(gy);
-    return [l / n, g - sign(n) * sqrt(x * x + gy * gy)];
+      l -= pi$1 * sign$1(x) * sign$1(gy);
+    return [l / n, g - sign$1(n) * sqrt$2(x * x + gy * gy)];
   };
 
   return project;
@@ -10460,11 +12724,11 @@
     A2 = -0.081106,
     A3 = 0.000893,
     A4 = 0.003796,
-    M = sqrt(3) / 2,
+    M = sqrt$2(3) / 2,
     iterations = 12;
 
 function equalEarthRaw(lambda, phi) {
-  var l = asin(M * sin$1(phi)), l2 = l * l, l6 = l2 * l2 * l2;
+  var l = asin$1(M * sin$1(phi)), l2 = l * l, l6 = l2 * l2 * l2;
   return [
     lambda * cos$1(l) / (M * (A1 + 3 * A2 * l2 + l6 * (7 * A3 + 9 * A4 * l2))),
     l * (A1 + A2 * l2 + l6 * (A3 + A4 * l2))
@@ -10477,11 +12741,11 @@
     fy = l * (A1 + A2 * l2 + l6 * (A3 + A4 * l2)) - y;
     fpy = A1 + 3 * A2 * l2 + l6 * (7 * A3 + 9 * A4 * l2);
     l -= delta = fy / fpy, l2 = l * l, l6 = l2 * l2 * l2;
-    if (abs(delta) < epsilon2$1) break;
+    if (abs$1(delta) < epsilon2) break;
   }
   return [
     M * x * (A1 + 3 * A2 * l2 + l6 * (7 * A3 + 9 * A4 * l2)) / cos$1(l),
-    asin(sin$1(l) / M)
+    asin$1(sin$1(l) / M)
   ];
 };
 
@@ -10503,18 +12767,18 @@
       .clipAngle(60);
 }
 
-function identity$5() {
+function identity$4() {
   var k = 1, tx = 0, ty = 0, sx = 1, sy = 1, // scale, translate and reflect
       alpha = 0, ca, sa, // angle
       x0 = null, y0, x1, y1, // clip extent
       kx = 1, ky = 1,
-      transform = transformer({
+      transform = transformer$3({
         point: function(x, y) {
           var p = projection([x, y]);
           this.stream.point(p[0], p[1]);
         }
       }),
-      postclip = identity$4,
+      postclip = identity$5,
       cache,
       cacheStream;
 
@@ -10550,7 +12814,7 @@
     return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip;
   };
   projection.clipExtent = function(_) {
-    return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$4) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
+    return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$5) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
   };
   projection.scale = function(_) {
     return arguments.length ? (k = +_, reset()) : k;
@@ -10559,7 +12823,7 @@
     return arguments.length ? (tx = +_[0], ty = +_[1], reset()) : [tx, ty];
   };
   projection.angle = function(_) {
-    return arguments.length ? (alpha = _ % 360 * radians, sa = sin$1(alpha), ca = cos$1(alpha), reset()) : alpha * degrees$1;
+    return arguments.length ? (alpha = _ % 360 * radians, sa = sin$1(alpha), ca = cos$1(alpha), reset()) : alpha * degrees;
   };
   projection.reflectX = function(_) {
     return arguments.length ? (sx = _ ? -1 : 1, reset()) : sx < 0;
@@ -10597,7 +12861,7 @@
     var phi2 = phi * phi, phi4 = phi2 * phi2;
     phi -= delta = (phi * (1.007226 + phi2 * (0.015085 + phi4 * (-0.044475 + 0.028874 * phi2 - 0.005916 * phi4))) - y) /
         (1.007226 + phi2 * (0.015085 * 3 + phi4 * (-0.044475 * 7 + 0.028874 * 9 * phi2 - 0.005916 * 11 * phi4)));
-  } while (abs(delta) > epsilon$2 && --i > 0);
+  } while (abs$1(delta) > epsilon$1 && --i > 0);
   return [
     x / (0.8707 + (phi2 = phi * phi) * (-0.131979 + phi2 * (-0.013791 + phi2 * phi2 * phi2 * (0.003971 - 0.001529 * phi2)))),
     phi
@@ -10613,12 +12877,12 @@
   return [cos$1(y) * sin$1(x), sin$1(y)];
 }
 
-orthographicRaw.invert = azimuthalInvert(asin);
+orthographicRaw.invert = azimuthalInvert(asin$1);
 
 function orthographic() {
   return projection(orthographicRaw)
       .scale(249.5)
-      .clipAngle(90 + epsilon$2);
+      .clipAngle(90 + epsilon$1);
 }
 
 function stereographicRaw(x, y) {
@@ -10637,11 +12901,11 @@
 }
 
 function transverseMercatorRaw(lambda, phi) {
-  return [log(tan((halfPi$2 + phi) / 2)), -lambda];
+  return [log$1(tan((halfPi$1 + phi) / 2)), -lambda];
 }
 
 transverseMercatorRaw.invert = function(x, y) {
-  return [-y, 2 * atan(exp(x)) - halfPi$2];
+  return [-y, 2 * atan(exp(x)) - halfPi$1];
 };
 
 function transverseMercator() {
@@ -10661,7 +12925,7 @@
       .scale(159.155);
 }
 
-function defaultSeparation(a, b) {
+function defaultSeparation$1(a, b) {
   return a.parent === b.parent ? 1 : 2;
 }
 
@@ -10694,7 +12958,7 @@
 }
 
 function cluster() {
-  var separation = defaultSeparation,
+  var separation = defaultSeparation$1,
       dx = 1,
       dy = 1,
       nodeSize = false;
@@ -10759,45 +13023,52 @@
   return this.eachAfter(count);
 }
 
-function node_each(callback) {
-  var node = this, current, next = [node], children, i, n;
-  do {
-    current = next.reverse(), next = [];
-    while (node = current.pop()) {
-      callback(node), children = node.children;
-      if (children) for (i = 0, n = children.length; i < n; ++i) {
-        next.push(children[i]);
-      }
-    }
-  } while (next.length);
+function node_each(callback, that) {
+  let index = -1;
+  for (const node of this) {
+    callback.call(that, node, ++index, this);
+  }
   return this;
 }
 
-function node_eachBefore(callback) {
-  var node = this, nodes = [node], children, i;
+function node_eachBefore(callback, that) {
+  var node = this, nodes = [node], children, i, index = -1;
   while (node = nodes.pop()) {
-    callback(node), children = node.children;
-    if (children) for (i = children.length - 1; i >= 0; --i) {
-      nodes.push(children[i]);
+    callback.call(that, node, ++index, this);
+    if (children = node.children) {
+      for (i = children.length - 1; i >= 0; --i) {
+        nodes.push(children[i]);
+      }
     }
   }
   return this;
 }
 
-function node_eachAfter(callback) {
-  var node = this, nodes = [node], next = [], children, i, n;
+function node_eachAfter(callback, that) {
+  var node = this, nodes = [node], next = [], children, i, n, index = -1;
   while (node = nodes.pop()) {
-    next.push(node), children = node.children;
-    if (children) for (i = 0, n = children.length; i < n; ++i) {
-      nodes.push(children[i]);
+    next.push(node);
+    if (children = node.children) {
+      for (i = 0, n = children.length; i < n; ++i) {
+        nodes.push(children[i]);
+      }
     }
   }
   while (node = next.pop()) {
-    callback(node);
+    callback.call(that, node, ++index, this);
   }
   return this;
 }
 
+function node_find(callback, that) {
+  let index = -1;
+  for (const node of this) {
+    if (callback.call(that, node, ++index, this)) {
+      return node;
+    }
+  }
+}
+
 function node_sum(value) {
   return this.eachAfter(function(node) {
     var sum = +value(node.data) || 0,
@@ -10856,11 +13127,7 @@
 }
 
 function node_descendants() {
-  var nodes = [];
-  this.each(function(node) {
-    nodes.push(node);
-  });
-  return nodes;
+  return Array.from(this);
 }
 
 function node_leaves() {
@@ -10883,9 +13150,30 @@
   return links;
 }
 
+function* node_iterator() {
+  var node = this, current, next = [node], children, i, n;
+  do {
+    current = next.reverse(), next = [];
+    while (node = current.pop()) {
+      yield node;
+      if (children = node.children) {
+        for (i = 0, n = children.length; i < n; ++i) {
+          next.push(children[i]);
+        }
+      }
+    }
+  } while (next.length);
+}
+
 function hierarchy(data, children) {
-  var root = new Node(data),
-      valued = +data.value && (root.value = data.value),
+  if (data instanceof Map) {
+    data = [undefined, data];
+    if (children === undefined) children = mapChildren;
+  } else if (children === undefined) {
+    children = objectChildren;
+  }
+
+  var root = new Node$1(data),
       node,
       nodes = [root],
       child,
@@ -10893,14 +13181,11 @@
       i,
       n;
 
-  if (children == null) children = defaultChildren;
-
   while (node = nodes.pop()) {
-    if (valued) node.value = +node.data.value;
-    if ((childs = children(node.data)) && (n = childs.length)) {
-      node.children = new Array(n);
+    if ((childs = children(node.data)) && (n = (childs = Array.from(childs)).length)) {
+      node.children = childs;
       for (i = n - 1; i >= 0; --i) {
-        nodes.push(child = node.children[i] = new Node(childs[i]));
+        nodes.push(child = childs[i] = new Node$1(childs[i]));
         child.parent = node;
         child.depth = node.depth + 1;
       }
@@ -10914,11 +13199,16 @@
   return hierarchy(this).eachBefore(copyData);
 }
 
-function defaultChildren(d) {
+function objectChildren(d) {
   return d.children;
 }
 
+function mapChildren(d) {
+  return Array.isArray(d) ? d[1] : null;
+}
+
 function copyData(node) {
+  if (node.data.value !== undefined) node.value = node.data.value;
   node.data = node.data.data;
 }
 
@@ -10928,19 +13218,20 @@
   while ((node = node.parent) && (node.height < ++height));
 }
 
-function Node(data) {
+function Node$1(data) {
   this.data = data;
   this.depth =
   this.height = 0;
   this.parent = null;
 }
 
-Node.prototype = hierarchy.prototype = {
-  constructor: Node,
+Node$1.prototype = hierarchy.prototype = {
+  constructor: Node$1,
   count: node_count,
   each: node_each,
   eachAfter: node_eachAfter,
   eachBefore: node_eachBefore,
+  find: node_find,
   sum: node_sum,
   sort: node_sort,
   path: node_path,
@@ -10948,18 +13239,52 @@
   descendants: node_descendants,
   leaves: node_leaves,
   links: node_links,
-  copy: node_copy
+  copy: node_copy,
+  [Symbol.iterator]: node_iterator
 };
 
-var slice$4 = Array.prototype.slice;
+function optional(f) {
+  return f == null ? null : required(f);
+}
 
-function shuffle$1(array) {
-  var m = array.length,
+function required(f) {
+  if (typeof f !== "function") throw new Error;
+  return f;
+}
+
+function constantZero() {
+  return 0;
+}
+
+function constant$2(x) {
+  return function() {
+    return x;
+  };
+}
+
+// https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use
+const a$1 = 1664525;
+const c$3 = 1013904223;
+const m = 4294967296; // 2^32
+
+function lcg$1() {
+  let s = 1;
+  return () => (s = (a$1 * s + c$3) % m) / m;
+}
+
+function array$1(x) {
+  return typeof x === "object" && "length" in x
+    ? x // Array, TypedArray, NodeList, array-like
+    : Array.from(x); // Map, Set, iterable, string, or anything else
+}
+
+function shuffle(array, random) {
+  let m = array.length,
       t,
       i;
 
   while (m) {
-    i = Math.random() * m-- | 0;
+    i = random() * m-- | 0;
     t = array[m];
     array[m] = array[i];
     array[i] = t;
@@ -10969,7 +13294,11 @@
 }
 
 function enclose(circles) {
-  var i = 0, n = (circles = shuffle$1(slice$4.call(circles))).length, B = [], p, e;
+  return packEncloseRandom(circles, lcg$1());
+}
+
+function packEncloseRandom(circles, random) {
+  var i = 0, n = (circles = shuffle(Array.from(circles), random)).length, B = [], p, e;
 
   while (i < n) {
     p = circles[i];
@@ -11015,7 +13344,7 @@
 }
 
 function enclosesWeak(a, b) {
-  var dr = a.r - b.r + 1e-6, dx = b.x - a.x, dy = b.y - a.y;
+  var dr = a.r - b.r + Math.max(a.r, b.r, 1) * 1e-9, dx = b.x - a.x, dy = b.y - a.y;
   return dr > 0 && dr * dr > dx * dx + dy * dy;
 }
 
@@ -11077,7 +13406,7 @@
       A = xb * xb + yb * yb - 1,
       B = 2 * (r1 + xa * xb + ya * yb),
       C = xa * xa + ya * ya - r1 * r1,
-      r = -(A ? (B + Math.sqrt(B * B - 4 * A * C)) / (2 * A) : C / B);
+      r = -(Math.abs(A) > 1e-6 ? (B + Math.sqrt(B * B - 4 * A * C)) / (2 * A) : C / B);
   return {
     x: x1 + xa + xb * r,
     y: y1 + ya + yb * r,
@@ -11123,14 +13452,14 @@
   return dx * dx + dy * dy;
 }
 
-function Node$1(circle) {
+function Node(circle) {
   this._ = circle;
   this.next = null;
   this.previous = null;
 }
 
-function packEnclose(circles) {
-  if (!(n = circles.length)) return 0;
+function packSiblingsRandom(circles, random) {
+  if (!(n = (circles = array$1(circles)).length)) return 0;
 
   var a, b, c, n, aa, ca, i, j, k, sj, sk;
 
@@ -11146,14 +13475,14 @@
   place(b, a, c = circles[2]);
 
   // Initialize the front-chain using the first three circles a, b and c.
-  a = new Node$1(a), b = new Node$1(b), c = new Node$1(c);
+  a = new Node(a), b = new Node(b), c = new Node(c);
   a.next = c.previous = b;
   b.next = a.previous = c;
   c.next = b.previous = a;
 
   // Attempt to place each remaining circle…
   pack: for (i = 3; i < n; ++i) {
-    place(a._, b._, c = circles[i]), c = new Node$1(c);
+    place(a._, b._, c = circles[i]), c = new Node(c);
 
     // Find the closest intersecting circle on the front-chain, if any.
     // “Closeness” is determined by linear distance along the front-chain.
@@ -11189,7 +13518,7 @@
   }
 
   // Compute the enclosing circle of the front chain.
-  a = [b._], c = b; while ((c = c.next) !== b) a.push(c._); c = enclose(a);
+  a = [b._], c = b; while ((c = c.next) !== b) a.push(c._); c = packEncloseRandom(a, random);
 
   // Translate the circles to put the enclosing circle around the origin.
   for (i = 0; i < n; ++i) a = circles[i], a.x -= c.x, a.y -= c.y;
@@ -11198,49 +13527,31 @@
 }
 
 function siblings(circles) {
-  packEnclose(circles);
+  packSiblingsRandom(circles, lcg$1());
   return circles;
 }
 
-function optional(f) {
-  return f == null ? null : required(f);
-}
-
-function required(f) {
-  if (typeof f !== "function") throw new Error;
-  return f;
-}
-
-function constantZero() {
-  return 0;
-}
-
-function constant$9(x) {
-  return function() {
-    return x;
-  };
-}
-
-function defaultRadius$1(d) {
+function defaultRadius(d) {
   return Math.sqrt(d.value);
 }
 
-function index$2() {
+function index$1() {
   var radius = null,
       dx = 1,
       dy = 1,
       padding = constantZero;
 
   function pack(root) {
+    const random = lcg$1();
     root.x = dx / 2, root.y = dy / 2;
     if (radius) {
       root.eachBefore(radiusLeaf(radius))
-          .eachAfter(packChildren(padding, 0.5))
+          .eachAfter(packChildrenRandom(padding, 0.5, random))
           .eachBefore(translateChild(1));
     } else {
-      root.eachBefore(radiusLeaf(defaultRadius$1))
-          .eachAfter(packChildren(constantZero, 1))
-          .eachAfter(packChildren(padding, root.r / Math.min(dx, dy)))
+      root.eachBefore(radiusLeaf(defaultRadius))
+          .eachAfter(packChildrenRandom(constantZero, 1, random))
+          .eachAfter(packChildrenRandom(padding, root.r / Math.min(dx, dy), random))
           .eachBefore(translateChild(Math.min(dx, dy) / (2 * root.r)));
     }
     return root;
@@ -11255,7 +13566,7 @@
   };
 
   pack.padding = function(x) {
-    return arguments.length ? (padding = typeof x === "function" ? x : constant$9(+x), pack) : padding;
+    return arguments.length ? (padding = typeof x === "function" ? x : constant$2(+x), pack) : padding;
   };
 
   return pack;
@@ -11269,7 +13580,7 @@
   };
 }
 
-function packChildren(padding, k) {
+function packChildrenRandom(padding, k, random) {
   return function(node) {
     if (children = node.children) {
       var children,
@@ -11279,7 +13590,7 @@
           e;
 
       if (r) for (i = 0; i < n; ++i) children[i].r += r;
-      e = packEnclose(children);
+      e = packSiblingsRandom(children, random);
       if (r) for (i = 0; i < n; ++i) children[i].r -= r;
       node.r = e + r;
     }
@@ -11367,9 +13678,9 @@
   return partition;
 }
 
-var keyPrefix$1 = "$", // Protect against keys like “__proto__”.
-    preroot = {depth: -1},
-    ambiguous = {};
+var preroot = {depth: -1},
+    ambiguous = {},
+    imputed = {};
 
 function defaultId(d) {
   return d.id;
@@ -11381,44 +13692,80 @@
 
 function stratify() {
   var id = defaultId,
-      parentId = defaultParentId;
+      parentId = defaultParentId,
+      path;
 
   function stratify(data) {
-    var d,
+    var nodes = Array.from(data),
+        currentId = id,
+        currentParentId = parentId,
+        n,
+        d,
         i,
-        n = data.length,
         root,
         parent,
         node,
-        nodes = new Array(n),
         nodeId,
         nodeKey,
-        nodeByKey = {};
+        nodeByKey = new Map;
 
-    for (i = 0; i < n; ++i) {
-      d = data[i], node = nodes[i] = new Node(d);
-      if ((nodeId = id(d, i, data)) != null && (nodeId += "")) {
-        nodeKey = keyPrefix$1 + (node.id = nodeId);
-        nodeByKey[nodeKey] = nodeKey in nodeByKey ? ambiguous : node;
+    if (path != null) {
+      const I = nodes.map((d, i) => normalize$1(path(d, i, data)));
+      const P = I.map(parentof);
+      const S = new Set(I).add("");
+      for (const i of P) {
+        if (!S.has(i)) {
+          S.add(i);
+          I.push(i);
+          P.push(parentof(i));
+          nodes.push(imputed);
+        }
+      }
+      currentId = (_, i) => I[i];
+      currentParentId = (_, i) => P[i];
+    }
+
+    for (i = 0, n = nodes.length; i < n; ++i) {
+      d = nodes[i], node = nodes[i] = new Node$1(d);
+      if ((nodeId = currentId(d, i, data)) != null && (nodeId += "")) {
+        nodeKey = node.id = nodeId;
+        nodeByKey.set(nodeKey, nodeByKey.has(nodeKey) ? ambiguous : node);
+      }
+      if ((nodeId = currentParentId(d, i, data)) != null && (nodeId += "")) {
+        node.parent = nodeId;
       }
     }
 
     for (i = 0; i < n; ++i) {
-      node = nodes[i], nodeId = parentId(data[i], i, data);
-      if (nodeId == null || !(nodeId += "")) {
-        if (root) throw new Error("multiple roots");
-        root = node;
-      } else {
-        parent = nodeByKey[keyPrefix$1 + nodeId];
+      node = nodes[i];
+      if (nodeId = node.parent) {
+        parent = nodeByKey.get(nodeId);
         if (!parent) throw new Error("missing: " + nodeId);
         if (parent === ambiguous) throw new Error("ambiguous: " + nodeId);
         if (parent.children) parent.children.push(node);
         else parent.children = [node];
         node.parent = parent;
+      } else {
+        if (root) throw new Error("multiple roots");
+        root = node;
       }
     }
 
     if (!root) throw new Error("no root");
+
+    // When imputing internal nodes, only introduce roots if needed.
+    // Then replace the imputed marker data with null.
+    if (path != null) {
+      while (root.data === imputed && root.children.length === 1) {
+        root = root.children[0], --n;
+      }
+      for (let i = nodes.length - 1; i >= 0; --i) {
+        node = nodes[i];
+        if (node.data !== imputed) break;
+        node.data = null;
+      }
+    }
+
     root.parent = preroot;
     root.eachBefore(function(node) { node.depth = node.parent.depth + 1; --n; }).eachBefore(computeHeight);
     root.parent = null;
@@ -11428,17 +13775,53 @@
   }
 
   stratify.id = function(x) {
-    return arguments.length ? (id = required(x), stratify) : id;
+    return arguments.length ? (id = optional(x), stratify) : id;
   };
 
   stratify.parentId = function(x) {
-    return arguments.length ? (parentId = required(x), stratify) : parentId;
+    return arguments.length ? (parentId = optional(x), stratify) : parentId;
+  };
+
+  stratify.path = function(x) {
+    return arguments.length ? (path = optional(x), stratify) : path;
   };
 
   return stratify;
 }
 
-function defaultSeparation$1(a, b) {
+// To normalize a path, we coerce to a string, strip the trailing slash if any
+// (as long as the trailing slash is not immediately preceded by another slash),
+// and add leading slash if missing.
+function normalize$1(path) {
+  path = `${path}`;
+  let i = path.length;
+  if (slash(path, i - 1) && !slash(path, i - 2)) path = path.slice(0, -1);
+  return path[0] === "/" ? path : `/${path}`;
+}
+
+// Walk backwards to find the first slash that is not the leading slash, e.g.:
+// "/foo/bar" ⇥ "/foo", "/foo" ⇥ "/", "/" ↦ "". (The root is special-cased
+// because the id of the root must be a truthy value.)
+function parentof(path) {
+  let i = path.length;
+  if (i < 2) return "";
+  while (--i > 1) if (slash(path, i)) break;
+  return path.slice(0, i);
+}
+
+// Slashes can be escaped; to determine whether a slash is a path delimiter, we
+// count the number of preceding backslashes escaping the forward slash: an odd
+// number indicates an escaped forward slash.
+function slash(path, i) {
+  if (path[i] === "/") {
+    let k = 0;
+    while (i > 0 && path[--i] === "\\") ++k;
+    if ((k & 1) === 0) return true;
+  }
+  return false;
+}
+
+function defaultSeparation(a, b) {
   return a.parent === b.parent ? 1 : 2;
 }
 
@@ -11509,7 +13892,7 @@
   this.i = i; // number
 }
 
-TreeNode.prototype = Object.create(Node.prototype);
+TreeNode.prototype = Object.create(Node$1.prototype);
 
 function treeRoot(root) {
   var tree = new TreeNode(root, 0),
@@ -11536,7 +13919,7 @@
 
 // Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
 function tree() {
-  var separation = defaultSeparation$1,
+  var separation = defaultSeparation,
       dx = 1,
       dy = 1,
       nodeSize = null;
@@ -11751,7 +14134,7 @@
   return squarify;
 })(phi);
 
-function index$3() {
+function index() {
   var tile = squarify,
       round = false,
       dx = 1,
@@ -11815,7 +14198,7 @@
   };
 
   treemap.paddingInner = function(x) {
-    return arguments.length ? (paddingInner = typeof x === "function" ? x : constant$9(+x), treemap) : paddingInner;
+    return arguments.length ? (paddingInner = typeof x === "function" ? x : constant$2(+x), treemap) : paddingInner;
   };
 
   treemap.paddingOuter = function(x) {
@@ -11823,19 +14206,19 @@
   };
 
   treemap.paddingTop = function(x) {
-    return arguments.length ? (paddingTop = typeof x === "function" ? x : constant$9(+x), treemap) : paddingTop;
+    return arguments.length ? (paddingTop = typeof x === "function" ? x : constant$2(+x), treemap) : paddingTop;
   };
 
   treemap.paddingRight = function(x) {
-    return arguments.length ? (paddingRight = typeof x === "function" ? x : constant$9(+x), treemap) : paddingRight;
+    return arguments.length ? (paddingRight = typeof x === "function" ? x : constant$2(+x), treemap) : paddingRight;
   };
 
   treemap.paddingBottom = function(x) {
-    return arguments.length ? (paddingBottom = typeof x === "function" ? x : constant$9(+x), treemap) : paddingBottom;
+    return arguments.length ? (paddingBottom = typeof x === "function" ? x : constant$2(+x), treemap) : paddingBottom;
   };
 
   treemap.paddingLeft = function(x) {
-    return arguments.length ? (paddingLeft = typeof x === "function" ? x : constant$9(+x), treemap) : paddingLeft;
+    return arguments.length ? (paddingLeft = typeof x === "function" ? x : constant$2(+x), treemap) : paddingLeft;
   };
 
   return treemap;
@@ -11877,11 +14260,11 @@
         valueRight = value - valueLeft;
 
     if ((x1 - x0) > (y1 - y0)) {
-      var xk = (x0 * valueRight + x1 * valueLeft) / value;
+      var xk = value ? (x0 * valueRight + x1 * valueLeft) / value : x1;
       partition(i, k, valueLeft, x0, y0, xk, y1);
       partition(k, j, valueRight, xk, y0, x1, y1);
     } else {
-      var yk = (y0 * valueRight + y1 * valueLeft) / value;
+      var yk = value ? (y0 * valueRight + y1 * valueLeft) / value : y1;
       partition(i, k, valueLeft, x0, y0, x1, yk);
       partition(k, j, valueRight, x0, yk, x1, y1);
     }
@@ -11908,8 +14291,8 @@
       while (++j < m) {
         row = rows[j], nodes = row.children;
         for (i = row.value = 0, n = nodes.length; i < n; ++i) row.value += nodes[i].value;
-        if (row.dice) treemapDice(row, x0, y0, x1, y0 += (y1 - y0) * row.value / value);
-        else treemapSlice(row, x0, y0, x0 += (x1 - x0) * row.value / value, y1);
+        if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += (y1 - y0) * row.value / value : y1);
+        else treemapSlice(row, x0, y0, value ? x0 += (x1 - x0) * row.value / value : x1, y1);
         value -= row.value;
       }
     } else {
@@ -11925,7 +14308,7 @@
   return resquarify;
 })(phi);
 
-function area$2(polygon) {
+function area$1(polygon) {
   var i = -1,
       n = polygon.length,
       a,
@@ -11941,7 +14324,7 @@
   return area / 2;
 }
 
-function centroid$1(polygon) {
+function centroid(polygon) {
   var i = -1,
       n = polygon.length,
       x = 0,
@@ -11978,11 +14361,11 @@
 // Assumes points.length >= 3, is sorted by x, unique in y.
 // Returns an array of indices into points in left-to-right order.
 function computeUpperHullIndexes(points) {
-  var n = points.length,
-      indexes = [0, 1],
-      size = 2;
+  const n = points.length,
+      indexes = [0, 1];
+  let size = 2, i;
 
-  for (var i = 2; i < n; ++i) {
+  for (i = 2; i < n; ++i) {
     while (size > 1 && cross$1(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) --size;
     indexes[size++] = i;
   }
@@ -12018,7 +14401,7 @@
   return hull;
 }
 
-function contains$2(polygon, point) {
+function contains(polygon, point) {
   var n = polygon.length,
       p = polygon[n - 1],
       x = point[0], y = point[1],
@@ -12035,7 +14418,7 @@
   return inside;
 }
 
-function length$2(polygon) {
+function length(polygon) {
   var i = -1,
       n = polygon.length,
       b = polygon[n - 1],
@@ -12053,15 +14436,13 @@
     yb = b[1];
     xa -= xb;
     ya -= yb;
-    perimeter += Math.sqrt(xa * xa + ya * ya);
+    perimeter += Math.hypot(xa, ya);
   }
 
   return perimeter;
 }
 
-function defaultSource$1() {
-  return Math.random();
-}
+var defaultSource = Math.random;
 
 var uniform = (function sourceRandomUniform(source) {
   function randomUniform(min, max) {
@@ -12077,7 +14458,22 @@
   randomUniform.source = sourceRandomUniform;
 
   return randomUniform;
-})(defaultSource$1);
+})(defaultSource);
+
+var int = (function sourceRandomInt(source) {
+  function randomInt(min, max) {
+    if (arguments.length < 2) max = min, min = 0;
+    min = Math.floor(min);
+    max = Math.floor(max) - min;
+    return function() {
+      return Math.floor(source() * max + min);
+    };
+  }
+
+  randomInt.source = sourceRandomInt;
+
+  return randomInt;
+})(defaultSource);
 
 var normal = (function sourceRandomNormal(source) {
   function randomNormal(mu, sigma) {
@@ -12104,11 +14500,13 @@
   randomNormal.source = sourceRandomNormal;
 
   return randomNormal;
-})(defaultSource$1);
+})(defaultSource);
 
 var logNormal = (function sourceRandomLogNormal(source) {
+  var N = normal.source(source);
+
   function randomLogNormal() {
-    var randomNormal = normal.source(source).apply(this, arguments);
+    var randomNormal = N.apply(this, arguments);
     return function() {
       return Math.exp(randomNormal());
     };
@@ -12117,24 +14515,29 @@
   randomLogNormal.source = sourceRandomLogNormal;
 
   return randomLogNormal;
-})(defaultSource$1);
+})(defaultSource);
 
 var irwinHall = (function sourceRandomIrwinHall(source) {
   function randomIrwinHall(n) {
+    if ((n = +n) <= 0) return () => 0;
     return function() {
-      for (var sum = 0, i = 0; i < n; ++i) sum += source();
-      return sum;
+      for (var sum = 0, i = n; i > 1; --i) sum += source();
+      return sum + i * source();
     };
   }
 
   randomIrwinHall.source = sourceRandomIrwinHall;
 
   return randomIrwinHall;
-})(defaultSource$1);
+})(defaultSource);
 
 var bates = (function sourceRandomBates(source) {
+  var I = irwinHall.source(source);
+
   function randomBates(n) {
-    var randomIrwinHall = irwinHall.source(source)(n);
+    // use limiting distribution at n === 0
+    if ((n = +n) === 0) return source;
+    var randomIrwinHall = I(n);
     return function() {
       return randomIrwinHall() / n;
     };
@@ -12143,19 +14546,230 @@
   randomBates.source = sourceRandomBates;
 
   return randomBates;
-})(defaultSource$1);
+})(defaultSource);
 
-var exponential$1 = (function sourceRandomExponential(source) {
+var exponential = (function sourceRandomExponential(source) {
   function randomExponential(lambda) {
     return function() {
-      return -Math.log(1 - source()) / lambda;
+      return -Math.log1p(-source()) / lambda;
     };
   }
 
   randomExponential.source = sourceRandomExponential;
 
   return randomExponential;
-})(defaultSource$1);
+})(defaultSource);
+
+var pareto = (function sourceRandomPareto(source) {
+  function randomPareto(alpha) {
+    if ((alpha = +alpha) < 0) throw new RangeError("invalid alpha");
+    alpha = 1 / -alpha;
+    return function() {
+      return Math.pow(1 - source(), alpha);
+    };
+  }
+
+  randomPareto.source = sourceRandomPareto;
+
+  return randomPareto;
+})(defaultSource);
+
+var bernoulli = (function sourceRandomBernoulli(source) {
+  function randomBernoulli(p) {
+    if ((p = +p) < 0 || p > 1) throw new RangeError("invalid p");
+    return function() {
+      return Math.floor(source() + p);
+    };
+  }
+
+  randomBernoulli.source = sourceRandomBernoulli;
+
+  return randomBernoulli;
+})(defaultSource);
+
+var geometric = (function sourceRandomGeometric(source) {
+  function randomGeometric(p) {
+    if ((p = +p) < 0 || p > 1) throw new RangeError("invalid p");
+    if (p === 0) return () => Infinity;
+    if (p === 1) return () => 1;
+    p = Math.log1p(-p);
+    return function() {
+      return 1 + Math.floor(Math.log1p(-source()) / p);
+    };
+  }
+
+  randomGeometric.source = sourceRandomGeometric;
+
+  return randomGeometric;
+})(defaultSource);
+
+var gamma = (function sourceRandomGamma(source) {
+  var randomNormal = normal.source(source)();
+
+  function randomGamma(k, theta) {
+    if ((k = +k) < 0) throw new RangeError("invalid k");
+    // degenerate distribution if k === 0
+    if (k === 0) return () => 0;
+    theta = theta == null ? 1 : +theta;
+    // exponential distribution if k === 1
+    if (k === 1) return () => -Math.log1p(-source()) * theta;
+
+    var d = (k < 1 ? k + 1 : k) - 1 / 3,
+        c = 1 / (3 * Math.sqrt(d)),
+        multiplier = k < 1 ? () => Math.pow(source(), 1 / k) : () => 1;
+    return function() {
+      do {
+        do {
+          var x = randomNormal(),
+              v = 1 + c * x;
+        } while (v <= 0);
+        v *= v * v;
+        var u = 1 - source();
+      } while (u >= 1 - 0.0331 * x * x * x * x && Math.log(u) >= 0.5 * x * x + d * (1 - v + Math.log(v)));
+      return d * v * multiplier() * theta;
+    };
+  }
+
+  randomGamma.source = sourceRandomGamma;
+
+  return randomGamma;
+})(defaultSource);
+
+var beta = (function sourceRandomBeta(source) {
+  var G = gamma.source(source);
+
+  function randomBeta(alpha, beta) {
+    var X = G(alpha),
+        Y = G(beta);
+    return function() {
+      var x = X();
+      return x === 0 ? 0 : x / (x + Y());
+    };
+  }
+
+  randomBeta.source = sourceRandomBeta;
+
+  return randomBeta;
+})(defaultSource);
+
+var binomial = (function sourceRandomBinomial(source) {
+  var G = geometric.source(source),
+      B = beta.source(source);
+
+  function randomBinomial(n, p) {
+    n = +n;
+    if ((p = +p) >= 1) return () => n;
+    if (p <= 0) return () => 0;
+    return function() {
+      var acc = 0, nn = n, pp = p;
+      while (nn * pp > 16 && nn * (1 - pp) > 16) {
+        var i = Math.floor((nn + 1) * pp),
+            y = B(i, nn - i + 1)();
+        if (y <= pp) {
+          acc += i;
+          nn -= i;
+          pp = (pp - y) / (1 - y);
+        } else {
+          nn = i - 1;
+          pp /= y;
+        }
+      }
+      var sign = pp < 0.5,
+          pFinal = sign ? pp : 1 - pp,
+          g = G(pFinal);
+      for (var s = g(), k = 0; s <= nn; ++k) s += g();
+      return acc + (sign ? k : nn - k);
+    };
+  }
+
+  randomBinomial.source = sourceRandomBinomial;
+
+  return randomBinomial;
+})(defaultSource);
+
+var weibull = (function sourceRandomWeibull(source) {
+  function randomWeibull(k, a, b) {
+    var outerFunc;
+    if ((k = +k) === 0) {
+      outerFunc = x => -Math.log(x);
+    } else {
+      k = 1 / k;
+      outerFunc = x => Math.pow(x, k);
+    }
+    a = a == null ? 0 : +a;
+    b = b == null ? 1 : +b;
+    return function() {
+      return a + b * outerFunc(-Math.log1p(-source()));
+    };
+  }
+
+  randomWeibull.source = sourceRandomWeibull;
+
+  return randomWeibull;
+})(defaultSource);
+
+var cauchy = (function sourceRandomCauchy(source) {
+  function randomCauchy(a, b) {
+    a = a == null ? 0 : +a;
+    b = b == null ? 1 : +b;
+    return function() {
+      return a + b * Math.tan(Math.PI * source());
+    };
+  }
+
+  randomCauchy.source = sourceRandomCauchy;
+
+  return randomCauchy;
+})(defaultSource);
+
+var logistic = (function sourceRandomLogistic(source) {
+  function randomLogistic(a, b) {
+    a = a == null ? 0 : +a;
+    b = b == null ? 1 : +b;
+    return function() {
+      var u = source();
+      return a + b * Math.log(u / (1 - u));
+    };
+  }
+
+  randomLogistic.source = sourceRandomLogistic;
+
+  return randomLogistic;
+})(defaultSource);
+
+var poisson = (function sourceRandomPoisson(source) {
+  var G = gamma.source(source),
+      B = binomial.source(source);
+
+  function randomPoisson(lambda) {
+    return function() {
+      var acc = 0, l = lambda;
+      while (l > 16) {
+        var n = Math.floor(0.875 * l),
+            t = G(n)();
+        if (t > l) return acc + B(n - 1, l / t)();
+        acc += n;
+        l -= t;
+      }
+      for (var s = -Math.log1p(-source()), k = 0; s <= l; ++k) s -= Math.log1p(-source());
+      return acc + k;
+    };
+  }
+
+  randomPoisson.source = sourceRandomPoisson;
+
+  return randomPoisson;
+})(defaultSource);
+
+// https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use
+const mul = 0x19660D;
+const inc = 0x3C6EF35F;
+const eps = 1 / 0x100000000;
+
+function lcg(seed = Math.random()) {
+  let state = (0 <= seed && seed < 1 ? seed / eps : Math.abs(seed)) | 0;
+  return () => (state = mul * state + inc | 0, eps * (state >>> 0));
+}
 
 function initRange(domain, range) {
   switch (arguments.length) {
@@ -12169,44 +14783,50 @@
 function initInterpolator(domain, interpolator) {
   switch (arguments.length) {
     case 0: break;
-    case 1: this.interpolator(domain); break;
-    default: this.interpolator(interpolator).domain(domain); break;
+    case 1: {
+      if (typeof domain === "function") this.interpolator(domain);
+      else this.range(domain);
+      break;
+    }
+    default: {
+      this.domain(domain);
+      if (typeof interpolator === "function") this.interpolator(interpolator);
+      else this.range(interpolator);
+      break;
+    }
   }
   return this;
 }
 
-var array$3 = Array.prototype;
-
-var map$3 = array$3.map;
-var slice$5 = array$3.slice;
-
-var implicit = {name: "implicit"};
+const implicit = Symbol("implicit");
 
 function ordinal() {
-  var index = map$1(),
+  var index = new InternMap(),
       domain = [],
       range = [],
       unknown = implicit;
 
   function scale(d) {
-    var key = d + "", i = index.get(key);
-    if (!i) {
+    let i = index.get(d);
+    if (i === undefined) {
       if (unknown !== implicit) return unknown;
-      index.set(key, i = domain.push(d));
+      index.set(d, i = domain.push(d) - 1);
     }
-    return range[(i - 1) % range.length];
+    return range[i % range.length];
   }
 
   scale.domain = function(_) {
     if (!arguments.length) return domain.slice();
-    domain = [], index = map$1();
-    var i = -1, n = _.length, d, key;
-    while (++i < n) if (!index.has(key = (d = _[i]) + "")) index.set(key, domain.push(d));
+    domain = [], index = new InternMap();
+    for (const value of _) {
+      if (index.has(value)) continue;
+      index.set(value, domain.push(value) - 1);
+    }
     return scale;
   };
 
   scale.range = function(_) {
-    return arguments.length ? (range = slice$5.call(_), scale) : range.slice();
+    return arguments.length ? (range = Array.from(_), scale) : range.slice();
   };
 
   scale.unknown = function(_) {
@@ -12226,7 +14846,8 @@
   var scale = ordinal().unknown(undefined),
       domain = scale.domain,
       ordinalRange = scale.range,
-      range = [0, 1],
+      r0 = 0,
+      r1 = 1,
       step,
       bandwidth,
       round = false,
@@ -12238,15 +14859,15 @@
 
   function rescale() {
     var n = domain().length,
-        reverse = range[1] < range[0],
-        start = range[reverse - 0],
-        stop = range[1 - reverse];
+        reverse = r1 < r0,
+        start = reverse ? r1 : r0,
+        stop = reverse ? r0 : r1;
     step = (stop - start) / Math.max(1, n - paddingInner + paddingOuter * 2);
     if (round) step = Math.floor(step);
     start += (stop - start - step * (n - paddingInner)) * align;
     bandwidth = step * (1 - paddingInner);
     if (round) start = Math.round(start), bandwidth = Math.round(bandwidth);
-    var values = sequence(n).map(function(i) { return start + step * i; });
+    var values = range$2(n).map(function(i) { return start + step * i; });
     return ordinalRange(reverse ? values.reverse() : values);
   }
 
@@ -12255,11 +14876,11 @@
   };
 
   scale.range = function(_) {
-    return arguments.length ? (range = [+_[0], +_[1]], rescale()) : range.slice();
+    return arguments.length ? ([r0, r1] = _, r0 = +r0, r1 = +r1, rescale()) : [r0, r1];
   };
 
   scale.rangeRound = function(_) {
-    return range = [+_[0], +_[1]], round = true, rescale();
+    return [r0, r1] = _, r0 = +r0, r1 = +r1, round = true, rescale();
   };
 
   scale.bandwidth = function() {
@@ -12291,7 +14912,7 @@
   };
 
   scale.copy = function() {
-    return band(domain(), range)
+    return band(domain(), [r0, r1])
         .round(round)
         .paddingInner(paddingInner)
         .paddingOuter(paddingOuter)
@@ -12315,34 +14936,34 @@
   return scale;
 }
 
-function point$1() {
+function point$4() {
   return pointish(band.apply(null, arguments).paddingInner(1));
 }
 
-function constant$a(x) {
+function constants(x) {
   return function() {
     return x;
   };
 }
 
-function number$2(x) {
+function number$1(x) {
   return +x;
 }
 
 var unit = [0, 1];
 
-function identity$6(x) {
+function identity$3(x) {
   return x;
 }
 
 function normalize(a, b) {
   return (b -= (a = +a))
       ? function(x) { return (x - a) / b; }
-      : constant$a(isNaN(b) ? NaN : 0.5);
+      : constants(isNaN(b) ? NaN : 0.5);
 }
 
-function clamper(domain) {
-  var a = domain[0], b = domain[domain.length - 1], t;
+function clamper(a, b) {
+  var t;
   if (a > b) t = a, a = b, b = t;
   return function(x) { return Math.max(a, Math.min(b, x)); };
 }
@@ -12374,12 +14995,12 @@
   }
 
   return function(x) {
-    var i = bisectRight(domain, x, 1, j) - 1;
+    var i = bisect(domain, x, 1, j) - 1;
     return r[i](d[i](x));
   };
 }
 
-function copy(source, target) {
+function copy$1(source, target) {
   return target
       .domain(source.domain())
       .range(source.range())
@@ -12388,26 +15009,28 @@
       .unknown(source.unknown());
 }
 
-function transformer$1() {
+function transformer$2() {
   var domain = unit,
       range = unit,
-      interpolate = interpolateValue,
+      interpolate = interpolate$2,
       transform,
       untransform,
       unknown,
-      clamp = identity$6,
+      clamp = identity$3,
       piecewise,
       output,
       input;
 
   function rescale() {
-    piecewise = Math.min(domain.length, range.length) > 2 ? polymap : bimap;
+    var n = Math.min(domain.length, range.length);
+    if (clamp !== identity$3) clamp = clamper(domain[0], domain[n - 1]);
+    piecewise = n > 2 ? polymap : bimap;
     output = input = null;
     return scale;
   }
 
   function scale(x) {
-    return isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate)))(transform(clamp(x)));
+    return x == null || isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate)))(transform(clamp(x)));
   }
 
   scale.invert = function(y) {
@@ -12415,19 +15038,19 @@
   };
 
   scale.domain = function(_) {
-    return arguments.length ? (domain = map$3.call(_, number$2), clamp === identity$6 || (clamp = clamper(domain)), rescale()) : domain.slice();
+    return arguments.length ? (domain = Array.from(_, number$1), rescale()) : domain.slice();
   };
 
   scale.range = function(_) {
-    return arguments.length ? (range = slice$5.call(_), rescale()) : range.slice();
+    return arguments.length ? (range = Array.from(_), rescale()) : range.slice();
   };
 
   scale.rangeRound = function(_) {
-    return range = slice$5.call(_), interpolate = interpolateRound, rescale();
+    return range = Array.from(_), interpolate = interpolateRound, rescale();
   };
 
   scale.clamp = function(_) {
-    return arguments.length ? (clamp = _ ? clamper(domain) : identity$6, scale) : clamp !== identity$6;
+    return arguments.length ? (clamp = _ ? true : identity$3, rescale()) : clamp !== identity$3;
   };
 
   scale.interpolate = function(_) {
@@ -12444,8 +15067,8 @@
   };
 }
 
-function continuous(transform, untransform) {
-  return transformer$1()(transform, untransform);
+function continuous() {
+  return transformer$2()(identity$3, identity$3);
 }
 
 function tickFormat(start, stop, count, specifier) {
@@ -12491,38 +15114,36 @@
   scale.nice = function(count) {
     if (count == null) count = 10;
 
-    var d = domain(),
-        i0 = 0,
-        i1 = d.length - 1,
-        start = d[i0],
-        stop = d[i1],
-        step;
+    var d = domain();
+    var i0 = 0;
+    var i1 = d.length - 1;
+    var start = d[i0];
+    var stop = d[i1];
+    var prestep;
+    var step;
+    var maxIter = 10;
 
     if (stop < start) {
       step = start, start = stop, stop = step;
       step = i0, i0 = i1, i1 = step;
     }
-
-    step = tickIncrement(start, stop, count);
-
-    if (step > 0) {
-      start = Math.floor(start / step) * step;
-      stop = Math.ceil(stop / step) * step;
+    
+    while (maxIter-- > 0) {
       step = tickIncrement(start, stop, count);
-    } else if (step < 0) {
-      start = Math.ceil(start * step) / step;
-      stop = Math.floor(stop * step) / step;
-      step = tickIncrement(start, stop, count);
-    }
-
-    if (step > 0) {
-      d[i0] = Math.floor(start / step) * step;
-      d[i1] = Math.ceil(stop / step) * step;
-      domain(d);
-    } else if (step < 0) {
-      d[i0] = Math.ceil(start * step) / step;
-      d[i1] = Math.floor(stop * step) / step;
-      domain(d);
+      if (step === prestep) {
+        d[i0] = start;
+        d[i1] = stop;
+        return domain(d);
+      } else if (step > 0) {
+        start = Math.floor(start / step) * step;
+        stop = Math.ceil(stop / step) * step;
+      } else if (step < 0) {
+        start = Math.ceil(start * step) / step;
+        stop = Math.floor(stop * step) / step;
+      } else {
+        break;
+      }
+      prestep = step;
     }
 
     return scale;
@@ -12531,11 +15152,11 @@
   return scale;
 }
 
-function linear$2() {
-  var scale = continuous(identity$6, identity$6);
+function linear() {
+  var scale = continuous();
 
   scale.copy = function() {
-    return copy(scale, linear$2());
+    return copy$1(scale, linear());
   };
 
   initRange.apply(scale, arguments);
@@ -12543,17 +15164,17 @@
   return linearish(scale);
 }
 
-function identity$7(domain) {
+function identity$2(domain) {
   var unknown;
 
   function scale(x) {
-    return isNaN(x = +x) ? unknown : x;
+    return x == null || isNaN(x = +x) ? unknown : x;
   }
 
   scale.invert = scale;
 
   scale.domain = scale.range = function(_) {
-    return arguments.length ? (domain = map$3.call(_, number$2), scale) : domain.slice();
+    return arguments.length ? (domain = Array.from(_, number$1), scale) : domain.slice();
   };
 
   scale.unknown = function(_) {
@@ -12561,10 +15182,10 @@
   };
 
   scale.copy = function() {
-    return identity$7(domain).unknown(unknown);
+    return identity$2(domain).unknown(unknown);
   };
 
-  domain = arguments.length ? map$3.call(domain, number$2) : [0, 1];
+  domain = arguments.length ? Array.from(domain, number$1) : [0, 1];
 
   return linearish(scale);
 }
@@ -12611,28 +15232,26 @@
 function powp(base) {
   return base === 10 ? pow10
       : base === Math.E ? Math.exp
-      : function(x) { return Math.pow(base, x); };
+      : x => Math.pow(base, x);
 }
 
 function logp(base) {
   return base === Math.E ? Math.log
       : base === 10 && Math.log10
       || base === 2 && Math.log2
-      || (base = Math.log(base), function(x) { return Math.log(x) / base; });
+      || (base = Math.log(base), x => Math.log(x) / base);
 }
 
 function reflect(f) {
-  return function(x) {
-    return -f(-x);
-  };
+  return (x, k) => -f(-x, k);
 }
 
 function loggish(transform) {
-  var scale = transform(transformLog, transformExp),
-      domain = scale.domain,
-      base = 10,
-      logs,
-      pows;
+  const scale = transform(transformLog, transformExp);
+  const domain = scale.domain;
+  let base = 10;
+  let logs;
+  let pows;
 
   function rescale() {
     logs = logp(base), pows = powp(base);
@@ -12653,78 +15272,75 @@
     return arguments.length ? (domain(_), rescale()) : domain();
   };
 
-  scale.ticks = function(count) {
-    var d = domain(),
-        u = d[0],
-        v = d[d.length - 1],
-        r;
+  scale.ticks = count => {
+    const d = domain();
+    let u = d[0];
+    let v = d[d.length - 1];
+    const r = v < u;
 
-    if (r = v < u) i = u, u = v, v = i;
+    if (r) ([u, v] = [v, u]);
 
-    var i = logs(u),
-        j = logs(v),
-        p,
-        k,
-        t,
-        n = count == null ? 10 : +count,
-        z = [];
+    let i = logs(u);
+    let j = logs(v);
+    let k;
+    let t;
+    const n = count == null ? 10 : +count;
+    let z = [];
 
     if (!(base % 1) && j - i < n) {
-      i = Math.round(i) - 1, j = Math.round(j) + 1;
-      if (u > 0) for (; i < j; ++i) {
-        for (k = 1, p = pows(i); k < base; ++k) {
-          t = p * k;
+      i = Math.floor(i), j = Math.ceil(j);
+      if (u > 0) for (; i <= j; ++i) {
+        for (k = 1; k < base; ++k) {
+          t = i < 0 ? k / pows(-i) : k * pows(i);
           if (t < u) continue;
           if (t > v) break;
           z.push(t);
         }
-      } else for (; i < j; ++i) {
-        for (k = base - 1, p = pows(i); k >= 1; --k) {
-          t = p * k;
+      } else for (; i <= j; ++i) {
+        for (k = base - 1; k >= 1; --k) {
+          t = i > 0 ? k / pows(-i) : k * pows(i);
           if (t < u) continue;
           if (t > v) break;
           z.push(t);
         }
       }
+      if (z.length * 2 < n) z = ticks(u, v, n);
     } else {
       z = ticks(i, j, Math.min(j - i, n)).map(pows);
     }
-
     return r ? z.reverse() : z;
   };
 
-  scale.tickFormat = function(count, specifier) {
-    if (specifier == null) specifier = base === 10 ? ".0e" : ",";
-    if (typeof specifier !== "function") specifier = exports.format(specifier);
-    if (count === Infinity) return specifier;
+  scale.tickFormat = (count, specifier) => {
     if (count == null) count = 10;
-    var k = Math.max(1, base * count / scale.ticks().length); // TODO fast estimate?
-    return function(d) {
-      var i = d / pows(Math.round(logs(d)));
+    if (specifier == null) specifier = base === 10 ? "s" : ",";
+    if (typeof specifier !== "function") {
+      if (!(base % 1) && (specifier = formatSpecifier(specifier)).precision == null) specifier.trim = true;
+      specifier = exports.format(specifier);
+    }
+    if (count === Infinity) return specifier;
+    const k = Math.max(1, base * count / scale.ticks().length); // TODO fast estimate?
+    return d => {
+      let i = d / pows(Math.round(logs(d)));
       if (i * base < base - 0.5) i *= base;
       return i <= k ? specifier(d) : "";
     };
   };
 
-  scale.nice = function() {
+  scale.nice = () => {
     return domain(nice(domain(), {
-      floor: function(x) { return pows(Math.floor(logs(x))); },
-      ceil: function(x) { return pows(Math.ceil(logs(x))); }
+      floor: x => pows(Math.floor(logs(x))),
+      ceil: x => pows(Math.ceil(logs(x)))
     }));
   };
 
   return scale;
 }
 
-function log$1() {
-  var scale = loggish(transformer$1()).domain([1, 10]);
-
-  scale.copy = function() {
-    return copy(scale, log$1()).base(scale.base());
-  };
-
+function log() {
+  const scale = loggish(transformer$2()).domain([1, 10]);
+  scale.copy = () => copy$1(scale, log()).base(scale.base());
   initRange.apply(scale, arguments);
-
   return scale;
 }
 
@@ -12751,10 +15367,10 @@
 }
 
 function symlog() {
-  var scale = symlogish(transformer$1());
+  var scale = symlogish(transformer$2());
 
   scale.copy = function() {
-    return copy(scale, symlog()).constant(scale.constant());
+    return copy$1(scale, symlog()).constant(scale.constant());
   };
 
   return initRange.apply(scale, arguments);
@@ -12775,11 +15391,11 @@
 }
 
 function powish(transform) {
-  var scale = transform(identity$6, identity$6),
+  var scale = transform(identity$3, identity$3),
       exponent = 1;
 
   function rescale() {
-    return exponent === 1 ? transform(identity$6, identity$6)
+    return exponent === 1 ? transform(identity$3, identity$3)
         : exponent === 0.5 ? transform(transformSqrt, transformSquare)
         : transform(transformPow(exponent), transformPow(1 / exponent));
   }
@@ -12791,11 +15407,11 @@
   return linearish(scale);
 }
 
-function pow$1() {
-  var scale = powish(transformer$1());
+function pow() {
+  var scale = powish(transformer$2());
 
   scale.copy = function() {
-    return copy(scale, pow$1()).exponent(scale.exponent());
+    return copy$1(scale, pow()).exponent(scale.exponent());
   };
 
   initRange.apply(scale, arguments);
@@ -12804,7 +15420,66 @@
 }
 
 function sqrt$1() {
-  return pow$1.apply(null, arguments).exponent(0.5);
+  return pow.apply(null, arguments).exponent(0.5);
+}
+
+function square$1(x) {
+  return Math.sign(x) * x * x;
+}
+
+function unsquare(x) {
+  return Math.sign(x) * Math.sqrt(Math.abs(x));
+}
+
+function radial() {
+  var squared = continuous(),
+      range = [0, 1],
+      round = false,
+      unknown;
+
+  function scale(x) {
+    var y = unsquare(squared(x));
+    return isNaN(y) ? unknown : round ? Math.round(y) : y;
+  }
+
+  scale.invert = function(y) {
+    return squared.invert(square$1(y));
+  };
+
+  scale.domain = function(_) {
+    return arguments.length ? (squared.domain(_), scale) : squared.domain();
+  };
+
+  scale.range = function(_) {
+    return arguments.length ? (squared.range((range = Array.from(_, number$1)).map(square$1)), scale) : range.slice();
+  };
+
+  scale.rangeRound = function(_) {
+    return scale.range(_).round(true);
+  };
+
+  scale.round = function(_) {
+    return arguments.length ? (round = !!_, scale) : round;
+  };
+
+  scale.clamp = function(_) {
+    return arguments.length ? (squared.clamp(_), scale) : squared.clamp();
+  };
+
+  scale.unknown = function(_) {
+    return arguments.length ? (unknown = _, scale) : unknown;
+  };
+
+  scale.copy = function() {
+    return radial(squared.domain(), range)
+        .round(round)
+        .clamp(squared.clamp())
+        .unknown(unknown);
+  };
+
+  initRange.apply(scale, arguments);
+
+  return linearish(scale);
 }
 
 function quantile() {
@@ -12816,12 +15491,12 @@
   function rescale() {
     var i = 0, n = Math.max(1, range.length);
     thresholds = new Array(n - 1);
-    while (++i < n) thresholds[i - 1] = threshold(domain, i / n);
+    while (++i < n) thresholds[i - 1] = quantileSorted(domain, i / n);
     return scale;
   }
 
   function scale(x) {
-    return isNaN(x = +x) ? unknown : range[bisectRight(thresholds, x)];
+    return x == null || isNaN(x = +x) ? unknown : range[bisect(thresholds, x)];
   }
 
   scale.invertExtent = function(y) {
@@ -12835,13 +15510,13 @@
   scale.domain = function(_) {
     if (!arguments.length) return domain.slice();
     domain = [];
-    for (var i = 0, n = _.length, d; i < n; ++i) if (d = _[i], d != null && !isNaN(d = +d)) domain.push(d);
-    domain.sort(ascending);
+    for (let d of _) if (d != null && !isNaN(d = +d)) domain.push(d);
+    domain.sort(ascending$3);
     return rescale();
   };
 
   scale.range = function(_) {
-    return arguments.length ? (range = slice$5.call(_), rescale()) : range.slice();
+    return arguments.length ? (range = Array.from(_), rescale()) : range.slice();
   };
 
   scale.unknown = function(_) {
@@ -12862,7 +15537,7 @@
   return initRange.apply(scale, arguments);
 }
 
-function quantize$1() {
+function quantize() {
   var x0 = 0,
       x1 = 1,
       n = 1,
@@ -12871,7 +15546,7 @@
       unknown;
 
   function scale(x) {
-    return x <= x ? range[bisectRight(domain, x, 0, n)] : unknown;
+    return x != null && x <= x ? range[bisect(domain, x, 0, n)] : unknown;
   }
 
   function rescale() {
@@ -12882,11 +15557,11 @@
   }
 
   scale.domain = function(_) {
-    return arguments.length ? (x0 = +_[0], x1 = +_[1], rescale()) : [x0, x1];
+    return arguments.length ? ([x0, x1] = _, x0 = +x0, x1 = +x1, rescale()) : [x0, x1];
   };
 
   scale.range = function(_) {
-    return arguments.length ? (n = (range = slice$5.call(_)).length - 1, rescale()) : range.slice();
+    return arguments.length ? (n = (range = Array.from(_)).length - 1, rescale()) : range.slice();
   };
 
   scale.invertExtent = function(y) {
@@ -12906,7 +15581,7 @@
   };
 
   scale.copy = function() {
-    return quantize$1()
+    return quantize()
         .domain([x0, x1])
         .range(range)
         .unknown(unknown);
@@ -12915,22 +15590,22 @@
   return initRange.apply(linearish(scale), arguments);
 }
 
-function threshold$1() {
+function threshold() {
   var domain = [0.5],
       range = [0, 1],
       unknown,
       n = 1;
 
   function scale(x) {
-    return x <= x ? range[bisectRight(domain, x, 0, n)] : unknown;
+    return x != null && x <= x ? range[bisect(domain, x, 0, n)] : unknown;
   }
 
   scale.domain = function(_) {
-    return arguments.length ? (domain = slice$5.call(_), n = Math.min(domain.length, range.length - 1), scale) : domain.slice();
+    return arguments.length ? (domain = Array.from(_), n = Math.min(domain.length, range.length - 1), scale) : domain.slice();
   };
 
   scale.range = function(_) {
-    return arguments.length ? (range = slice$5.call(_), n = Math.min(domain.length, range.length - 1), scale) : range.slice();
+    return arguments.length ? (range = Array.from(_), n = Math.min(domain.length, range.length - 1), scale) : range.slice();
   };
 
   scale.invertExtent = function(y) {
@@ -12943,7 +15618,7 @@
   };
 
   scale.copy = function() {
-    return threshold$1()
+    return threshold()
         .domain(domain)
         .range(range)
         .unknown(unknown);
@@ -12952,47 +15627,46 @@
   return initRange.apply(scale, arguments);
 }
 
-var t0$1 = new Date,
-    t1$1 = new Date;
+const t0 = new Date, t1 = new Date;
 
-function newInterval(floori, offseti, count, field) {
+function timeInterval(floori, offseti, count, field) {
 
   function interval(date) {
     return floori(date = arguments.length === 0 ? new Date : new Date(+date)), date;
   }
 
-  interval.floor = function(date) {
+  interval.floor = (date) => {
     return floori(date = new Date(+date)), date;
   };
 
-  interval.ceil = function(date) {
+  interval.ceil = (date) => {
     return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date;
   };
 
-  interval.round = function(date) {
-    var d0 = interval(date),
-        d1 = interval.ceil(date);
+  interval.round = (date) => {
+    const d0 = interval(date), d1 = interval.ceil(date);
     return date - d0 < d1 - date ? d0 : d1;
   };
 
-  interval.offset = function(date, step) {
+  interval.offset = (date, step) => {
     return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date;
   };
 
-  interval.range = function(start, stop, step) {
-    var range = [], previous;
+  interval.range = (start, stop, step) => {
+    const range = [];
     start = interval.ceil(start);
     step = step == null ? 1 : Math.floor(step);
     if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date
+    let previous;
     do range.push(previous = new Date(+start)), offseti(start, step), floori(start);
     while (previous < start && start < stop);
     return range;
   };
 
-  interval.filter = function(test) {
-    return newInterval(function(date) {
+  interval.filter = (test) => {
+    return timeInterval((date) => {
       if (date >= date) while (floori(date), !test(date)) date.setTime(date - 1);
-    }, function(date, step) {
+    }, (date, step) => {
       if (date >= date) {
         if (step < 0) while (++step <= 0) {
           while (offseti(date, -1), !test(date)) {} // eslint-disable-line no-empty
@@ -13004,254 +15678,323 @@
   };
 
   if (count) {
-    interval.count = function(start, end) {
-      t0$1.setTime(+start), t1$1.setTime(+end);
-      floori(t0$1), floori(t1$1);
-      return Math.floor(count(t0$1, t1$1));
+    interval.count = (start, end) => {
+      t0.setTime(+start), t1.setTime(+end);
+      floori(t0), floori(t1);
+      return Math.floor(count(t0, t1));
     };
 
-    interval.every = function(step) {
+    interval.every = (step) => {
       step = Math.floor(step);
       return !isFinite(step) || !(step > 0) ? null
           : !(step > 1) ? interval
           : interval.filter(field
-              ? function(d) { return field(d) % step === 0; }
-              : function(d) { return interval.count(0, d) % step === 0; });
+              ? (d) => field(d) % step === 0
+              : (d) => interval.count(0, d) % step === 0);
     };
   }
 
   return interval;
 }
 
-var millisecond = newInterval(function() {
+const millisecond = timeInterval(() => {
   // noop
-}, function(date, step) {
+}, (date, step) => {
   date.setTime(+date + step);
-}, function(start, end) {
+}, (start, end) => {
   return end - start;
 });
 
 // An optimized implementation for this simple case.
-millisecond.every = function(k) {
+millisecond.every = (k) => {
   k = Math.floor(k);
   if (!isFinite(k) || !(k > 0)) return null;
   if (!(k > 1)) return millisecond;
-  return newInterval(function(date) {
+  return timeInterval((date) => {
     date.setTime(Math.floor(date / k) * k);
-  }, function(date, step) {
+  }, (date, step) => {
     date.setTime(+date + step * k);
-  }, function(start, end) {
+  }, (start, end) => {
     return (end - start) / k;
   });
 };
-var milliseconds = millisecond.range;
 
-var durationSecond = 1e3;
-var durationMinute = 6e4;
-var durationHour = 36e5;
-var durationDay = 864e5;
-var durationWeek = 6048e5;
+const milliseconds = millisecond.range;
 
-var second = newInterval(function(date) {
+const durationSecond = 1000;
+const durationMinute = durationSecond * 60;
+const durationHour = durationMinute * 60;
+const durationDay = durationHour * 24;
+const durationWeek = durationDay * 7;
+const durationMonth = durationDay * 30;
+const durationYear = durationDay * 365;
+
+const second = timeInterval((date) => {
   date.setTime(date - date.getMilliseconds());
-}, function(date, step) {
+}, (date, step) => {
   date.setTime(+date + step * durationSecond);
-}, function(start, end) {
+}, (start, end) => {
   return (end - start) / durationSecond;
-}, function(date) {
+}, (date) => {
   return date.getUTCSeconds();
 });
-var seconds = second.range;
 
-var minute = newInterval(function(date) {
+const seconds = second.range;
+
+const timeMinute = timeInterval((date) => {
   date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond);
-}, function(date, step) {
+}, (date, step) => {
   date.setTime(+date + step * durationMinute);
-}, function(start, end) {
+}, (start, end) => {
   return (end - start) / durationMinute;
-}, function(date) {
+}, (date) => {
   return date.getMinutes();
 });
-var minutes = minute.range;
 
-var hour = newInterval(function(date) {
+const timeMinutes = timeMinute.range;
+
+const utcMinute = timeInterval((date) => {
+  date.setUTCSeconds(0, 0);
+}, (date, step) => {
+  date.setTime(+date + step * durationMinute);
+}, (start, end) => {
+  return (end - start) / durationMinute;
+}, (date) => {
+  return date.getUTCMinutes();
+});
+
+const utcMinutes = utcMinute.range;
+
+const timeHour = timeInterval((date) => {
   date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond - date.getMinutes() * durationMinute);
-}, function(date, step) {
+}, (date, step) => {
   date.setTime(+date + step * durationHour);
-}, function(start, end) {
+}, (start, end) => {
   return (end - start) / durationHour;
-}, function(date) {
+}, (date) => {
   return date.getHours();
 });
-var hours = hour.range;
 
-var day = newInterval(function(date) {
-  date.setHours(0, 0, 0, 0);
-}, function(date, step) {
-  date.setDate(date.getDate() + step);
-}, function(start, end) {
-  return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationDay;
-}, function(date) {
-  return date.getDate() - 1;
+const timeHours = timeHour.range;
+
+const utcHour = timeInterval((date) => {
+  date.setUTCMinutes(0, 0, 0);
+}, (date, step) => {
+  date.setTime(+date + step * durationHour);
+}, (start, end) => {
+  return (end - start) / durationHour;
+}, (date) => {
+  return date.getUTCHours();
 });
-var days = day.range;
 
-function weekday(i) {
-  return newInterval(function(date) {
+const utcHours = utcHour.range;
+
+const timeDay = timeInterval(
+  date => date.setHours(0, 0, 0, 0),
+  (date, step) => date.setDate(date.getDate() + step),
+  (start, end) => (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationDay,
+  date => date.getDate() - 1
+);
+
+const timeDays = timeDay.range;
+
+const utcDay = timeInterval((date) => {
+  date.setUTCHours(0, 0, 0, 0);
+}, (date, step) => {
+  date.setUTCDate(date.getUTCDate() + step);
+}, (start, end) => {
+  return (end - start) / durationDay;
+}, (date) => {
+  return date.getUTCDate() - 1;
+});
+
+const utcDays = utcDay.range;
+
+const unixDay = timeInterval((date) => {
+  date.setUTCHours(0, 0, 0, 0);
+}, (date, step) => {
+  date.setUTCDate(date.getUTCDate() + step);
+}, (start, end) => {
+  return (end - start) / durationDay;
+}, (date) => {
+  return Math.floor(date / durationDay);
+});
+
+const unixDays = unixDay.range;
+
+function timeWeekday(i) {
+  return timeInterval((date) => {
     date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);
     date.setHours(0, 0, 0, 0);
-  }, function(date, step) {
+  }, (date, step) => {
     date.setDate(date.getDate() + step * 7);
-  }, function(start, end) {
+  }, (start, end) => {
     return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationWeek;
   });
 }
 
-var sunday = weekday(0);
-var monday = weekday(1);
-var tuesday = weekday(2);
-var wednesday = weekday(3);
-var thursday = weekday(4);
-var friday = weekday(5);
-var saturday = weekday(6);
+const timeSunday = timeWeekday(0);
+const timeMonday = timeWeekday(1);
+const timeTuesday = timeWeekday(2);
+const timeWednesday = timeWeekday(3);
+const timeThursday = timeWeekday(4);
+const timeFriday = timeWeekday(5);
+const timeSaturday = timeWeekday(6);
 
-var sundays = sunday.range;
-var mondays = monday.range;
-var tuesdays = tuesday.range;
-var wednesdays = wednesday.range;
-var thursdays = thursday.range;
-var fridays = friday.range;
-var saturdays = saturday.range;
-
-var month = newInterval(function(date) {
-  date.setDate(1);
-  date.setHours(0, 0, 0, 0);
-}, function(date, step) {
-  date.setMonth(date.getMonth() + step);
-}, function(start, end) {
-  return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;
-}, function(date) {
-  return date.getMonth();
-});
-var months = month.range;
-
-var year = newInterval(function(date) {
-  date.setMonth(0, 1);
-  date.setHours(0, 0, 0, 0);
-}, function(date, step) {
-  date.setFullYear(date.getFullYear() + step);
-}, function(start, end) {
-  return end.getFullYear() - start.getFullYear();
-}, function(date) {
-  return date.getFullYear();
-});
-
-// An optimized implementation for this simple case.
-year.every = function(k) {
-  return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
-    date.setFullYear(Math.floor(date.getFullYear() / k) * k);
-    date.setMonth(0, 1);
-    date.setHours(0, 0, 0, 0);
-  }, function(date, step) {
-    date.setFullYear(date.getFullYear() + step * k);
-  });
-};
-var years = year.range;
-
-var utcMinute = newInterval(function(date) {
-  date.setUTCSeconds(0, 0);
-}, function(date, step) {
-  date.setTime(+date + step * durationMinute);
-}, function(start, end) {
-  return (end - start) / durationMinute;
-}, function(date) {
-  return date.getUTCMinutes();
-});
-var utcMinutes = utcMinute.range;
-
-var utcHour = newInterval(function(date) {
-  date.setUTCMinutes(0, 0, 0);
-}, function(date, step) {
-  date.setTime(+date + step * durationHour);
-}, function(start, end) {
-  return (end - start) / durationHour;
-}, function(date) {
-  return date.getUTCHours();
-});
-var utcHours = utcHour.range;
-
-var utcDay = newInterval(function(date) {
-  date.setUTCHours(0, 0, 0, 0);
-}, function(date, step) {
-  date.setUTCDate(date.getUTCDate() + step);
-}, function(start, end) {
-  return (end - start) / durationDay;
-}, function(date) {
-  return date.getUTCDate() - 1;
-});
-var utcDays = utcDay.range;
+const timeSundays = timeSunday.range;
+const timeMondays = timeMonday.range;
+const timeTuesdays = timeTuesday.range;
+const timeWednesdays = timeWednesday.range;
+const timeThursdays = timeThursday.range;
+const timeFridays = timeFriday.range;
+const timeSaturdays = timeSaturday.range;
 
 function utcWeekday(i) {
-  return newInterval(function(date) {
+  return timeInterval((date) => {
     date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);
     date.setUTCHours(0, 0, 0, 0);
-  }, function(date, step) {
+  }, (date, step) => {
     date.setUTCDate(date.getUTCDate() + step * 7);
-  }, function(start, end) {
+  }, (start, end) => {
     return (end - start) / durationWeek;
   });
 }
 
-var utcSunday = utcWeekday(0);
-var utcMonday = utcWeekday(1);
-var utcTuesday = utcWeekday(2);
-var utcWednesday = utcWeekday(3);
-var utcThursday = utcWeekday(4);
-var utcFriday = utcWeekday(5);
-var utcSaturday = utcWeekday(6);
+const utcSunday = utcWeekday(0);
+const utcMonday = utcWeekday(1);
+const utcTuesday = utcWeekday(2);
+const utcWednesday = utcWeekday(3);
+const utcThursday = utcWeekday(4);
+const utcFriday = utcWeekday(5);
+const utcSaturday = utcWeekday(6);
 
-var utcSundays = utcSunday.range;
-var utcMondays = utcMonday.range;
-var utcTuesdays = utcTuesday.range;
-var utcWednesdays = utcWednesday.range;
-var utcThursdays = utcThursday.range;
-var utcFridays = utcFriday.range;
-var utcSaturdays = utcSaturday.range;
+const utcSundays = utcSunday.range;
+const utcMondays = utcMonday.range;
+const utcTuesdays = utcTuesday.range;
+const utcWednesdays = utcWednesday.range;
+const utcThursdays = utcThursday.range;
+const utcFridays = utcFriday.range;
+const utcSaturdays = utcSaturday.range;
 
-var utcMonth = newInterval(function(date) {
+const timeMonth = timeInterval((date) => {
+  date.setDate(1);
+  date.setHours(0, 0, 0, 0);
+}, (date, step) => {
+  date.setMonth(date.getMonth() + step);
+}, (start, end) => {
+  return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;
+}, (date) => {
+  return date.getMonth();
+});
+
+const timeMonths = timeMonth.range;
+
+const utcMonth = timeInterval((date) => {
   date.setUTCDate(1);
   date.setUTCHours(0, 0, 0, 0);
-}, function(date, step) {
+}, (date, step) => {
   date.setUTCMonth(date.getUTCMonth() + step);
-}, function(start, end) {
+}, (start, end) => {
   return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12;
-}, function(date) {
+}, (date) => {
   return date.getUTCMonth();
 });
-var utcMonths = utcMonth.range;
 
-var utcYear = newInterval(function(date) {
+const utcMonths = utcMonth.range;
+
+const timeYear = timeInterval((date) => {
+  date.setMonth(0, 1);
+  date.setHours(0, 0, 0, 0);
+}, (date, step) => {
+  date.setFullYear(date.getFullYear() + step);
+}, (start, end) => {
+  return end.getFullYear() - start.getFullYear();
+}, (date) => {
+  return date.getFullYear();
+});
+
+// An optimized implementation for this simple case.
+timeYear.every = (k) => {
+  return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval((date) => {
+    date.setFullYear(Math.floor(date.getFullYear() / k) * k);
+    date.setMonth(0, 1);
+    date.setHours(0, 0, 0, 0);
+  }, (date, step) => {
+    date.setFullYear(date.getFullYear() + step * k);
+  });
+};
+
+const timeYears = timeYear.range;
+
+const utcYear = timeInterval((date) => {
   date.setUTCMonth(0, 1);
   date.setUTCHours(0, 0, 0, 0);
-}, function(date, step) {
+}, (date, step) => {
   date.setUTCFullYear(date.getUTCFullYear() + step);
-}, function(start, end) {
+}, (start, end) => {
   return end.getUTCFullYear() - start.getUTCFullYear();
-}, function(date) {
+}, (date) => {
   return date.getUTCFullYear();
 });
 
 // An optimized implementation for this simple case.
-utcYear.every = function(k) {
-  return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
+utcYear.every = (k) => {
+  return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval((date) => {
     date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k);
     date.setUTCMonth(0, 1);
     date.setUTCHours(0, 0, 0, 0);
-  }, function(date, step) {
+  }, (date, step) => {
     date.setUTCFullYear(date.getUTCFullYear() + step * k);
   });
 };
-var utcYears = utcYear.range;
+
+const utcYears = utcYear.range;
+
+function ticker(year, month, week, day, hour, minute) {
+
+  const tickIntervals = [
+    [second,  1,      durationSecond],
+    [second,  5,  5 * durationSecond],
+    [second, 15, 15 * durationSecond],
+    [second, 30, 30 * durationSecond],
+    [minute,  1,      durationMinute],
+    [minute,  5,  5 * durationMinute],
+    [minute, 15, 15 * durationMinute],
+    [minute, 30, 30 * durationMinute],
+    [  hour,  1,      durationHour  ],
+    [  hour,  3,  3 * durationHour  ],
+    [  hour,  6,  6 * durationHour  ],
+    [  hour, 12, 12 * durationHour  ],
+    [   day,  1,      durationDay   ],
+    [   day,  2,  2 * durationDay   ],
+    [  week,  1,      durationWeek  ],
+    [ month,  1,      durationMonth ],
+    [ month,  3,  3 * durationMonth ],
+    [  year,  1,      durationYear  ]
+  ];
+
+  function ticks(start, stop, count) {
+    const reverse = stop < start;
+    if (reverse) [start, stop] = [stop, start];
+    const interval = count && typeof count.range === "function" ? count : tickInterval(start, stop, count);
+    const ticks = interval ? interval.range(start, +stop + 1) : []; // inclusive stop
+    return reverse ? ticks.reverse() : ticks;
+  }
+
+  function tickInterval(start, stop, count) {
+    const target = Math.abs(stop - start) / count;
+    const i = bisector(([,, step]) => step).right(tickIntervals, target);
+    if (i === tickIntervals.length) return year.every(tickStep(start / durationYear, stop / durationYear, count));
+    if (i === 0) return millisecond.every(Math.max(tickStep(start, stop, count), 1));
+    const [t, step] = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];
+    return t.every(step);
+  }
+
+  return [ticks, tickInterval];
+}
+
+const [utcTicks, utcTickInterval] = ticker(utcYear, utcMonth, utcSunday, unixDay, utcHour, utcMinute);
+const [timeTicks, timeTickInterval] = ticker(timeYear, timeMonth, timeSunday, timeDay, timeHour, timeMinute);
 
 function localDate(d) {
   if (0 <= d.y && d.y < 100) {
@@ -13275,7 +16018,7 @@
   return {y: y, m: m, d: d, H: 0, M: 0, S: 0, L: 0};
 }
 
-function formatLocale$1(locale) {
+function formatLocale(locale) {
   var locale_dateTime = locale.dateTime,
       locale_date = locale.date,
       locale_time = locale.time,
@@ -13305,6 +16048,8 @@
     "d": formatDayOfMonth,
     "e": formatDayOfMonth,
     "f": formatMicroseconds,
+    "g": formatYearISO,
+    "G": formatFullYearISO,
     "H": formatHour24,
     "I": formatHour12,
     "j": formatDayOfYear,
@@ -13323,7 +16068,7 @@
     "W": formatWeekNumberMonday,
     "x": null,
     "X": null,
-    "y": formatYear$1,
+    "y": formatYear,
     "Y": formatFullYear,
     "Z": formatZone,
     "%": formatLiteralPercent
@@ -13338,6 +16083,8 @@
     "d": formatUTCDayOfMonth,
     "e": formatUTCDayOfMonth,
     "f": formatUTCMicroseconds,
+    "g": formatUTCYearISO,
+    "G": formatUTCFullYearISO,
     "H": formatUTCHour24,
     "I": formatUTCHour12,
     "j": formatUTCDayOfYear,
@@ -13371,6 +16118,8 @@
     "d": parseDayOfMonth,
     "e": parseDayOfMonth,
     "f": parseMicroseconds,
+    "g": parseYear,
+    "G": parseFullYear,
     "H": parseHour24,
     "I": parseHour24,
     "j": parseDayOfYear,
@@ -13435,7 +16184,7 @@
     return function(string) {
       var d = newDate(1900, undefined, 1),
           i = parseSpecifier(d, specifier, string += "", 0),
-          week, day$1;
+          week, day;
       if (i != string.length) return null;
 
       // If a UNIX timestamp is specified, return it.
@@ -13456,25 +16205,25 @@
         if (d.V < 1 || d.V > 53) return null;
         if (!("w" in d)) d.w = 1;
         if ("Z" in d) {
-          week = utcDate(newDate(d.y, 0, 1)), day$1 = week.getUTCDay();
-          week = day$1 > 4 || day$1 === 0 ? utcMonday.ceil(week) : utcMonday(week);
+          week = utcDate(newDate(d.y, 0, 1)), day = week.getUTCDay();
+          week = day > 4 || day === 0 ? utcMonday.ceil(week) : utcMonday(week);
           week = utcDay.offset(week, (d.V - 1) * 7);
           d.y = week.getUTCFullYear();
           d.m = week.getUTCMonth();
           d.d = week.getUTCDate() + (d.w + 6) % 7;
         } else {
-          week = localDate(newDate(d.y, 0, 1)), day$1 = week.getDay();
-          week = day$1 > 4 || day$1 === 0 ? monday.ceil(week) : monday(week);
-          week = day.offset(week, (d.V - 1) * 7);
+          week = localDate(newDate(d.y, 0, 1)), day = week.getDay();
+          week = day > 4 || day === 0 ? timeMonday.ceil(week) : timeMonday(week);
+          week = timeDay.offset(week, (d.V - 1) * 7);
           d.y = week.getFullYear();
           d.m = week.getMonth();
           d.d = week.getDate() + (d.w + 6) % 7;
         }
       } else if ("W" in d || "U" in d) {
         if (!("w" in d)) d.w = "u" in d ? d.u % 7 : "W" in d ? 1 : 0;
-        day$1 = "Z" in d ? utcDate(newDate(d.y, 0, 1)).getUTCDay() : localDate(newDate(d.y, 0, 1)).getDay();
+        day = "Z" in d ? utcDate(newDate(d.y, 0, 1)).getUTCDay() : localDate(newDate(d.y, 0, 1)).getDay();
         d.m = 0;
-        d.d = "W" in d ? (d.w + 6) % 7 + d.W * 7 - (day$1 + 5) % 7 : d.w + d.U * 7 - (day$1 + 6) % 7;
+        d.d = "W" in d ? (d.w + 6) % 7 + d.W * 7 - (day + 5) % 7 : d.w + d.U * 7 - (day + 6) % 7;
       }
 
       // If a time zone is specified, all fields are interpreted as UTC and then
@@ -13514,27 +16263,27 @@
 
   function parsePeriod(d, string, i) {
     var n = periodRe.exec(string.slice(i));
-    return n ? (d.p = periodLookup[n[0].toLowerCase()], i + n[0].length) : -1;
+    return n ? (d.p = periodLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
   }
 
   function parseShortWeekday(d, string, i) {
     var n = shortWeekdayRe.exec(string.slice(i));
-    return n ? (d.w = shortWeekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
+    return n ? (d.w = shortWeekdayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
   }
 
   function parseWeekday(d, string, i) {
     var n = weekdayRe.exec(string.slice(i));
-    return n ? (d.w = weekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
+    return n ? (d.w = weekdayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
   }
 
   function parseShortMonth(d, string, i) {
     var n = shortMonthRe.exec(string.slice(i));
-    return n ? (d.m = shortMonthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
+    return n ? (d.m = shortMonthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
   }
 
   function parseMonth(d, string, i) {
     var n = monthRe.exec(string.slice(i));
-    return n ? (d.m = monthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
+    return n ? (d.m = monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
   }
 
   function parseLocaleDateTime(d, string, i) {
@@ -13626,7 +16375,7 @@
     percentRe = /^%/,
     requoteRe = /[\\^$*+?|[\]().{}]/g;
 
-function pad$1(value, fill, width) {
+function pad(value, fill, width) {
   var sign = value < 0 ? "-" : "",
       string = (sign ? -value : value) + "",
       length = string.length;
@@ -13642,9 +16391,7 @@
 }
 
 function formatLookup(names) {
-  var map = {}, i = -1, n = names.length;
-  while (++i < n) map[names[i].toLowerCase()] = i;
-  return map;
+  return new Map(names.map((name, i) => [name.toLowerCase(), i]));
 }
 
 function parseWeekdayNumberSunday(d, string, i) {
@@ -13748,23 +16495,23 @@
 }
 
 function formatDayOfMonth(d, p) {
-  return pad$1(d.getDate(), p, 2);
+  return pad(d.getDate(), p, 2);
 }
 
 function formatHour24(d, p) {
-  return pad$1(d.getHours(), p, 2);
+  return pad(d.getHours(), p, 2);
 }
 
 function formatHour12(d, p) {
-  return pad$1(d.getHours() % 12 || 12, p, 2);
+  return pad(d.getHours() % 12 || 12, p, 2);
 }
 
 function formatDayOfYear(d, p) {
-  return pad$1(1 + day.count(year(d), d), p, 3);
+  return pad(1 + timeDay.count(timeYear(d), d), p, 3);
 }
 
 function formatMilliseconds(d, p) {
-  return pad$1(d.getMilliseconds(), p, 3);
+  return pad(d.getMilliseconds(), p, 3);
 }
 
 function formatMicroseconds(d, p) {
@@ -13772,15 +16519,15 @@
 }
 
 function formatMonthNumber(d, p) {
-  return pad$1(d.getMonth() + 1, p, 2);
+  return pad(d.getMonth() + 1, p, 2);
 }
 
 function formatMinutes(d, p) {
-  return pad$1(d.getMinutes(), p, 2);
+  return pad(d.getMinutes(), p, 2);
 }
 
 function formatSeconds(d, p) {
-  return pad$1(d.getSeconds(), p, 2);
+  return pad(d.getSeconds(), p, 2);
 }
 
 function formatWeekdayNumberMonday(d) {
@@ -13789,13 +16536,17 @@
 }
 
 function formatWeekNumberSunday(d, p) {
-  return pad$1(sunday.count(year(d) - 1, d), p, 2);
+  return pad(timeSunday.count(timeYear(d) - 1, d), p, 2);
+}
+
+function dISO(d) {
+  var day = d.getDay();
+  return (day >= 4 || day === 0) ? timeThursday(d) : timeThursday.ceil(d);
 }
 
 function formatWeekNumberISO(d, p) {
-  var day = d.getDay();
-  d = (day >= 4 || day === 0) ? thursday(d) : thursday.ceil(d);
-  return pad$1(thursday.count(year(d), d) + (year(d).getDay() === 4), p, 2);
+  d = dISO(d);
+  return pad(timeThursday.count(timeYear(d), d) + (timeYear(d).getDay() === 4), p, 2);
 }
 
 function formatWeekdayNumberSunday(d) {
@@ -13803,42 +16554,53 @@
 }
 
 function formatWeekNumberMonday(d, p) {
-  return pad$1(monday.count(year(d) - 1, d), p, 2);
+  return pad(timeMonday.count(timeYear(d) - 1, d), p, 2);
 }
 
-function formatYear$1(d, p) {
-  return pad$1(d.getFullYear() % 100, p, 2);
+function formatYear(d, p) {
+  return pad(d.getFullYear() % 100, p, 2);
+}
+
+function formatYearISO(d, p) {
+  d = dISO(d);
+  return pad(d.getFullYear() % 100, p, 2);
 }
 
 function formatFullYear(d, p) {
-  return pad$1(d.getFullYear() % 10000, p, 4);
+  return pad(d.getFullYear() % 10000, p, 4);
+}
+
+function formatFullYearISO(d, p) {
+  var day = d.getDay();
+  d = (day >= 4 || day === 0) ? timeThursday(d) : timeThursday.ceil(d);
+  return pad(d.getFullYear() % 10000, p, 4);
 }
 
 function formatZone(d) {
   var z = d.getTimezoneOffset();
   return (z > 0 ? "-" : (z *= -1, "+"))
-      + pad$1(z / 60 | 0, "0", 2)
-      + pad$1(z % 60, "0", 2);
+      + pad(z / 60 | 0, "0", 2)
+      + pad(z % 60, "0", 2);
 }
 
 function formatUTCDayOfMonth(d, p) {
-  return pad$1(d.getUTCDate(), p, 2);
+  return pad(d.getUTCDate(), p, 2);
 }
 
 function formatUTCHour24(d, p) {
-  return pad$1(d.getUTCHours(), p, 2);
+  return pad(d.getUTCHours(), p, 2);
 }
 
 function formatUTCHour12(d, p) {
-  return pad$1(d.getUTCHours() % 12 || 12, p, 2);
+  return pad(d.getUTCHours() % 12 || 12, p, 2);
 }
 
 function formatUTCDayOfYear(d, p) {
-  return pad$1(1 + utcDay.count(utcYear(d), d), p, 3);
+  return pad(1 + utcDay.count(utcYear(d), d), p, 3);
 }
 
 function formatUTCMilliseconds(d, p) {
-  return pad$1(d.getUTCMilliseconds(), p, 3);
+  return pad(d.getUTCMilliseconds(), p, 3);
 }
 
 function formatUTCMicroseconds(d, p) {
@@ -13846,15 +16608,15 @@
 }
 
 function formatUTCMonthNumber(d, p) {
-  return pad$1(d.getUTCMonth() + 1, p, 2);
+  return pad(d.getUTCMonth() + 1, p, 2);
 }
 
 function formatUTCMinutes(d, p) {
-  return pad$1(d.getUTCMinutes(), p, 2);
+  return pad(d.getUTCMinutes(), p, 2);
 }
 
 function formatUTCSeconds(d, p) {
-  return pad$1(d.getUTCSeconds(), p, 2);
+  return pad(d.getUTCSeconds(), p, 2);
 }
 
 function formatUTCWeekdayNumberMonday(d) {
@@ -13863,13 +16625,17 @@
 }
 
 function formatUTCWeekNumberSunday(d, p) {
-  return pad$1(utcSunday.count(utcYear(d) - 1, d), p, 2);
+  return pad(utcSunday.count(utcYear(d) - 1, d), p, 2);
+}
+
+function UTCdISO(d) {
+  var day = d.getUTCDay();
+  return (day >= 4 || day === 0) ? utcThursday(d) : utcThursday.ceil(d);
 }
 
 function formatUTCWeekNumberISO(d, p) {
-  var day = d.getUTCDay();
-  d = (day >= 4 || day === 0) ? utcThursday(d) : utcThursday.ceil(d);
-  return pad$1(utcThursday.count(utcYear(d), d) + (utcYear(d).getUTCDay() === 4), p, 2);
+  d = UTCdISO(d);
+  return pad(utcThursday.count(utcYear(d), d) + (utcYear(d).getUTCDay() === 4), p, 2);
 }
 
 function formatUTCWeekdayNumberSunday(d) {
@@ -13877,15 +16643,26 @@
 }
 
 function formatUTCWeekNumberMonday(d, p) {
-  return pad$1(utcMonday.count(utcYear(d) - 1, d), p, 2);
+  return pad(utcMonday.count(utcYear(d) - 1, d), p, 2);
 }
 
 function formatUTCYear(d, p) {
-  return pad$1(d.getUTCFullYear() % 100, p, 2);
+  return pad(d.getUTCFullYear() % 100, p, 2);
+}
+
+function formatUTCYearISO(d, p) {
+  d = UTCdISO(d);
+  return pad(d.getUTCFullYear() % 100, p, 2);
 }
 
 function formatUTCFullYear(d, p) {
-  return pad$1(d.getUTCFullYear() % 10000, p, 4);
+  return pad(d.getUTCFullYear() % 10000, p, 4);
+}
+
+function formatUTCFullYearISO(d, p) {
+  var day = d.getUTCDay();
+  d = (day >= 4 || day === 0) ? utcThursday(d) : utcThursday.ceil(d);
+  return pad(d.getUTCFullYear() % 10000, p, 4);
 }
 
 function formatUTCZone() {
@@ -13904,9 +16681,13 @@
   return Math.floor(+d / 1000);
 }
 
-var locale$1;
+var locale;
+exports.timeFormat = void 0;
+exports.timeParse = void 0;
+exports.utcFormat = void 0;
+exports.utcParse = void 0;
 
-defaultLocale$1({
+defaultLocale({
   dateTime: "%x, %X",
   date: "%-m/%-d/%Y",
   time: "%-I:%M:%S %p",
@@ -13917,13 +16698,13 @@
   shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
 });
 
-function defaultLocale$1(definition) {
-  locale$1 = formatLocale$1(definition);
-  exports.timeFormat = locale$1.format;
-  exports.timeParse = locale$1.parse;
-  exports.utcFormat = locale$1.utcFormat;
-  exports.utcParse = locale$1.utcParse;
-  return locale$1;
+function defaultLocale(definition) {
+  locale = formatLocale(definition);
+  exports.timeFormat = locale.format;
+  exports.timeParse = locale.parse;
+  exports.utcFormat = locale.utcFormat;
+  exports.utcParse = locale.utcParse;
+  return locale;
 }
 
 var isoSpecifier = "%Y-%m-%dT%H:%M:%S.%LZ";
@@ -13936,6 +16717,8 @@
     ? formatIsoNative
     : exports.utcFormat(isoSpecifier);
 
+var formatIso$1 = formatIso;
+
 function parseIsoNative(string) {
   var date = new Date(string);
   return isNaN(date) ? null : date;
@@ -13945,24 +16728,18 @@
     ? parseIsoNative
     : exports.utcParse(isoSpecifier);
 
-var durationSecond$1 = 1000,
-    durationMinute$1 = durationSecond$1 * 60,
-    durationHour$1 = durationMinute$1 * 60,
-    durationDay$1 = durationHour$1 * 24,
-    durationWeek$1 = durationDay$1 * 7,
-    durationMonth = durationDay$1 * 30,
-    durationYear = durationDay$1 * 365;
+var parseIso$1 = parseIso;
 
-function date$1(t) {
+function date(t) {
   return new Date(t);
 }
 
-function number$3(t) {
+function number(t) {
   return t instanceof Date ? +t : +new Date(+t);
 }
 
-function calendar(year, month, week, day, hour, minute, second, millisecond, format) {
-  var scale = continuous(identity$6, identity$6),
+function calendar(ticks, tickInterval, year, month, week, day, hour, minute, second, format) {
+  var scale = continuous(),
       invert = scale.invert,
       domain = scale.domain;
 
@@ -13975,27 +16752,6 @@
       formatMonth = format("%B"),
       formatYear = format("%Y");
 
-  var tickIntervals = [
-    [second,  1,      durationSecond$1],
-    [second,  5,  5 * durationSecond$1],
-    [second, 15, 15 * durationSecond$1],
-    [second, 30, 30 * durationSecond$1],
-    [minute,  1,      durationMinute$1],
-    [minute,  5,  5 * durationMinute$1],
-    [minute, 15, 15 * durationMinute$1],
-    [minute, 30, 30 * durationMinute$1],
-    [  hour,  1,      durationHour$1  ],
-    [  hour,  3,  3 * durationHour$1  ],
-    [  hour,  6,  6 * durationHour$1  ],
-    [  hour, 12, 12 * durationHour$1  ],
-    [   day,  1,      durationDay$1   ],
-    [   day,  2,  2 * durationDay$1   ],
-    [  week,  1,      durationWeek$1  ],
-    [ month,  1,      durationMonth ],
-    [ month,  3,  3 * durationMonth ],
-    [  year,  1,      durationYear  ]
-  ];
-
   function tickFormat(date) {
     return (second(date) < date ? formatMillisecond
         : minute(date) < date ? formatSecond
@@ -14006,94 +16762,61 @@
         : formatYear)(date);
   }
 
-  function tickInterval(interval, start, stop, step) {
-    if (interval == null) interval = 10;
-
-    // If a desired tick count is specified, pick a reasonable tick interval
-    // based on the extent of the domain and a rough estimate of tick size.
-    // Otherwise, assume interval is already a time interval and use it.
-    if (typeof interval === "number") {
-      var target = Math.abs(stop - start) / interval,
-          i = bisector(function(i) { return i[2]; }).right(tickIntervals, target);
-      if (i === tickIntervals.length) {
-        step = tickStep(start / durationYear, stop / durationYear, interval);
-        interval = year;
-      } else if (i) {
-        i = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];
-        step = i[1];
-        interval = i[0];
-      } else {
-        step = Math.max(tickStep(start, stop, interval), 1);
-        interval = millisecond;
-      }
-    }
-
-    return step == null ? interval : interval.every(step);
-  }
-
   scale.invert = function(y) {
     return new Date(invert(y));
   };
 
   scale.domain = function(_) {
-    return arguments.length ? domain(map$3.call(_, number$3)) : domain().map(date$1);
+    return arguments.length ? domain(Array.from(_, number)) : domain().map(date);
   };
 
-  scale.ticks = function(interval, step) {
-    var d = domain(),
-        t0 = d[0],
-        t1 = d[d.length - 1],
-        r = t1 < t0,
-        t;
-    if (r) t = t0, t0 = t1, t1 = t;
-    t = tickInterval(interval, t0, t1, step);
-    t = t ? t.range(t0, t1 + 1) : []; // inclusive stop
-    return r ? t.reverse() : t;
+  scale.ticks = function(interval) {
+    var d = domain();
+    return ticks(d[0], d[d.length - 1], interval == null ? 10 : interval);
   };
 
   scale.tickFormat = function(count, specifier) {
     return specifier == null ? tickFormat : format(specifier);
   };
 
-  scale.nice = function(interval, step) {
+  scale.nice = function(interval) {
     var d = domain();
-    return (interval = tickInterval(interval, d[0], d[d.length - 1], step))
-        ? domain(nice(d, interval))
-        : scale;
+    if (!interval || typeof interval.range !== "function") interval = tickInterval(d[0], d[d.length - 1], interval == null ? 10 : interval);
+    return interval ? domain(nice(d, interval)) : scale;
   };
 
   scale.copy = function() {
-    return copy(scale, calendar(year, month, week, day, hour, minute, second, millisecond, format));
+    return copy$1(scale, calendar(ticks, tickInterval, year, month, week, day, hour, minute, second, format));
   };
 
   return scale;
 }
 
 function time() {
-  return initRange.apply(calendar(year, month, sunday, day, hour, minute, second, millisecond, exports.timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]), arguments);
+  return initRange.apply(calendar(timeTicks, timeTickInterval, timeYear, timeMonth, timeSunday, timeDay, timeHour, timeMinute, second, exports.timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]), arguments);
 }
 
 function utcTime() {
-  return initRange.apply(calendar(utcYear, utcMonth, utcSunday, utcDay, utcHour, utcMinute, second, millisecond, exports.utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]), arguments);
+  return initRange.apply(calendar(utcTicks, utcTickInterval, utcYear, utcMonth, utcSunday, utcDay, utcHour, utcMinute, second, exports.utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]), arguments);
 }
 
-function transformer$2() {
+function transformer$1() {
   var x0 = 0,
       x1 = 1,
       t0,
       t1,
       k10,
       transform,
-      interpolator = identity$6,
+      interpolator = identity$3,
       clamp = false,
       unknown;
 
   function scale(x) {
-    return isNaN(x = +x) ? unknown : interpolator(k10 === 0 ? 0.5 : (x = (transform(x) - t0) * k10, clamp ? Math.max(0, Math.min(1, x)) : x));
+    return x == null || isNaN(x = +x) ? unknown : interpolator(k10 === 0 ? 0.5 : (x = (transform(x) - t0) * k10, clamp ? Math.max(0, Math.min(1, x)) : x));
   }
 
   scale.domain = function(_) {
-    return arguments.length ? (t0 = transform(x0 = +_[0]), t1 = transform(x1 = +_[1]), k10 = t0 === t1 ? 0 : 1 / (t1 - t0), scale) : [x0, x1];
+    return arguments.length ? ([x0, x1] = _, t0 = transform(x0 = +x0), t1 = transform(x1 = +x1), k10 = t0 === t1 ? 0 : 1 / (t1 - t0), scale) : [x0, x1];
   };
 
   scale.clamp = function(_) {
@@ -14104,6 +16827,17 @@
     return arguments.length ? (interpolator = _, scale) : interpolator;
   };
 
+  function range(interpolate) {
+    return function(_) {
+      var r0, r1;
+      return arguments.length ? ([r0, r1] = _, interpolator = interpolate(r0, r1), scale) : [interpolator(0), interpolator(1)];
+    };
+  }
+
+  scale.range = range(interpolate$2);
+
+  scale.rangeRound = range(interpolateRound);
+
   scale.unknown = function(_) {
     return arguments.length ? (unknown = _, scale) : unknown;
   };
@@ -14114,7 +16848,7 @@
   };
 }
 
-function copy$1(source, target) {
+function copy(source, target) {
   return target
       .domain(source.domain())
       .interpolator(source.interpolator())
@@ -14123,40 +16857,40 @@
 }
 
 function sequential() {
-  var scale = linearish(transformer$2()(identity$6));
+  var scale = linearish(transformer$1()(identity$3));
 
   scale.copy = function() {
-    return copy$1(scale, sequential());
+    return copy(scale, sequential());
   };
 
   return initInterpolator.apply(scale, arguments);
 }
 
 function sequentialLog() {
-  var scale = loggish(transformer$2()).domain([1, 10]);
+  var scale = loggish(transformer$1()).domain([1, 10]);
 
   scale.copy = function() {
-    return copy$1(scale, sequentialLog()).base(scale.base());
+    return copy(scale, sequentialLog()).base(scale.base());
   };
 
   return initInterpolator.apply(scale, arguments);
 }
 
 function sequentialSymlog() {
-  var scale = symlogish(transformer$2());
+  var scale = symlogish(transformer$1());
 
   scale.copy = function() {
-    return copy$1(scale, sequentialSymlog()).constant(scale.constant());
+    return copy(scale, sequentialSymlog()).constant(scale.constant());
   };
 
   return initInterpolator.apply(scale, arguments);
 }
 
 function sequentialPow() {
-  var scale = powish(transformer$2());
+  var scale = powish(transformer$1());
 
   scale.copy = function() {
-    return copy$1(scale, sequentialPow()).exponent(scale.exponent());
+    return copy(scale, sequentialPow()).exponent(scale.exponent());
   };
 
   return initInterpolator.apply(scale, arguments);
@@ -14168,17 +16902,17 @@
 
 function sequentialQuantile() {
   var domain = [],
-      interpolator = identity$6;
+      interpolator = identity$3;
 
   function scale(x) {
-    if (!isNaN(x = +x)) return interpolator((bisectRight(domain, x) - 1) / (domain.length - 1));
+    if (x != null && !isNaN(x = +x)) return interpolator((bisect(domain, x, 1) - 1) / (domain.length - 1));
   }
 
   scale.domain = function(_) {
     if (!arguments.length) return domain.slice();
     domain = [];
-    for (var i = 0, n = _.length, d; i < n; ++i) if (d = _[i], d != null && !isNaN(d = +d)) domain.push(d);
-    domain.sort(ascending);
+    for (let d of _) if (d != null && !isNaN(d = +d)) domain.push(d);
+    domain.sort(ascending$3);
     return scale;
   };
 
@@ -14186,6 +16920,14 @@
     return arguments.length ? (interpolator = _, scale) : interpolator;
   };
 
+  scale.range = function() {
+    return domain.map((d, i) => interpolator(i / (domain.length - 1)));
+  };
+
+  scale.quantiles = function(n) {
+    return Array.from({length: n + 1}, (_, i) => quantile$1(domain, i / n));
+  };
+
   scale.copy = function() {
     return sequentialQuantile(interpolator).domain(domain);
   };
@@ -14193,26 +16935,27 @@
   return initInterpolator.apply(scale, arguments);
 }
 
-function transformer$3() {
+function transformer() {
   var x0 = 0,
       x1 = 0.5,
       x2 = 1,
+      s = 1,
       t0,
       t1,
       t2,
       k10,
       k21,
-      interpolator = identity$6,
+      interpolator = identity$3,
       transform,
       clamp = false,
       unknown;
 
   function scale(x) {
-    return isNaN(x = +x) ? unknown : (x = 0.5 + ((x = +transform(x)) - t1) * (x < t1 ? k10 : k21), interpolator(clamp ? Math.max(0, Math.min(1, x)) : x));
+    return isNaN(x = +x) ? unknown : (x = 0.5 + ((x = +transform(x)) - t1) * (s * x < s * t1 ? k10 : k21), interpolator(clamp ? Math.max(0, Math.min(1, x)) : x));
   }
 
   scale.domain = function(_) {
-    return arguments.length ? (t0 = transform(x0 = +_[0]), t1 = transform(x1 = +_[1]), t2 = transform(x2 = +_[2]), k10 = t0 === t1 ? 0 : 0.5 / (t1 - t0), k21 = t1 === t2 ? 0 : 0.5 / (t2 - t1), scale) : [x0, x1, x2];
+    return arguments.length ? ([x0, x1, x2] = _, t0 = transform(x0 = +x0), t1 = transform(x1 = +x1), t2 = transform(x2 = +x2), k10 = t0 === t1 ? 0 : 0.5 / (t1 - t0), k21 = t1 === t2 ? 0 : 0.5 / (t2 - t1), s = t1 < t0 ? -1 : 1, scale) : [x0, x1, x2];
   };
 
   scale.clamp = function(_) {
@@ -14223,51 +16966,62 @@
     return arguments.length ? (interpolator = _, scale) : interpolator;
   };
 
+  function range(interpolate) {
+    return function(_) {
+      var r0, r1, r2;
+      return arguments.length ? ([r0, r1, r2] = _, interpolator = piecewise(interpolate, [r0, r1, r2]), scale) : [interpolator(0), interpolator(0.5), interpolator(1)];
+    };
+  }
+
+  scale.range = range(interpolate$2);
+
+  scale.rangeRound = range(interpolateRound);
+
   scale.unknown = function(_) {
     return arguments.length ? (unknown = _, scale) : unknown;
   };
 
   return function(t) {
-    transform = t, t0 = t(x0), t1 = t(x1), t2 = t(x2), k10 = t0 === t1 ? 0 : 0.5 / (t1 - t0), k21 = t1 === t2 ? 0 : 0.5 / (t2 - t1);
+    transform = t, t0 = t(x0), t1 = t(x1), t2 = t(x2), k10 = t0 === t1 ? 0 : 0.5 / (t1 - t0), k21 = t1 === t2 ? 0 : 0.5 / (t2 - t1), s = t1 < t0 ? -1 : 1;
     return scale;
   };
 }
 
-function diverging() {
-  var scale = linearish(transformer$3()(identity$6));
+function diverging$1() {
+  var scale = linearish(transformer()(identity$3));
 
   scale.copy = function() {
-    return copy$1(scale, diverging());
+    return copy(scale, diverging$1());
   };
 
   return initInterpolator.apply(scale, arguments);
 }
 
 function divergingLog() {
-  var scale = loggish(transformer$3()).domain([0.1, 1, 10]);
+  var scale = loggish(transformer()).domain([0.1, 1, 10]);
 
   scale.copy = function() {
-    return copy$1(scale, divergingLog()).base(scale.base());
+    return copy(scale, divergingLog()).base(scale.base());
   };
 
   return initInterpolator.apply(scale, arguments);
 }
 
 function divergingSymlog() {
-  var scale = symlogish(transformer$3());
+  var scale = symlogish(transformer());
 
   scale.copy = function() {
-    return copy$1(scale, divergingSymlog()).constant(scale.constant());
+    return copy(scale, divergingSymlog()).constant(scale.constant());
   };
 
   return initInterpolator.apply(scale, arguments);
 }
 
 function divergingPow() {
-  var scale = powish(transformer$3());
+  var scale = powish(transformer());
 
   scale.copy = function() {
-    return copy$1(scale, divergingPow()).exponent(scale.exponent());
+    return copy(scale, divergingPow()).exponent(scale.exponent());
   };
 
   return initInterpolator.apply(scale, arguments);
@@ -14303,11 +17057,9 @@
 
 var Tableau10 = colors("4e79a7f28e2ce1575976b7b259a14fedc949af7aa1ff9da79c755fbab0ab");
 
-function ramp(scheme) {
-  return rgbBasis(scheme[scheme.length - 1]);
-}
+var ramp$1 = scheme => rgbBasis(scheme[scheme.length - 1]);
 
-var scheme = new Array(3).concat(
+var scheme$q = new Array(3).concat(
   "d8b365f5f5f55ab4ac",
   "a6611adfc27d80cdc1018571",
   "a6611adfc27df5f5f580cdc1018571",
@@ -14319,9 +17071,9 @@
   "5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30"
 ).map(colors);
 
-var BrBG = ramp(scheme);
+var BrBG = ramp$1(scheme$q);
 
-var scheme$1 = new Array(3).concat(
+var scheme$p = new Array(3).concat(
   "af8dc3f7f7f77fbf7b",
   "7b3294c2a5cfa6dba0008837",
   "7b3294c2a5cff7f7f7a6dba0008837",
@@ -14333,9 +17085,9 @@
   "40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b"
 ).map(colors);
 
-var PRGn = ramp(scheme$1);
+var PRGn = ramp$1(scheme$p);
 
-var scheme$2 = new Array(3).concat(
+var scheme$o = new Array(3).concat(
   "e9a3c9f7f7f7a1d76a",
   "d01c8bf1b6dab8e1864dac26",
   "d01c8bf1b6daf7f7f7b8e1864dac26",
@@ -14347,9 +17099,9 @@
   "8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419"
 ).map(colors);
 
-var PiYG = ramp(scheme$2);
+var PiYG = ramp$1(scheme$o);
 
-var scheme$3 = new Array(3).concat(
+var scheme$n = new Array(3).concat(
   "998ec3f7f7f7f1a340",
   "5e3c99b2abd2fdb863e66101",
   "5e3c99b2abd2f7f7f7fdb863e66101",
@@ -14361,9 +17113,9 @@
   "2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08"
 ).map(colors);
 
-var PuOr = ramp(scheme$3);
+var PuOr = ramp$1(scheme$n);
 
-var scheme$4 = new Array(3).concat(
+var scheme$m = new Array(3).concat(
   "ef8a62f7f7f767a9cf",
   "ca0020f4a58292c5de0571b0",
   "ca0020f4a582f7f7f792c5de0571b0",
@@ -14375,9 +17127,9 @@
   "67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061"
 ).map(colors);
 
-var RdBu = ramp(scheme$4);
+var RdBu = ramp$1(scheme$m);
 
-var scheme$5 = new Array(3).concat(
+var scheme$l = new Array(3).concat(
   "ef8a62ffffff999999",
   "ca0020f4a582bababa404040",
   "ca0020f4a582ffffffbababa404040",
@@ -14389,9 +17141,9 @@
   "67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a"
 ).map(colors);
 
-var RdGy = ramp(scheme$5);
+var RdGy = ramp$1(scheme$l);
 
-var scheme$6 = new Array(3).concat(
+var scheme$k = new Array(3).concat(
   "fc8d59ffffbf91bfdb",
   "d7191cfdae61abd9e92c7bb6",
   "d7191cfdae61ffffbfabd9e92c7bb6",
@@ -14403,9 +17155,9 @@
   "a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695"
 ).map(colors);
 
-var RdYlBu = ramp(scheme$6);
+var RdYlBu = ramp$1(scheme$k);
 
-var scheme$7 = new Array(3).concat(
+var scheme$j = new Array(3).concat(
   "fc8d59ffffbf91cf60",
   "d7191cfdae61a6d96a1a9641",
   "d7191cfdae61ffffbfa6d96a1a9641",
@@ -14417,9 +17169,9 @@
   "a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837"
 ).map(colors);
 
-var RdYlGn = ramp(scheme$7);
+var RdYlGn = ramp$1(scheme$j);
 
-var scheme$8 = new Array(3).concat(
+var scheme$i = new Array(3).concat(
   "fc8d59ffffbf99d594",
   "d7191cfdae61abdda42b83ba",
   "d7191cfdae61ffffbfabdda42b83ba",
@@ -14431,9 +17183,9 @@
   "9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2"
 ).map(colors);
 
-var Spectral = ramp(scheme$8);
+var Spectral = ramp$1(scheme$i);
 
-var scheme$9 = new Array(3).concat(
+var scheme$h = new Array(3).concat(
   "e5f5f999d8c92ca25f",
   "edf8fbb2e2e266c2a4238b45",
   "edf8fbb2e2e266c2a42ca25f006d2c",
@@ -14443,9 +17195,9 @@
   "f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b"
 ).map(colors);
 
-var BuGn = ramp(scheme$9);
+var BuGn = ramp$1(scheme$h);
 
-var scheme$a = new Array(3).concat(
+var scheme$g = new Array(3).concat(
   "e0ecf49ebcda8856a7",
   "edf8fbb3cde38c96c688419d",
   "edf8fbb3cde38c96c68856a7810f7c",
@@ -14455,9 +17207,9 @@
   "f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b"
 ).map(colors);
 
-var BuPu = ramp(scheme$a);
+var BuPu = ramp$1(scheme$g);
 
-var scheme$b = new Array(3).concat(
+var scheme$f = new Array(3).concat(
   "e0f3dba8ddb543a2ca",
   "f0f9e8bae4bc7bccc42b8cbe",
   "f0f9e8bae4bc7bccc443a2ca0868ac",
@@ -14467,9 +17219,9 @@
   "f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081"
 ).map(colors);
 
-var GnBu = ramp(scheme$b);
+var GnBu = ramp$1(scheme$f);
 
-var scheme$c = new Array(3).concat(
+var scheme$e = new Array(3).concat(
   "fee8c8fdbb84e34a33",
   "fef0d9fdcc8afc8d59d7301f",
   "fef0d9fdcc8afc8d59e34a33b30000",
@@ -14479,7 +17231,7 @@
   "fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000"
 ).map(colors);
 
-var OrRd = ramp(scheme$c);
+var OrRd = ramp$1(scheme$e);
 
 var scheme$d = new Array(3).concat(
   "ece2f0a6bddb1c9099",
@@ -14491,9 +17243,9 @@
   "fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636"
 ).map(colors);
 
-var PuBuGn = ramp(scheme$d);
+var PuBuGn = ramp$1(scheme$d);
 
-var scheme$e = new Array(3).concat(
+var scheme$c = new Array(3).concat(
   "ece7f2a6bddb2b8cbe",
   "f1eef6bdc9e174a9cf0570b0",
   "f1eef6bdc9e174a9cf2b8cbe045a8d",
@@ -14503,9 +17255,9 @@
   "fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858"
 ).map(colors);
 
-var PuBu = ramp(scheme$e);
+var PuBu = ramp$1(scheme$c);
 
-var scheme$f = new Array(3).concat(
+var scheme$b = new Array(3).concat(
   "e7e1efc994c7dd1c77",
   "f1eef6d7b5d8df65b0ce1256",
   "f1eef6d7b5d8df65b0dd1c77980043",
@@ -14515,9 +17267,9 @@
   "f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f"
 ).map(colors);
 
-var PuRd = ramp(scheme$f);
+var PuRd = ramp$1(scheme$b);
 
-var scheme$g = new Array(3).concat(
+var scheme$a = new Array(3).concat(
   "fde0ddfa9fb5c51b8a",
   "feebe2fbb4b9f768a1ae017e",
   "feebe2fbb4b9f768a1c51b8a7a0177",
@@ -14527,9 +17279,9 @@
   "fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a"
 ).map(colors);
 
-var RdPu = ramp(scheme$g);
+var RdPu = ramp$1(scheme$a);
 
-var scheme$h = new Array(3).concat(
+var scheme$9 = new Array(3).concat(
   "edf8b17fcdbb2c7fb8",
   "ffffcca1dab441b6c4225ea8",
   "ffffcca1dab441b6c42c7fb8253494",
@@ -14539,9 +17291,9 @@
   "ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58"
 ).map(colors);
 
-var YlGnBu = ramp(scheme$h);
+var YlGnBu = ramp$1(scheme$9);
 
-var scheme$i = new Array(3).concat(
+var scheme$8 = new Array(3).concat(
   "f7fcb9addd8e31a354",
   "ffffccc2e69978c679238443",
   "ffffccc2e69978c67931a354006837",
@@ -14551,9 +17303,9 @@
   "ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529"
 ).map(colors);
 
-var YlGn = ramp(scheme$i);
+var YlGn = ramp$1(scheme$8);
 
-var scheme$j = new Array(3).concat(
+var scheme$7 = new Array(3).concat(
   "fff7bcfec44fd95f0e",
   "ffffd4fed98efe9929cc4c02",
   "ffffd4fed98efe9929d95f0e993404",
@@ -14563,9 +17315,9 @@
   "ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506"
 ).map(colors);
 
-var YlOrBr = ramp(scheme$j);
+var YlOrBr = ramp$1(scheme$7);
 
-var scheme$k = new Array(3).concat(
+var scheme$6 = new Array(3).concat(
   "ffeda0feb24cf03b20",
   "ffffb2fecc5cfd8d3ce31a1c",
   "ffffb2fecc5cfd8d3cf03b20bd0026",
@@ -14575,9 +17327,9 @@
   "ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026"
 ).map(colors);
 
-var YlOrRd = ramp(scheme$k);
+var YlOrRd = ramp$1(scheme$6);
 
-var scheme$l = new Array(3).concat(
+var scheme$5 = new Array(3).concat(
   "deebf79ecae13182bd",
   "eff3ffbdd7e76baed62171b5",
   "eff3ffbdd7e76baed63182bd08519c",
@@ -14587,9 +17339,9 @@
   "f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b"
 ).map(colors);
 
-var Blues = ramp(scheme$l);
+var Blues = ramp$1(scheme$5);
 
-var scheme$m = new Array(3).concat(
+var scheme$4 = new Array(3).concat(
   "e5f5e0a1d99b31a354",
   "edf8e9bae4b374c476238b45",
   "edf8e9bae4b374c47631a354006d2c",
@@ -14599,9 +17351,9 @@
   "f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b"
 ).map(colors);
 
-var Greens = ramp(scheme$m);
+var Greens = ramp$1(scheme$4);
 
-var scheme$n = new Array(3).concat(
+var scheme$3 = new Array(3).concat(
   "f0f0f0bdbdbd636363",
   "f7f7f7cccccc969696525252",
   "f7f7f7cccccc969696636363252525",
@@ -14611,9 +17363,9 @@
   "fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000"
 ).map(colors);
 
-var Greys = ramp(scheme$n);
+var Greys = ramp$1(scheme$3);
 
-var scheme$o = new Array(3).concat(
+var scheme$2 = new Array(3).concat(
   "efedf5bcbddc756bb1",
   "f2f0f7cbc9e29e9ac86a51a3",
   "f2f0f7cbc9e29e9ac8756bb154278f",
@@ -14623,9 +17375,9 @@
   "fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d"
 ).map(colors);
 
-var Purples = ramp(scheme$o);
+var Purples = ramp$1(scheme$2);
 
-var scheme$p = new Array(3).concat(
+var scheme$1 = new Array(3).concat(
   "fee0d2fc9272de2d26",
   "fee5d9fcae91fb6a4acb181d",
   "fee5d9fcae91fb6a4ade2d26a50f15",
@@ -14635,9 +17387,9 @@
   "fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d"
 ).map(colors);
 
-var Reds = ramp(scheme$p);
+var Reds = ramp$1(scheme$1);
 
-var scheme$q = new Array(3).concat(
+var scheme = new Array(3).concat(
   "fee6cefdae6be6550d",
   "feeddefdbe85fd8d3cd94701",
   "feeddefdbe85fd8d3ce6550da63603",
@@ -14647,7 +17399,7 @@
   "fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704"
 ).map(colors);
 
-var Oranges = ramp(scheme$q);
+var Oranges = ramp$1(scheme);
 
 function cividis(t) {
   t = Math.max(0, Math.min(1, t));
@@ -14658,21 +17410,21 @@
       + ")";
 }
 
-var cubehelix$3 = cubehelixLong(cubehelix(300, 0.5, 0.0), cubehelix(-240, 0.5, 1.0));
+var cubehelix = cubehelixLong(cubehelix$3(300, 0.5, 0.0), cubehelix$3(-240, 0.5, 1.0));
 
-var warm = cubehelixLong(cubehelix(-100, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
+var warm = cubehelixLong(cubehelix$3(-100, 0.75, 0.35), cubehelix$3(80, 1.50, 0.8));
 
-var cool = cubehelixLong(cubehelix(260, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
+var cool = cubehelixLong(cubehelix$3(260, 0.75, 0.35), cubehelix$3(80, 1.50, 0.8));
 
-var c = cubehelix();
+var c$2 = cubehelix$3();
 
 function rainbow(t) {
   if (t < 0 || t > 1) t -= Math.floor(t);
   var ts = Math.abs(t - 0.5);
-  c.h = 360 * t - 100;
-  c.s = 1.5 - 1.5 * ts;
-  c.l = 0.8 - 0.9 * ts;
-  return c + "";
+  c$2.h = 360 * t - 100;
+  c$2.s = 1.5 - 1.5 * ts;
+  c$2.l = 0.8 - 0.9 * ts;
+  return c$2 + "";
 }
 
 var c$1 = rgb(),
@@ -14697,46 +17449,64 @@
       + ")";
 }
 
-function ramp$1(range) {
+function ramp(range) {
   var n = range.length;
   return function(t) {
     return range[Math.max(0, Math.min(n - 1, Math.floor(t * n)))];
   };
 }
 
-var viridis = ramp$1(colors("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725"));
+var viridis = ramp(colors("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725"));
 
-var magma = ramp$1(colors("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf"));
+var magma = ramp(colors("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf"));
 
-var inferno = ramp$1(colors("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4"));
+var inferno = ramp(colors("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4"));
 
-var plasma = ramp$1(colors("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));
+var plasma = ramp(colors("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));
 
-function constant$b(x) {
+function constant$1(x) {
   return function constant() {
     return x;
   };
 }
 
-var abs$1 = Math.abs;
-var atan2$1 = Math.atan2;
-var cos$2 = Math.cos;
-var max$2 = Math.max;
-var min$1 = Math.min;
-var sin$2 = Math.sin;
-var sqrt$2 = Math.sqrt;
+const abs = Math.abs;
+const atan2 = Math.atan2;
+const cos = Math.cos;
+const max = Math.max;
+const min = Math.min;
+const sin = Math.sin;
+const sqrt = Math.sqrt;
 
-var epsilon$3 = 1e-12;
-var pi$4 = Math.PI;
-var halfPi$3 = pi$4 / 2;
-var tau$4 = 2 * pi$4;
+const epsilon = 1e-12;
+const pi = Math.PI;
+const halfPi = pi / 2;
+const tau = 2 * pi;
 
-function acos$1(x) {
-  return x > 1 ? 0 : x < -1 ? pi$4 : Math.acos(x);
+function acos(x) {
+  return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);
 }
 
-function asin$1(x) {
-  return x >= 1 ? halfPi$3 : x <= -1 ? -halfPi$3 : Math.asin(x);
+function asin(x) {
+  return x >= 1 ? halfPi : x <= -1 ? -halfPi : Math.asin(x);
+}
+
+function withPath(shape) {
+  let digits = 3;
+
+  shape.digits = function(_) {
+    if (!arguments.length) return digits;
+    if (_ == null) {
+      digits = null;
+    } else {
+      const d = Math.floor(_);
+      if (!(d >= 0)) throw new RangeError(`invalid digits: ${_}`);
+      digits = d;
+    }
+    return shape;
+  };
+
+  return () => new Path$1(digits);
 }
 
 function arcInnerRadius(d) {
@@ -14763,7 +17533,7 @@
   var x10 = x1 - x0, y10 = y1 - y0,
       x32 = x3 - x2, y32 = y3 - y2,
       t = y32 * x10 - x32 * y10;
-  if (t * t < epsilon$3) return;
+  if (t * t < epsilon) return;
   t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t;
   return [x0 + t * x10, y0 + t * y10];
 }
@@ -14773,7 +17543,7 @@
 function cornerTangents(x0, y0, x1, y1, r1, rc, cw) {
   var x01 = x0 - x1,
       y01 = y0 - y1,
-      lo = (cw ? rc : -rc) / sqrt$2(x01 * x01 + y01 * y01),
+      lo = (cw ? rc : -rc) / sqrt(x01 * x01 + y01 * y01),
       ox = lo * y01,
       oy = -lo * x01,
       x11 = x0 + ox,
@@ -14787,7 +17557,7 @@
       d2 = dx * dx + dy * dy,
       r = r1 - rc,
       D = x11 * y10 - x10 * y11,
-      d = (dy < 0 ? -1 : 1) * sqrt$2(max$2(0, r * r * d2 - D * D)),
+      d = (dy < 0 ? -1 : 1) * sqrt(max(0, r * r * d2 - D * D)),
       cx0 = (D * dy - dx * d) / d2,
       cy0 = (-D * dx - dy * d) / d2,
       cx1 = (D * dy + dx * d) / d2,
@@ -14814,21 +17584,22 @@
 function arc() {
   var innerRadius = arcInnerRadius,
       outerRadius = arcOuterRadius,
-      cornerRadius = constant$b(0),
+      cornerRadius = constant$1(0),
       padRadius = null,
       startAngle = arcStartAngle,
       endAngle = arcEndAngle,
       padAngle = arcPadAngle,
-      context = null;
+      context = null,
+      path = withPath(arc);
 
   function arc() {
     var buffer,
         r,
         r0 = +innerRadius.apply(this, arguments),
         r1 = +outerRadius.apply(this, arguments),
-        a0 = startAngle.apply(this, arguments) - halfPi$3,
-        a1 = endAngle.apply(this, arguments) - halfPi$3,
-        da = abs$1(a1 - a0),
+        a0 = startAngle.apply(this, arguments) - halfPi,
+        a1 = endAngle.apply(this, arguments) - halfPi,
+        da = abs(a1 - a0),
         cw = a1 > a0;
 
     if (!context) context = buffer = path();
@@ -14837,14 +17608,14 @@
     if (r1 < r0) r = r1, r1 = r0, r0 = r;
 
     // Is it a point?
-    if (!(r1 > epsilon$3)) context.moveTo(0, 0);
+    if (!(r1 > epsilon)) context.moveTo(0, 0);
 
     // Or is it a circle or annulus?
-    else if (da > tau$4 - epsilon$3) {
-      context.moveTo(r1 * cos$2(a0), r1 * sin$2(a0));
+    else if (da > tau - epsilon) {
+      context.moveTo(r1 * cos(a0), r1 * sin(a0));
       context.arc(0, 0, r1, a0, a1, !cw);
-      if (r0 > epsilon$3) {
-        context.moveTo(r0 * cos$2(a1), r0 * sin$2(a1));
+      if (r0 > epsilon) {
+        context.moveTo(r0 * cos(a1), r0 * sin(a1));
         context.arc(0, 0, r0, a1, a0, cw);
       }
     }
@@ -14858,67 +17629,73 @@
           da0 = da,
           da1 = da,
           ap = padAngle.apply(this, arguments) / 2,
-          rp = (ap > epsilon$3) && (padRadius ? +padRadius.apply(this, arguments) : sqrt$2(r0 * r0 + r1 * r1)),
-          rc = min$1(abs$1(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),
+          rp = (ap > epsilon) && (padRadius ? +padRadius.apply(this, arguments) : sqrt(r0 * r0 + r1 * r1)),
+          rc = min(abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),
           rc0 = rc,
           rc1 = rc,
           t0,
           t1;
 
       // Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.
-      if (rp > epsilon$3) {
-        var p0 = asin$1(rp / r0 * sin$2(ap)),
-            p1 = asin$1(rp / r1 * sin$2(ap));
-        if ((da0 -= p0 * 2) > epsilon$3) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;
+      if (rp > epsilon) {
+        var p0 = asin(rp / r0 * sin(ap)),
+            p1 = asin(rp / r1 * sin(ap));
+        if ((da0 -= p0 * 2) > epsilon) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;
         else da0 = 0, a00 = a10 = (a0 + a1) / 2;
-        if ((da1 -= p1 * 2) > epsilon$3) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;
+        if ((da1 -= p1 * 2) > epsilon) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;
         else da1 = 0, a01 = a11 = (a0 + a1) / 2;
       }
 
-      var x01 = r1 * cos$2(a01),
-          y01 = r1 * sin$2(a01),
-          x10 = r0 * cos$2(a10),
-          y10 = r0 * sin$2(a10);
+      var x01 = r1 * cos(a01),
+          y01 = r1 * sin(a01),
+          x10 = r0 * cos(a10),
+          y10 = r0 * sin(a10);
 
       // Apply rounded corners?
-      if (rc > epsilon$3) {
-        var x11 = r1 * cos$2(a11),
-            y11 = r1 * sin$2(a11),
-            x00 = r0 * cos$2(a00),
-            y00 = r0 * sin$2(a00),
+      if (rc > epsilon) {
+        var x11 = r1 * cos(a11),
+            y11 = r1 * sin(a11),
+            x00 = r0 * cos(a00),
+            y00 = r0 * sin(a00),
             oc;
 
-        // Restrict the corner radius according to the sector angle.
-        if (da < pi$4 && (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10))) {
-          var ax = x01 - oc[0],
-              ay = y01 - oc[1],
-              bx = x11 - oc[0],
-              by = y11 - oc[1],
-              kc = 1 / sin$2(acos$1((ax * bx + ay * by) / (sqrt$2(ax * ax + ay * ay) * sqrt$2(bx * bx + by * by))) / 2),
-              lc = sqrt$2(oc[0] * oc[0] + oc[1] * oc[1]);
-          rc0 = min$1(rc, (r0 - lc) / (kc - 1));
-          rc1 = min$1(rc, (r1 - lc) / (kc + 1));
+        // Restrict the corner radius according to the sector angle. If this
+        // intersection fails, it’s probably because the arc is too small, so
+        // disable the corner radius entirely.
+        if (da < pi) {
+          if (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10)) {
+            var ax = x01 - oc[0],
+                ay = y01 - oc[1],
+                bx = x11 - oc[0],
+                by = y11 - oc[1],
+                kc = 1 / sin(acos((ax * bx + ay * by) / (sqrt(ax * ax + ay * ay) * sqrt(bx * bx + by * by))) / 2),
+                lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
+            rc0 = min(rc, (r0 - lc) / (kc - 1));
+            rc1 = min(rc, (r1 - lc) / (kc + 1));
+          } else {
+            rc0 = rc1 = 0;
+          }
         }
       }
 
       // Is the sector collapsed to a line?
-      if (!(da1 > epsilon$3)) context.moveTo(x01, y01);
+      if (!(da1 > epsilon)) context.moveTo(x01, y01);
 
       // Does the sector’s outer ring have rounded corners?
-      else if (rc1 > epsilon$3) {
+      else if (rc1 > epsilon) {
         t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);
         t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);
 
         context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);
 
         // Have the corners merged?
-        if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2$1(t0.y01, t0.x01), atan2$1(t1.y01, t1.x01), !cw);
+        if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);
 
         // Otherwise, draw the two corners and the ring.
         else {
-          context.arc(t0.cx, t0.cy, rc1, atan2$1(t0.y01, t0.x01), atan2$1(t0.y11, t0.x11), !cw);
-          context.arc(0, 0, r1, atan2$1(t0.cy + t0.y11, t0.cx + t0.x11), atan2$1(t1.cy + t1.y11, t1.cx + t1.x11), !cw);
-          context.arc(t1.cx, t1.cy, rc1, atan2$1(t1.y11, t1.x11), atan2$1(t1.y01, t1.x01), !cw);
+          context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);
+          context.arc(0, 0, r1, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), !cw);
+          context.arc(t1.cx, t1.cy, rc1, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);
         }
       }
 
@@ -14927,23 +17704,23 @@
 
       // Is there no inner ring, and it’s a circular sector?
       // Or perhaps it’s an annular sector collapsed due to padding?
-      if (!(r0 > epsilon$3) || !(da0 > epsilon$3)) context.lineTo(x10, y10);
+      if (!(r0 > epsilon) || !(da0 > epsilon)) context.lineTo(x10, y10);
 
       // Does the sector’s inner ring (or point) have rounded corners?
-      else if (rc0 > epsilon$3) {
+      else if (rc0 > epsilon) {
         t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);
         t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);
 
         context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);
 
         // Have the corners merged?
-        if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2$1(t0.y01, t0.x01), atan2$1(t1.y01, t1.x01), !cw);
+        if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);
 
         // Otherwise, draw the two corners and the ring.
         else {
-          context.arc(t0.cx, t0.cy, rc0, atan2$1(t0.y01, t0.x01), atan2$1(t0.y11, t0.x11), !cw);
-          context.arc(0, 0, r0, atan2$1(t0.cy + t0.y11, t0.cx + t0.x11), atan2$1(t1.cy + t1.y11, t1.cx + t1.x11), cw);
-          context.arc(t1.cx, t1.cy, rc0, atan2$1(t1.y11, t1.x11), atan2$1(t1.y01, t1.x01), !cw);
+          context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);
+          context.arc(0, 0, r0, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), cw);
+          context.arc(t1.cx, t1.cy, rc0, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);
         }
       }
 
@@ -14958,36 +17735,36 @@
 
   arc.centroid = function() {
     var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,
-        a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi$4 / 2;
-    return [cos$2(a) * r, sin$2(a) * r];
+        a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi / 2;
+    return [cos(a) * r, sin(a) * r];
   };
 
   arc.innerRadius = function(_) {
-    return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant$b(+_), arc) : innerRadius;
+    return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant$1(+_), arc) : innerRadius;
   };
 
   arc.outerRadius = function(_) {
-    return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant$b(+_), arc) : outerRadius;
+    return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant$1(+_), arc) : outerRadius;
   };
 
   arc.cornerRadius = function(_) {
-    return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant$b(+_), arc) : cornerRadius;
+    return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant$1(+_), arc) : cornerRadius;
   };
 
   arc.padRadius = function(_) {
-    return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant$b(+_), arc) : padRadius;
+    return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant$1(+_), arc) : padRadius;
   };
 
   arc.startAngle = function(_) {
-    return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$b(+_), arc) : startAngle;
+    return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$1(+_), arc) : startAngle;
   };
 
   arc.endAngle = function(_) {
-    return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$b(+_), arc) : endAngle;
+    return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$1(+_), arc) : endAngle;
   };
 
   arc.padAngle = function(_) {
-    return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$b(+_), arc) : padAngle;
+    return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$1(+_), arc) : padAngle;
   };
 
   arc.context = function(_) {
@@ -14997,6 +17774,14 @@
   return arc;
 }
 
+var slice = Array.prototype.slice;
+
+function array(x) {
+  return typeof x === "object" && "length" in x
+    ? x // Array, TypedArray, NodeList, array-like
+    : Array.from(x); // Map, Set, iterable, string, or anything else
+}
+
 function Linear(context) {
   this._context = context;
 }
@@ -15019,7 +17804,7 @@
     x = +x, y = +y;
     switch (this._point) {
       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
-      case 1: this._point = 2; // proceed
+      case 1: this._point = 2; // falls through
       default: this._context.lineTo(x, y); break;
     }
   }
@@ -15029,25 +17814,27 @@
   return new Linear(context);
 }
 
-function x$3(p) {
+function x(p) {
   return p[0];
 }
 
-function y$3(p) {
+function y(p) {
   return p[1];
 }
 
-function line() {
-  var x = x$3,
-      y = y$3,
-      defined = constant$b(true),
+function line(x$1, y$1) {
+  var defined = constant$1(true),
       context = null,
       curve = curveLinear,
-      output = null;
+      output = null,
+      path = withPath(line);
+
+  x$1 = typeof x$1 === "function" ? x$1 : (x$1 === undefined) ? x : constant$1(x$1);
+  y$1 = typeof y$1 === "function" ? y$1 : (y$1 === undefined) ? y : constant$1(y$1);
 
   function line(data) {
     var i,
-        n = data.length,
+        n = (data = array(data)).length,
         d,
         defined0 = false,
         buffer;
@@ -15059,22 +17846,22 @@
         if (defined0 = !defined0) output.lineStart();
         else output.lineEnd();
       }
-      if (defined0) output.point(+x(d, i, data), +y(d, i, data));
+      if (defined0) output.point(+x$1(d, i, data), +y$1(d, i, data));
     }
 
     if (buffer) return output = null, buffer + "" || null;
   }
 
   line.x = function(_) {
-    return arguments.length ? (x = typeof _ === "function" ? _ : constant$b(+_), line) : x;
+    return arguments.length ? (x$1 = typeof _ === "function" ? _ : constant$1(+_), line) : x$1;
   };
 
   line.y = function(_) {
-    return arguments.length ? (y = typeof _ === "function" ? _ : constant$b(+_), line) : y;
+    return arguments.length ? (y$1 = typeof _ === "function" ? _ : constant$1(+_), line) : y$1;
   };
 
   line.defined = function(_) {
-    return arguments.length ? (defined = typeof _ === "function" ? _ : constant$b(!!_), line) : defined;
+    return arguments.length ? (defined = typeof _ === "function" ? _ : constant$1(!!_), line) : defined;
   };
 
   line.curve = function(_) {
@@ -15088,21 +17875,23 @@
   return line;
 }
 
-function area$3() {
-  var x0 = x$3,
-      x1 = null,
-      y0 = constant$b(0),
-      y1 = y$3,
-      defined = constant$b(true),
+function area(x0, y0, y1) {
+  var x1 = null,
+      defined = constant$1(true),
       context = null,
       curve = curveLinear,
-      output = null;
+      output = null,
+      path = withPath(area);
+
+  x0 = typeof x0 === "function" ? x0 : (x0 === undefined) ? x : constant$1(+x0);
+  y0 = typeof y0 === "function" ? y0 : (y0 === undefined) ? constant$1(0) : constant$1(+y0);
+  y1 = typeof y1 === "function" ? y1 : (y1 === undefined) ? y : constant$1(+y1);
 
   function area(data) {
     var i,
         j,
         k,
-        n = data.length,
+        n = (data = array(data)).length,
         d,
         defined0 = false,
         buffer,
@@ -15141,27 +17930,27 @@
   }
 
   area.x = function(_) {
-    return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$b(+_), x1 = null, area) : x0;
+    return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$1(+_), x1 = null, area) : x0;
   };
 
   area.x0 = function(_) {
-    return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$b(+_), area) : x0;
+    return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$1(+_), area) : x0;
   };
 
   area.x1 = function(_) {
-    return arguments.length ? (x1 = _ == null ? null : typeof _ === "function" ? _ : constant$b(+_), area) : x1;
+    return arguments.length ? (x1 = _ == null ? null : typeof _ === "function" ? _ : constant$1(+_), area) : x1;
   };
 
   area.y = function(_) {
-    return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$b(+_), y1 = null, area) : y0;
+    return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$1(+_), y1 = null, area) : y0;
   };
 
   area.y0 = function(_) {
-    return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$b(+_), area) : y0;
+    return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$1(+_), area) : y0;
   };
 
   area.y1 = function(_) {
-    return arguments.length ? (y1 = _ == null ? null : typeof _ === "function" ? _ : constant$b(+_), area) : y1;
+    return arguments.length ? (y1 = _ == null ? null : typeof _ === "function" ? _ : constant$1(+_), area) : y1;
   };
 
   area.lineX0 =
@@ -15178,7 +17967,7 @@
   };
 
   area.defined = function(_) {
-    return arguments.length ? (defined = typeof _ === "function" ? _ : constant$b(!!_), area) : defined;
+    return arguments.length ? (defined = typeof _ === "function" ? _ : constant$1(!!_), area) : defined;
   };
 
   area.curve = function(_) {
@@ -15196,28 +17985,28 @@
   return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
 }
 
-function identity$8(d) {
+function identity$1(d) {
   return d;
 }
 
 function pie() {
-  var value = identity$8,
+  var value = identity$1,
       sortValues = descending$1,
       sort = null,
-      startAngle = constant$b(0),
-      endAngle = constant$b(tau$4),
-      padAngle = constant$b(0);
+      startAngle = constant$1(0),
+      endAngle = constant$1(tau),
+      padAngle = constant$1(0);
 
   function pie(data) {
     var i,
-        n = data.length,
+        n = (data = array(data)).length,
         j,
         k,
         sum = 0,
         index = new Array(n),
         arcs = new Array(n),
         a0 = +startAngle.apply(this, arguments),
-        da = Math.min(tau$4, Math.max(-tau$4, endAngle.apply(this, arguments) - a0)),
+        da = Math.min(tau, Math.max(-tau, endAngle.apply(this, arguments) - a0)),
         a1,
         p = Math.min(Math.abs(da) / n, padAngle.apply(this, arguments)),
         pa = p * (da < 0 ? -1 : 1),
@@ -15249,7 +18038,7 @@
   }
 
   pie.value = function(_) {
-    return arguments.length ? (value = typeof _ === "function" ? _ : constant$b(+_), pie) : value;
+    return arguments.length ? (value = typeof _ === "function" ? _ : constant$1(+_), pie) : value;
   };
 
   pie.sortValues = function(_) {
@@ -15261,15 +18050,15 @@
   };
 
   pie.startAngle = function(_) {
-    return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$b(+_), pie) : startAngle;
+    return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$1(+_), pie) : startAngle;
   };
 
   pie.endAngle = function(_) {
-    return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$b(+_), pie) : endAngle;
+    return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$1(+_), pie) : endAngle;
   };
 
   pie.padAngle = function(_) {
-    return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$b(+_), pie) : padAngle;
+    return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$1(+_), pie) : padAngle;
   };
 
   return pie;
@@ -15328,7 +18117,7 @@
 }
 
 function areaRadial() {
-  var a = area$3().curve(curveRadialLinear),
+  var a = area().curve(curveRadialLinear),
       c = a.curve,
       x0 = a.lineX0,
       x1 = a.lineX1,
@@ -15357,7 +18146,79 @@
   return [(y = +y) * Math.cos(x -= Math.PI / 2), y * Math.sin(x)];
 }
 
-var slice$6 = Array.prototype.slice;
+class Bump {
+  constructor(context, x) {
+    this._context = context;
+    this._x = x;
+  }
+  areaStart() {
+    this._line = 0;
+  }
+  areaEnd() {
+    this._line = NaN;
+  }
+  lineStart() {
+    this._point = 0;
+  }
+  lineEnd() {
+    if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
+    this._line = 1 - this._line;
+  }
+  point(x, y) {
+    x = +x, y = +y;
+    switch (this._point) {
+      case 0: {
+        this._point = 1;
+        if (this._line) this._context.lineTo(x, y);
+        else this._context.moveTo(x, y);
+        break;
+      }
+      case 1: this._point = 2; // falls through
+      default: {
+        if (this._x) this._context.bezierCurveTo(this._x0 = (this._x0 + x) / 2, this._y0, this._x0, y, x, y);
+        else this._context.bezierCurveTo(this._x0, this._y0 = (this._y0 + y) / 2, x, this._y0, x, y);
+        break;
+      }
+    }
+    this._x0 = x, this._y0 = y;
+  }
+}
+
+class BumpRadial {
+  constructor(context) {
+    this._context = context;
+  }
+  lineStart() {
+    this._point = 0;
+  }
+  lineEnd() {}
+  point(x, y) {
+    x = +x, y = +y;
+    if (this._point === 0) {
+      this._point = 1;
+    } else {
+      const p0 = pointRadial(this._x0, this._y0);
+      const p1 = pointRadial(this._x0, this._y0 = (this._y0 + y) / 2);
+      const p2 = pointRadial(x, this._y0);
+      const p3 = pointRadial(x, y);
+      this._context.moveTo(...p0);
+      this._context.bezierCurveTo(...p1, ...p2, ...p3);
+    }
+    this._x0 = x, this._y0 = y;
+  }
+}
+
+function bumpX(context) {
+  return new Bump(context, true);
+}
+
+function bumpY(context) {
+  return new Bump(context, false);
+}
+
+function bumpRadial(context) {
+  return new BumpRadial(context);
+}
 
 function linkSource(d) {
   return d.source;
@@ -15367,18 +18228,26 @@
   return d.target;
 }
 
-function link$2(curve) {
-  var source = linkSource,
+function link(curve) {
+  let source = linkSource,
       target = linkTarget,
-      x = x$3,
-      y = y$3,
-      context = null;
+      x$1 = x,
+      y$1 = y,
+      context = null,
+      output = null,
+      path = withPath(link);
 
   function link() {
-    var buffer, argv = slice$6.call(arguments), s = source.apply(this, argv), t = target.apply(this, argv);
-    if (!context) context = buffer = path();
-    curve(context, +x.apply(this, (argv[0] = s, argv)), +y.apply(this, argv), +x.apply(this, (argv[0] = t, argv)), +y.apply(this, argv));
-    if (buffer) return context = null, buffer + "" || null;
+    let buffer;
+    const argv = slice.call(arguments);
+    const s = source.apply(this, argv);
+    const t = target.apply(this, argv);
+    if (context == null) output = curve(buffer = path());
+    output.lineStart();
+    argv[0] = s, output.point(+x$1.apply(this, argv), +y$1.apply(this, argv));
+    argv[0] = t, output.point(+x$1.apply(this, argv), +y$1.apply(this, argv));
+    output.lineEnd();
+    if (buffer) return output = null, buffer + "" || null;
   }
 
   link.source = function(_) {
@@ -15390,65 +18259,62 @@
   };
 
   link.x = function(_) {
-    return arguments.length ? (x = typeof _ === "function" ? _ : constant$b(+_), link) : x;
+    return arguments.length ? (x$1 = typeof _ === "function" ? _ : constant$1(+_), link) : x$1;
   };
 
   link.y = function(_) {
-    return arguments.length ? (y = typeof _ === "function" ? _ : constant$b(+_), link) : y;
+    return arguments.length ? (y$1 = typeof _ === "function" ? _ : constant$1(+_), link) : y$1;
   };
 
   link.context = function(_) {
-    return arguments.length ? ((context = _ == null ? null : _), link) : context;
+    return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), link) : context;
   };
 
   return link;
 }
 
-function curveHorizontal(context, x0, y0, x1, y1) {
-  context.moveTo(x0, y0);
-  context.bezierCurveTo(x0 = (x0 + x1) / 2, y0, x0, y1, x1, y1);
-}
-
-function curveVertical(context, x0, y0, x1, y1) {
-  context.moveTo(x0, y0);
-  context.bezierCurveTo(x0, y0 = (y0 + y1) / 2, x1, y0, x1, y1);
-}
-
-function curveRadial$1(context, x0, y0, x1, y1) {
-  var p0 = pointRadial(x0, y0),
-      p1 = pointRadial(x0, y0 = (y0 + y1) / 2),
-      p2 = pointRadial(x1, y0),
-      p3 = pointRadial(x1, y1);
-  context.moveTo(p0[0], p0[1]);
-  context.bezierCurveTo(p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]);
-}
-
 function linkHorizontal() {
-  return link$2(curveHorizontal);
+  return link(bumpX);
 }
 
 function linkVertical() {
-  return link$2(curveVertical);
+  return link(bumpY);
 }
 
 function linkRadial() {
-  var l = link$2(curveRadial$1);
+  const l = link(bumpRadial);
   l.angle = l.x, delete l.x;
   l.radius = l.y, delete l.y;
   return l;
 }
 
-var circle$2 = {
-  draw: function(context, size) {
-    var r = Math.sqrt(size / pi$4);
-    context.moveTo(r, 0);
-    context.arc(0, 0, r, 0, tau$4);
+const sqrt3$2 = sqrt(3);
+
+var asterisk = {
+  draw(context, size) {
+    const r = sqrt(size + min(size / 28, 0.75)) * 0.59436;
+    const t = r / 2;
+    const u = t * sqrt3$2;
+    context.moveTo(0, r);
+    context.lineTo(0, -r);
+    context.moveTo(-u, -t);
+    context.lineTo(u, t);
+    context.moveTo(-u, t);
+    context.lineTo(u, -t);
   }
 };
 
-var cross$2 = {
-  draw: function(context, size) {
-    var r = Math.sqrt(size / 5) / 2;
+var circle = {
+  draw(context, size) {
+    const r = sqrt(size / pi);
+    context.moveTo(r, 0);
+    context.arc(0, 0, r, 0, tau);
+  }
+};
+
+var cross = {
+  draw(context, size) {
+    const r = sqrt(size / 5) / 2;
     context.moveTo(-3 * r, -r);
     context.lineTo(-r, -r);
     context.lineTo(-r, -3 * r);
@@ -15465,13 +18331,13 @@
   }
 };
 
-var tan30 = Math.sqrt(1 / 3),
-    tan30_2 = tan30 * 2;
+const tan30 = sqrt(1 / 3);
+const tan30_2 = tan30 * 2;
 
 var diamond = {
-  draw: function(context, size) {
-    var y = Math.sqrt(size / tan30_2),
-        x = y * tan30;
+  draw(context, size) {
+    const y = sqrt(size / tan30_2);
+    const x = y * tan30;
     context.moveTo(0, -y);
     context.lineTo(x, 0);
     context.lineTo(0, y);
@@ -15480,22 +18346,62 @@
   }
 };
 
-var ka = 0.89081309152928522810,
-    kr = Math.sin(pi$4 / 10) / Math.sin(7 * pi$4 / 10),
-    kx = Math.sin(tau$4 / 10) * kr,
-    ky = -Math.cos(tau$4 / 10) * kr;
+var diamond2 = {
+  draw(context, size) {
+    const r = sqrt(size) * 0.62625;
+    context.moveTo(0, -r);
+    context.lineTo(r, 0);
+    context.lineTo(0, r);
+    context.lineTo(-r, 0);
+    context.closePath();
+  }
+};
+
+var plus = {
+  draw(context, size) {
+    const r = sqrt(size - min(size / 7, 2)) * 0.87559;
+    context.moveTo(-r, 0);
+    context.lineTo(r, 0);
+    context.moveTo(0, r);
+    context.lineTo(0, -r);
+  }
+};
+
+var square = {
+  draw(context, size) {
+    const w = sqrt(size);
+    const x = -w / 2;
+    context.rect(x, x, w, w);
+  }
+};
+
+var square2 = {
+  draw(context, size) {
+    const r = sqrt(size) * 0.4431;
+    context.moveTo(r, r);
+    context.lineTo(r, -r);
+    context.lineTo(-r, -r);
+    context.lineTo(-r, r);
+    context.closePath();
+  }
+};
+
+const ka = 0.89081309152928522810;
+const kr = sin(pi / 10) / sin(7 * pi / 10);
+const kx = sin(tau / 10) * kr;
+const ky = -cos(tau / 10) * kr;
 
 var star = {
-  draw: function(context, size) {
-    var r = Math.sqrt(size * ka),
-        x = kx * r,
-        y = ky * r;
+  draw(context, size) {
+    const r = sqrt(size * ka);
+    const x = kx * r;
+    const y = ky * r;
     context.moveTo(0, -r);
     context.lineTo(x, y);
-    for (var i = 1; i < 5; ++i) {
-      var a = tau$4 * i / 5,
-          c = Math.cos(a),
-          s = Math.sin(a);
+    for (let i = 1; i < 5; ++i) {
+      const a = tau * i / 5;
+      const c = cos(a);
+      const s = sin(a);
       context.lineTo(s * r, -c * r);
       context.lineTo(c * x - s * y, s * x + c * y);
     }
@@ -15503,56 +18409,70 @@
   }
 };
 
-var square = {
-  draw: function(context, size) {
-    var w = Math.sqrt(size),
-        x = -w / 2;
-    context.rect(x, x, w, w);
-  }
-};
-
-var sqrt3 = Math.sqrt(3);
+const sqrt3$1 = sqrt(3);
 
 var triangle = {
-  draw: function(context, size) {
-    var y = -Math.sqrt(size / (sqrt3 * 3));
+  draw(context, size) {
+    const y = -sqrt(size / (sqrt3$1 * 3));
     context.moveTo(0, y * 2);
-    context.lineTo(-sqrt3 * y, -y);
-    context.lineTo(sqrt3 * y, -y);
+    context.lineTo(-sqrt3$1 * y, -y);
+    context.lineTo(sqrt3$1 * y, -y);
     context.closePath();
   }
 };
 
-var c$2 = -0.5,
-    s = Math.sqrt(3) / 2,
-    k = 1 / Math.sqrt(12),
-    a = (k / 2 + 1) * 3;
+const sqrt3 = sqrt(3);
+
+var triangle2 = {
+  draw(context, size) {
+    const s = sqrt(size) * 0.6824;
+    const t = s  / 2;
+    const u = (s * sqrt3) / 2; // cos(Math.PI / 6)
+    context.moveTo(0, -s);
+    context.lineTo(u, t);
+    context.lineTo(-u, t);
+    context.closePath();
+  }
+};
+
+const c = -0.5;
+const s = sqrt(3) / 2;
+const k = 1 / sqrt(12);
+const a = (k / 2 + 1) * 3;
 
 var wye = {
-  draw: function(context, size) {
-    var r = Math.sqrt(size / a),
-        x0 = r / 2,
-        y0 = r * k,
-        x1 = x0,
-        y1 = r * k + r,
-        x2 = -x1,
-        y2 = y1;
+  draw(context, size) {
+    const r = sqrt(size / a);
+    const x0 = r / 2, y0 = r * k;
+    const x1 = x0, y1 = r * k + r;
+    const x2 = -x1, y2 = y1;
     context.moveTo(x0, y0);
     context.lineTo(x1, y1);
     context.lineTo(x2, y2);
-    context.lineTo(c$2 * x0 - s * y0, s * x0 + c$2 * y0);
-    context.lineTo(c$2 * x1 - s * y1, s * x1 + c$2 * y1);
-    context.lineTo(c$2 * x2 - s * y2, s * x2 + c$2 * y2);
-    context.lineTo(c$2 * x0 + s * y0, c$2 * y0 - s * x0);
-    context.lineTo(c$2 * x1 + s * y1, c$2 * y1 - s * x1);
-    context.lineTo(c$2 * x2 + s * y2, c$2 * y2 - s * x2);
+    context.lineTo(c * x0 - s * y0, s * x0 + c * y0);
+    context.lineTo(c * x1 - s * y1, s * x1 + c * y1);
+    context.lineTo(c * x2 - s * y2, s * x2 + c * y2);
+    context.lineTo(c * x0 + s * y0, c * y0 - s * x0);
+    context.lineTo(c * x1 + s * y1, c * y1 - s * x1);
+    context.lineTo(c * x2 + s * y2, c * y2 - s * x2);
     context.closePath();
   }
 };
 
-var symbols = [
-  circle$2,
-  cross$2,
+var times = {
+  draw(context, size) {
+    const r = sqrt(size - min(size / 6, 1.7)) * 0.6189;
+    context.moveTo(-r, -r);
+    context.lineTo(r, r);
+    context.moveTo(-r, r);
+    context.lineTo(r, -r);
+  }
+};
+
+// These symbols are designed to be filled.
+const symbolsFill = [
+  circle,
+  cross,
   diamond,
   square,
   star,
@@ -15560,24 +18480,37 @@
   wye
 ];
 
-function symbol() {
-  var type = constant$b(circle$2),
-      size = constant$b(64),
-      context = null;
+// These symbols are designed to be stroked (with a width of 1.5px and round caps).
+const symbolsStroke = [
+  circle,
+  plus,
+  times,
+  triangle2,
+  asterisk,
+  square2,
+  diamond2
+];
+
+function Symbol$1(type, size) {
+  let context = null,
+      path = withPath(symbol);
+
+  type = typeof type === "function" ? type : constant$1(type || circle);
+  size = typeof size === "function" ? size : constant$1(size === undefined ? 64 : +size);
 
   function symbol() {
-    var buffer;
+    let buffer;
     if (!context) context = buffer = path();
     type.apply(this, arguments).draw(context, +size.apply(this, arguments));
     if (buffer) return context = null, buffer + "" || null;
   }
 
   symbol.type = function(_) {
-    return arguments.length ? (type = typeof _ === "function" ? _ : constant$b(_), symbol) : type;
+    return arguments.length ? (type = typeof _ === "function" ? _ : constant$1(_), symbol) : type;
   };
 
   symbol.size = function(_) {
-    return arguments.length ? (size = typeof _ === "function" ? _ : constant$b(+_), symbol) : size;
+    return arguments.length ? (size = typeof _ === "function" ? _ : constant$1(+_), symbol) : size;
   };
 
   symbol.context = function(_) {
@@ -15587,9 +18520,9 @@
   return symbol;
 }
 
-function noop$3() {}
+function noop() {}
 
-function point$2(that, x, y) {
+function point$3(that, x, y) {
   that._context.bezierCurveTo(
     (2 * that._x0 + that._x1) / 3,
     (2 * that._y0 + that._y1) / 3,
@@ -15618,7 +18551,7 @@
   },
   lineEnd: function() {
     switch (this._point) {
-      case 3: point$2(this, this._x1, this._y1); // proceed
+      case 3: point$3(this, this._x1, this._y1); // falls through
       case 2: this._context.lineTo(this._x1, this._y1); break;
     }
     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
@@ -15629,15 +18562,15 @@
     switch (this._point) {
       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
       case 1: this._point = 2; break;
-      case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // proceed
-      default: point$2(this, x, y); break;
+      case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // falls through
+      default: point$3(this, x, y); break;
     }
     this._x0 = this._x1, this._x1 = x;
     this._y0 = this._y1, this._y1 = y;
   }
 };
 
-function basis$2(context) {
+function basis(context) {
   return new Basis(context);
 }
 
@@ -15646,8 +18579,8 @@
 }
 
 BasisClosed.prototype = {
-  areaStart: noop$3,
-  areaEnd: noop$3,
+  areaStart: noop,
+  areaEnd: noop,
   lineStart: function() {
     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 =
     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN;
@@ -15680,14 +18613,14 @@
       case 0: this._point = 1; this._x2 = x, this._y2 = y; break;
       case 1: this._point = 2; this._x3 = x, this._y3 = y; break;
       case 2: this._point = 3; this._x4 = x, this._y4 = y; this._context.moveTo((this._x0 + 4 * this._x1 + x) / 6, (this._y0 + 4 * this._y1 + y) / 6); break;
-      default: point$2(this, x, y); break;
+      default: point$3(this, x, y); break;
     }
     this._x0 = this._x1, this._x1 = x;
     this._y0 = this._y1, this._y1 = y;
   }
 };
 
-function basisClosed$1(context) {
+function basisClosed(context) {
   return new BasisClosed(context);
 }
 
@@ -15717,8 +18650,8 @@
       case 0: this._point = 1; break;
       case 1: this._point = 2; break;
       case 2: this._point = 3; var x0 = (this._x0 + 4 * this._x1 + x) / 6, y0 = (this._y0 + 4 * this._y1 + y) / 6; this._line ? this._context.lineTo(x0, y0) : this._context.moveTo(x0, y0); break;
-      case 3: this._point = 4; // proceed
-      default: point$2(this, x, y); break;
+      case 3: this._point = 4; // falls through
+      default: point$3(this, x, y); break;
     }
     this._x0 = this._x1, this._x1 = x;
     this._y0 = this._y1, this._y1 = y;
@@ -15784,7 +18717,7 @@
   return bundle;
 })(0.85);
 
-function point$3(that, x, y) {
+function point$2(that, x, y) {
   that._context.bezierCurveTo(
     that._x1 + that._k * (that._x2 - that._x0),
     that._y1 + that._k * (that._y2 - that._y0),
@@ -15815,7 +18748,7 @@
   lineEnd: function() {
     switch (this._point) {
       case 2: this._context.lineTo(this._x2, this._y2); break;
-      case 3: point$3(this, this._x1, this._y1); break;
+      case 3: point$2(this, this._x1, this._y1); break;
     }
     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
     this._line = 1 - this._line;
@@ -15825,8 +18758,8 @@
     switch (this._point) {
       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
       case 1: this._point = 2; this._x1 = x, this._y1 = y; break;
-      case 2: this._point = 3; // proceed
-      default: point$3(this, x, y); break;
+      case 2: this._point = 3; // falls through
+      default: point$2(this, x, y); break;
     }
     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
@@ -15852,8 +18785,8 @@
 }
 
 CardinalClosed.prototype = {
-  areaStart: noop$3,
-  areaEnd: noop$3,
+  areaStart: noop,
+  areaEnd: noop,
   lineStart: function() {
     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
@@ -15885,7 +18818,7 @@
       case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
       case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
       case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
-      default: point$3(this, x, y); break;
+      default: point$2(this, x, y); break;
     }
     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
@@ -15932,8 +18865,8 @@
       case 0: this._point = 1; break;
       case 1: this._point = 2; break;
       case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
-      case 3: this._point = 4; // proceed
-      default: point$3(this, x, y); break;
+      case 3: this._point = 4; // falls through
+      default: point$2(this, x, y); break;
     }
     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
@@ -15953,20 +18886,20 @@
   return cardinal;
 })(0);
 
-function point$4(that, x, y) {
+function point$1(that, x, y) {
   var x1 = that._x1,
       y1 = that._y1,
       x2 = that._x2,
       y2 = that._y2;
 
-  if (that._l01_a > epsilon$3) {
+  if (that._l01_a > epsilon) {
     var a = 2 * that._l01_2a + 3 * that._l01_a * that._l12_a + that._l12_2a,
         n = 3 * that._l01_a * (that._l01_a + that._l12_a);
     x1 = (x1 * a - that._x0 * that._l12_2a + that._x2 * that._l01_2a) / n;
     y1 = (y1 * a - that._y0 * that._l12_2a + that._y2 * that._l01_2a) / n;
   }
 
-  if (that._l23_a > epsilon$3) {
+  if (that._l23_a > epsilon) {
     var b = 2 * that._l23_2a + 3 * that._l23_a * that._l12_a + that._l12_2a,
         m = 3 * that._l23_a * (that._l23_a + that._l12_a);
     x2 = (x2 * b + that._x1 * that._l23_2a - x * that._l12_2a) / m;
@@ -16015,8 +18948,8 @@
     switch (this._point) {
       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
       case 1: this._point = 2; break;
-      case 2: this._point = 3; // proceed
-      default: point$4(this, x, y); break;
+      case 2: this._point = 3; // falls through
+      default: point$1(this, x, y); break;
     }
 
     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
@@ -16045,8 +18978,8 @@
 }
 
 CatmullRomClosed.prototype = {
-  areaStart: noop$3,
-  areaEnd: noop$3,
+  areaStart: noop,
+  areaEnd: noop,
   lineStart: function() {
     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
@@ -16087,7 +19020,7 @@
       case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
       case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
       case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
-      default: point$4(this, x, y); break;
+      default: point$1(this, x, y); break;
     }
 
     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
@@ -16146,8 +19079,8 @@
       case 0: this._point = 1; break;
       case 1: this._point = 2; break;
       case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
-      case 3: this._point = 4; // proceed
-      default: point$4(this, x, y); break;
+      case 3: this._point = 4; // falls through
+      default: point$1(this, x, y); break;
     }
 
     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
@@ -16175,8 +19108,8 @@
 }
 
 LinearClosed.prototype = {
-  areaStart: noop$3,
-  areaEnd: noop$3,
+  areaStart: noop,
+  areaEnd: noop,
   lineStart: function() {
     this._point = 0;
   },
@@ -16194,7 +19127,7 @@
   return new LinearClosed(context);
 }
 
-function sign$1(x) {
+function sign(x) {
   return x < 0 ? -1 : 1;
 }
 
@@ -16208,7 +19141,7 @@
       s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0),
       s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0),
       p = (s0 * h1 + s1 * h0) / (h0 + h1);
-  return (sign$1(s0) + sign$1(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
+  return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
 }
 
 // Calculate a one-sided slope.
@@ -16220,7 +19153,7 @@
 // According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations
 // "you can express cubic Hermite interpolation in terms of cubic Bézier curves
 // with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1".
-function point$5(that, t0, t1) {
+function point(that, t0, t1) {
   var x0 = that._x0,
       y0 = that._y0,
       x1 = that._x1,
@@ -16249,7 +19182,7 @@
   lineEnd: function() {
     switch (this._point) {
       case 2: this._context.lineTo(this._x1, this._y1); break;
-      case 3: point$5(this, this._t0, slope2(this, this._t0)); break;
+      case 3: point(this, this._t0, slope2(this, this._t0)); break;
     }
     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
     this._line = 1 - this._line;
@@ -16262,8 +19195,8 @@
     switch (this._point) {
       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
       case 1: this._point = 2; break;
-      case 2: this._point = 3; point$5(this, slope2(this, t1 = slope3(this, x, y)), t1); break;
-      default: point$5(this, this._t0, t1 = slope3(this, x, y)); break;
+      case 2: this._point = 3; point(this, slope2(this, t1 = slope3(this, x, y)), t1); break;
+      default: point(this, this._t0, t1 = slope3(this, x, y)); break;
     }
 
     this._x0 = this._x1, this._x1 = x;
@@ -16390,7 +19323,7 @@
     x = +x, y = +y;
     switch (this._point) {
       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
-      case 1: this._point = 2; // proceed
+      case 1: this._point = 2; // falls through
       default: {
         if (this._t <= 0) {
           this._context.lineTo(this._x, y);
@@ -16429,7 +19362,7 @@
   }
 }
 
-function none$2(series) {
+function none(series) {
   var n = series.length, o = new Array(n);
   while (--n >= 0) o[n] = n;
   return o;
@@ -16439,29 +19372,30 @@
   return d[key];
 }
 
+function stackSeries(key) {
+  const series = [];
+  series.key = key;
+  return series;
+}
+
 function stack() {
-  var keys = constant$b([]),
-      order = none$2,
+  var keys = constant$1([]),
+      order = none,
       offset = none$1,
       value = stackValue;
 
   function stack(data) {
-    var kz = keys.apply(this, arguments),
-        i,
-        m = data.length,
-        n = kz.length,
-        sz = new Array(n),
+    var sz = Array.from(keys.apply(this, arguments), stackSeries),
+        i, n = sz.length, j = -1,
         oz;
 
-    for (i = 0; i < n; ++i) {
-      for (var ki = kz[i], si = sz[i] = new Array(m), j = 0, sij; j < m; ++j) {
-        si[j] = sij = [0, +value(data[j], ki, j, data)];
-        sij.data = data[j];
+    for (const d of data) {
+      for (i = 0, ++j; i < n; ++i) {
+        (sz[i][j] = [0, +value(d, sz[i].key, j, data)]).data = d;
       }
-      si.key = ki;
     }
 
-    for (i = 0, oz = order(sz); i < n; ++i) {
+    for (i = 0, oz = array(order(sz)); i < n; ++i) {
       sz[oz[i]].index = i;
     }
 
@@ -16470,15 +19404,15 @@
   }
 
   stack.keys = function(_) {
-    return arguments.length ? (keys = typeof _ === "function" ? _ : constant$b(slice$6.call(_)), stack) : keys;
+    return arguments.length ? (keys = typeof _ === "function" ? _ : constant$1(Array.from(_)), stack) : keys;
   };
 
   stack.value = function(_) {
-    return arguments.length ? (value = typeof _ === "function" ? _ : constant$b(+_), stack) : value;
+    return arguments.length ? (value = typeof _ === "function" ? _ : constant$1(+_), stack) : value;
   };
 
   stack.order = function(_) {
-    return arguments.length ? (order = _ == null ? none$2 : typeof _ === "function" ? _ : constant$b(slice$6.call(_)), stack) : order;
+    return arguments.length ? (order = _ == null ? none : typeof _ === "function" ? _ : constant$1(Array.from(_)), stack) : order;
   };
 
   stack.offset = function(_) {
@@ -16497,7 +19431,7 @@
   none$1(series, order);
 }
 
-function diverging$1(series, order) {
+function diverging(series, order) {
   if (!((n = series.length) > 0)) return;
   for (var i, j = 0, d, dy, yp, yn, n, m = series[order[0]].length; j < m; ++j) {
     for (yp = yn = 0, i = 0; i < n; ++i) {
@@ -16546,7 +19480,7 @@
 
 function appearance(series) {
   var peaks = series.map(peak);
-  return none$2(series).sort(function(a, b) { return peaks[a] - peaks[b]; });
+  return none(series).sort(function(a, b) { return peaks[a] - peaks[b]; });
 }
 
 function peak(series) {
@@ -16555,26 +19489,26 @@
   return j;
 }
 
-function ascending$3(series) {
-  var sums = series.map(sum$2);
-  return none$2(series).sort(function(a, b) { return sums[a] - sums[b]; });
+function ascending(series) {
+  var sums = series.map(sum);
+  return none(series).sort(function(a, b) { return sums[a] - sums[b]; });
 }
 
-function sum$2(series) {
+function sum(series) {
   var s = 0, i = -1, n = series.length, v;
   while (++i < n) if (v = +series[i][1]) s += v;
   return s;
 }
 
-function descending$2(series) {
-  return ascending$3(series).reverse();
+function descending(series) {
+  return ascending(series).reverse();
 }
 
 function insideOut(series) {
   var n = series.length,
       i,
       j,
-      sums = series.map(sum$2),
+      sums = series.map(sum),
       order = appearance(series),
       top = 0,
       bottom = 0,
@@ -16596,1006 +19530,24 @@
 }
 
 function reverse(series) {
-  return none$2(series).reverse();
+  return none(series).reverse();
 }
 
-function constant$c(x) {
-  return function() {
-    return x;
-  };
-}
+var constant = x => () => x;
 
-function x$4(d) {
-  return d[0];
-}
-
-function y$4(d) {
-  return d[1];
-}
-
-function RedBlackTree() {
-  this._ = null; // root node
-}
-
-function RedBlackNode(node) {
-  node.U = // parent node
-  node.C = // color - true for red, false for black
-  node.L = // left node
-  node.R = // right node
-  node.P = // previous node
-  node.N = null; // next node
-}
-
-RedBlackTree.prototype = {
-  constructor: RedBlackTree,
-
-  insert: function(after, node) {
-    var parent, grandpa, uncle;
-
-    if (after) {
-      node.P = after;
-      node.N = after.N;
-      if (after.N) after.N.P = node;
-      after.N = node;
-      if (after.R) {
-        after = after.R;
-        while (after.L) after = after.L;
-        after.L = node;
-      } else {
-        after.R = node;
-      }
-      parent = after;
-    } else if (this._) {
-      after = RedBlackFirst(this._);
-      node.P = null;
-      node.N = after;
-      after.P = after.L = node;
-      parent = after;
-    } else {
-      node.P = node.N = null;
-      this._ = node;
-      parent = null;
-    }
-    node.L = node.R = null;
-    node.U = parent;
-    node.C = true;
-
-    after = node;
-    while (parent && parent.C) {
-      grandpa = parent.U;
-      if (parent === grandpa.L) {
-        uncle = grandpa.R;
-        if (uncle && uncle.C) {
-          parent.C = uncle.C = false;
-          grandpa.C = true;
-          after = grandpa;
-        } else {
-          if (after === parent.R) {
-            RedBlackRotateLeft(this, parent);
-            after = parent;
-            parent = after.U;
-          }
-          parent.C = false;
-          grandpa.C = true;
-          RedBlackRotateRight(this, grandpa);
-        }
-      } else {
-        uncle = grandpa.L;
-        if (uncle && uncle.C) {
-          parent.C = uncle.C = false;
-          grandpa.C = true;
-          after = grandpa;
-        } else {
-          if (after === parent.L) {
-            RedBlackRotateRight(this, parent);
-            after = parent;
-            parent = after.U;
-          }
-          parent.C = false;
-          grandpa.C = true;
-          RedBlackRotateLeft(this, grandpa);
-        }
-      }
-      parent = after.U;
-    }
-    this._.C = false;
-  },
-
-  remove: function(node) {
-    if (node.N) node.N.P = node.P;
-    if (node.P) node.P.N = node.N;
-    node.N = node.P = null;
-
-    var parent = node.U,
-        sibling,
-        left = node.L,
-        right = node.R,
-        next,
-        red;
-
-    if (!left) next = right;
-    else if (!right) next = left;
-    else next = RedBlackFirst(right);
-
-    if (parent) {
-      if (parent.L === node) parent.L = next;
-      else parent.R = next;
-    } else {
-      this._ = next;
-    }
-
-    if (left && right) {
-      red = next.C;
-      next.C = node.C;
-      next.L = left;
-      left.U = next;
-      if (next !== right) {
-        parent = next.U;
-        next.U = node.U;
-        node = next.R;
-        parent.L = node;
-        next.R = right;
-        right.U = next;
-      } else {
-        next.U = parent;
-        parent = next;
-        node = next.R;
-      }
-    } else {
-      red = node.C;
-      node = next;
-    }
-
-    if (node) node.U = parent;
-    if (red) return;
-    if (node && node.C) { node.C = false; return; }
-
-    do {
-      if (node === this._) break;
-      if (node === parent.L) {
-        sibling = parent.R;
-        if (sibling.C) {
-          sibling.C = false;
-          parent.C = true;
-          RedBlackRotateLeft(this, parent);
-          sibling = parent.R;
-        }
-        if ((sibling.L && sibling.L.C)
-            || (sibling.R && sibling.R.C)) {
-          if (!sibling.R || !sibling.R.C) {
-            sibling.L.C = false;
-            sibling.C = true;
-            RedBlackRotateRight(this, sibling);
-            sibling = parent.R;
-          }
-          sibling.C = parent.C;
-          parent.C = sibling.R.C = false;
-          RedBlackRotateLeft(this, parent);
-          node = this._;
-          break;
-        }
-      } else {
-        sibling = parent.L;
-        if (sibling.C) {
-          sibling.C = false;
-          parent.C = true;
-          RedBlackRotateRight(this, parent);
-          sibling = parent.L;
-        }
-        if ((sibling.L && sibling.L.C)
-          || (sibling.R && sibling.R.C)) {
-          if (!sibling.L || !sibling.L.C) {
-            sibling.R.C = false;
-            sibling.C = true;
-            RedBlackRotateLeft(this, sibling);
-            sibling = parent.L;
-          }
-          sibling.C = parent.C;
-          parent.C = sibling.L.C = false;
-          RedBlackRotateRight(this, parent);
-          node = this._;
-          break;
-        }
-      }
-      sibling.C = true;
-      node = parent;
-      parent = parent.U;
-    } while (!node.C);
-
-    if (node) node.C = false;
-  }
-};
-
-function RedBlackRotateLeft(tree, node) {
-  var p = node,
-      q = node.R,
-      parent = p.U;
-
-  if (parent) {
-    if (parent.L === p) parent.L = q;
-    else parent.R = q;
-  } else {
-    tree._ = q;
-  }
-
-  q.U = parent;
-  p.U = q;
-  p.R = q.L;
-  if (p.R) p.R.U = p;
-  q.L = p;
-}
-
-function RedBlackRotateRight(tree, node) {
-  var p = node,
-      q = node.L,
-      parent = p.U;
-
-  if (parent) {
-    if (parent.L === p) parent.L = q;
-    else parent.R = q;
-  } else {
-    tree._ = q;
-  }
-
-  q.U = parent;
-  p.U = q;
-  p.L = q.R;
-  if (p.L) p.L.U = p;
-  q.R = p;
-}
-
-function RedBlackFirst(node) {
-  while (node.L) node = node.L;
-  return node;
-}
-
-function createEdge(left, right, v0, v1) {
-  var edge = [null, null],
-      index = edges.push(edge) - 1;
-  edge.left = left;
-  edge.right = right;
-  if (v0) setEdgeEnd(edge, left, right, v0);
-  if (v1) setEdgeEnd(edge, right, left, v1);
-  cells[left.index].halfedges.push(index);
-  cells[right.index].halfedges.push(index);
-  return edge;
-}
-
-function createBorderEdge(left, v0, v1) {
-  var edge = [v0, v1];
-  edge.left = left;
-  return edge;
-}
-
-function setEdgeEnd(edge, left, right, vertex) {
-  if (!edge[0] && !edge[1]) {
-    edge[0] = vertex;
-    edge.left = left;
-    edge.right = right;
-  } else if (edge.left === right) {
-    edge[1] = vertex;
-  } else {
-    edge[0] = vertex;
-  }
-}
-
-// Liang–Barsky line clipping.
-function clipEdge(edge, x0, y0, x1, y1) {
-  var a = edge[0],
-      b = edge[1],
-      ax = a[0],
-      ay = a[1],
-      bx = b[0],
-      by = b[1],
-      t0 = 0,
-      t1 = 1,
-      dx = bx - ax,
-      dy = by - ay,
-      r;
-
-  r = x0 - ax;
-  if (!dx && r > 0) return;
-  r /= dx;
-  if (dx < 0) {
-    if (r < t0) return;
-    if (r < t1) t1 = r;
-  } else if (dx > 0) {
-    if (r > t1) return;
-    if (r > t0) t0 = r;
-  }
-
-  r = x1 - ax;
-  if (!dx && r < 0) return;
-  r /= dx;
-  if (dx < 0) {
-    if (r > t1) return;
-    if (r > t0) t0 = r;
-  } else if (dx > 0) {
-    if (r < t0) return;
-    if (r < t1) t1 = r;
-  }
-
-  r = y0 - ay;
-  if (!dy && r > 0) return;
-  r /= dy;
-  if (dy < 0) {
-    if (r < t0) return;
-    if (r < t1) t1 = r;
-  } else if (dy > 0) {
-    if (r > t1) return;
-    if (r > t0) t0 = r;
-  }
-
-  r = y1 - ay;
-  if (!dy && r < 0) return;
-  r /= dy;
-  if (dy < 0) {
-    if (r > t1) return;
-    if (r > t0) t0 = r;
-  } else if (dy > 0) {
-    if (r < t0) return;
-    if (r < t1) t1 = r;
-  }
-
-  if (!(t0 > 0) && !(t1 < 1)) return true; // TODO Better check?
-
-  if (t0 > 0) edge[0] = [ax + t0 * dx, ay + t0 * dy];
-  if (t1 < 1) edge[1] = [ax + t1 * dx, ay + t1 * dy];
-  return true;
-}
-
-function connectEdge(edge, x0, y0, x1, y1) {
-  var v1 = edge[1];
-  if (v1) return true;
-
-  var v0 = edge[0],
-      left = edge.left,
-      right = edge.right,
-      lx = left[0],
-      ly = left[1],
-      rx = right[0],
-      ry = right[1],
-      fx = (lx + rx) / 2,
-      fy = (ly + ry) / 2,
-      fm,
-      fb;
-
-  if (ry === ly) {
-    if (fx < x0 || fx >= x1) return;
-    if (lx > rx) {
-      if (!v0) v0 = [fx, y0];
-      else if (v0[1] >= y1) return;
-      v1 = [fx, y1];
-    } else {
-      if (!v0) v0 = [fx, y1];
-      else if (v0[1] < y0) return;
-      v1 = [fx, y0];
-    }
-  } else {
-    fm = (lx - rx) / (ry - ly);
-    fb = fy - fm * fx;
-    if (fm < -1 || fm > 1) {
-      if (lx > rx) {
-        if (!v0) v0 = [(y0 - fb) / fm, y0];
-        else if (v0[1] >= y1) return;
-        v1 = [(y1 - fb) / fm, y1];
-      } else {
-        if (!v0) v0 = [(y1 - fb) / fm, y1];
-        else if (v0[1] < y0) return;
-        v1 = [(y0 - fb) / fm, y0];
-      }
-    } else {
-      if (ly < ry) {
-        if (!v0) v0 = [x0, fm * x0 + fb];
-        else if (v0[0] >= x1) return;
-        v1 = [x1, fm * x1 + fb];
-      } else {
-        if (!v0) v0 = [x1, fm * x1 + fb];
-        else if (v0[0] < x0) return;
-        v1 = [x0, fm * x0 + fb];
-      }
-    }
-  }
-
-  edge[0] = v0;
-  edge[1] = v1;
-  return true;
-}
-
-function clipEdges(x0, y0, x1, y1) {
-  var i = edges.length,
-      edge;
-
-  while (i--) {
-    if (!connectEdge(edge = edges[i], x0, y0, x1, y1)
-        || !clipEdge(edge, x0, y0, x1, y1)
-        || !(Math.abs(edge[0][0] - edge[1][0]) > epsilon$4
-            || Math.abs(edge[0][1] - edge[1][1]) > epsilon$4)) {
-      delete edges[i];
-    }
-  }
-}
-
-function createCell(site) {
-  return cells[site.index] = {
-    site: site,
-    halfedges: []
-  };
-}
-
-function cellHalfedgeAngle(cell, edge) {
-  var site = cell.site,
-      va = edge.left,
-      vb = edge.right;
-  if (site === vb) vb = va, va = site;
-  if (vb) return Math.atan2(vb[1] - va[1], vb[0] - va[0]);
-  if (site === va) va = edge[1], vb = edge[0];
-  else va = edge[0], vb = edge[1];
-  return Math.atan2(va[0] - vb[0], vb[1] - va[1]);
-}
-
-function cellHalfedgeStart(cell, edge) {
-  return edge[+(edge.left !== cell.site)];
-}
-
-function cellHalfedgeEnd(cell, edge) {
-  return edge[+(edge.left === cell.site)];
-}
-
-function sortCellHalfedges() {
-  for (var i = 0, n = cells.length, cell, halfedges, j, m; i < n; ++i) {
-    if ((cell = cells[i]) && (m = (halfedges = cell.halfedges).length)) {
-      var index = new Array(m),
-          array = new Array(m);
-      for (j = 0; j < m; ++j) index[j] = j, array[j] = cellHalfedgeAngle(cell, edges[halfedges[j]]);
-      index.sort(function(i, j) { return array[j] - array[i]; });
-      for (j = 0; j < m; ++j) array[j] = halfedges[index[j]];
-      for (j = 0; j < m; ++j) halfedges[j] = array[j];
-    }
-  }
-}
-
-function clipCells(x0, y0, x1, y1) {
-  var nCells = cells.length,
-      iCell,
-      cell,
-      site,
-      iHalfedge,
-      halfedges,
-      nHalfedges,
-      start,
-      startX,
-      startY,
-      end,
-      endX,
-      endY,
-      cover = true;
-
-  for (iCell = 0; iCell < nCells; ++iCell) {
-    if (cell = cells[iCell]) {
-      site = cell.site;
-      halfedges = cell.halfedges;
-      iHalfedge = halfedges.length;
-
-      // Remove any dangling clipped edges.
-      while (iHalfedge--) {
-        if (!edges[halfedges[iHalfedge]]) {
-          halfedges.splice(iHalfedge, 1);
-        }
-      }
-
-      // Insert any border edges as necessary.
-      iHalfedge = 0, nHalfedges = halfedges.length;
-      while (iHalfedge < nHalfedges) {
-        end = cellHalfedgeEnd(cell, edges[halfedges[iHalfedge]]), endX = end[0], endY = end[1];
-        start = cellHalfedgeStart(cell, edges[halfedges[++iHalfedge % nHalfedges]]), startX = start[0], startY = start[1];
-        if (Math.abs(endX - startX) > epsilon$4 || Math.abs(endY - startY) > epsilon$4) {
-          halfedges.splice(iHalfedge, 0, edges.push(createBorderEdge(site, end,
-              Math.abs(endX - x0) < epsilon$4 && y1 - endY > epsilon$4 ? [x0, Math.abs(startX - x0) < epsilon$4 ? startY : y1]
-              : Math.abs(endY - y1) < epsilon$4 && x1 - endX > epsilon$4 ? [Math.abs(startY - y1) < epsilon$4 ? startX : x1, y1]
-              : Math.abs(endX - x1) < epsilon$4 && endY - y0 > epsilon$4 ? [x1, Math.abs(startX - x1) < epsilon$4 ? startY : y0]
-              : Math.abs(endY - y0) < epsilon$4 && endX - x0 > epsilon$4 ? [Math.abs(startY - y0) < epsilon$4 ? startX : x0, y0]
-              : null)) - 1);
-          ++nHalfedges;
-        }
-      }
-
-      if (nHalfedges) cover = false;
-    }
-  }
-
-  // If there weren’t any edges, have the closest site cover the extent.
-  // It doesn’t matter which corner of the extent we measure!
-  if (cover) {
-    var dx, dy, d2, dc = Infinity;
-
-    for (iCell = 0, cover = null; iCell < nCells; ++iCell) {
-      if (cell = cells[iCell]) {
-        site = cell.site;
-        dx = site[0] - x0;
-        dy = site[1] - y0;
-        d2 = dx * dx + dy * dy;
-        if (d2 < dc) dc = d2, cover = cell;
-      }
-    }
-
-    if (cover) {
-      var v00 = [x0, y0], v01 = [x0, y1], v11 = [x1, y1], v10 = [x1, y0];
-      cover.halfedges.push(
-        edges.push(createBorderEdge(site = cover.site, v00, v01)) - 1,
-        edges.push(createBorderEdge(site, v01, v11)) - 1,
-        edges.push(createBorderEdge(site, v11, v10)) - 1,
-        edges.push(createBorderEdge(site, v10, v00)) - 1
-      );
-    }
-  }
-
-  // Lastly delete any cells with no edges; these were entirely clipped.
-  for (iCell = 0; iCell < nCells; ++iCell) {
-    if (cell = cells[iCell]) {
-      if (!cell.halfedges.length) {
-        delete cells[iCell];
-      }
-    }
-  }
-}
-
-var circlePool = [];
-
-var firstCircle;
-
-function Circle() {
-  RedBlackNode(this);
-  this.x =
-  this.y =
-  this.arc =
-  this.site =
-  this.cy = null;
-}
-
-function attachCircle(arc) {
-  var lArc = arc.P,
-      rArc = arc.N;
-
-  if (!lArc || !rArc) return;
-
-  var lSite = lArc.site,
-      cSite = arc.site,
-      rSite = rArc.site;
-
-  if (lSite === rSite) return;
-
-  var bx = cSite[0],
-      by = cSite[1],
-      ax = lSite[0] - bx,
-      ay = lSite[1] - by,
-      cx = rSite[0] - bx,
-      cy = rSite[1] - by;
-
-  var d = 2 * (ax * cy - ay * cx);
-  if (d >= -epsilon2$2) return;
-
-  var ha = ax * ax + ay * ay,
-      hc = cx * cx + cy * cy,
-      x = (cy * ha - ay * hc) / d,
-      y = (ax * hc - cx * ha) / d;
-
-  var circle = circlePool.pop() || new Circle;
-  circle.arc = arc;
-  circle.site = cSite;
-  circle.x = x + bx;
-  circle.y = (circle.cy = y + by) + Math.sqrt(x * x + y * y); // y bottom
-
-  arc.circle = circle;
-
-  var before = null,
-      node = circles._;
-
-  while (node) {
-    if (circle.y < node.y || (circle.y === node.y && circle.x <= node.x)) {
-      if (node.L) node = node.L;
-      else { before = node.P; break; }
-    } else {
-      if (node.R) node = node.R;
-      else { before = node; break; }
-    }
-  }
-
-  circles.insert(before, circle);
-  if (!before) firstCircle = circle;
-}
-
-function detachCircle(arc) {
-  var circle = arc.circle;
-  if (circle) {
-    if (!circle.P) firstCircle = circle.N;
-    circles.remove(circle);
-    circlePool.push(circle);
-    RedBlackNode(circle);
-    arc.circle = null;
-  }
-}
-
-var beachPool = [];
-
-function Beach() {
-  RedBlackNode(this);
-  this.edge =
-  this.site =
-  this.circle = null;
-}
-
-function createBeach(site) {
-  var beach = beachPool.pop() || new Beach;
-  beach.site = site;
-  return beach;
-}
-
-function detachBeach(beach) {
-  detachCircle(beach);
-  beaches.remove(beach);
-  beachPool.push(beach);
-  RedBlackNode(beach);
-}
-
-function removeBeach(beach) {
-  var circle = beach.circle,
-      x = circle.x,
-      y = circle.cy,
-      vertex = [x, y],
-      previous = beach.P,
-      next = beach.N,
-      disappearing = [beach];
-
-  detachBeach(beach);
-
-  var lArc = previous;
-  while (lArc.circle
-      && Math.abs(x - lArc.circle.x) < epsilon$4
-      && Math.abs(y - lArc.circle.cy) < epsilon$4) {
-    previous = lArc.P;
-    disappearing.unshift(lArc);
-    detachBeach(lArc);
-    lArc = previous;
-  }
-
-  disappearing.unshift(lArc);
-  detachCircle(lArc);
-
-  var rArc = next;
-  while (rArc.circle
-      && Math.abs(x - rArc.circle.x) < epsilon$4
-      && Math.abs(y - rArc.circle.cy) < epsilon$4) {
-    next = rArc.N;
-    disappearing.push(rArc);
-    detachBeach(rArc);
-    rArc = next;
-  }
-
-  disappearing.push(rArc);
-  detachCircle(rArc);
-
-  var nArcs = disappearing.length,
-      iArc;
-  for (iArc = 1; iArc < nArcs; ++iArc) {
-    rArc = disappearing[iArc];
-    lArc = disappearing[iArc - 1];
-    setEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
-  }
-
-  lArc = disappearing[0];
-  rArc = disappearing[nArcs - 1];
-  rArc.edge = createEdge(lArc.site, rArc.site, null, vertex);
-
-  attachCircle(lArc);
-  attachCircle(rArc);
-}
-
-function addBeach(site) {
-  var x = site[0],
-      directrix = site[1],
-      lArc,
-      rArc,
-      dxl,
-      dxr,
-      node = beaches._;
-
-  while (node) {
-    dxl = leftBreakPoint(node, directrix) - x;
-    if (dxl > epsilon$4) node = node.L; else {
-      dxr = x - rightBreakPoint(node, directrix);
-      if (dxr > epsilon$4) {
-        if (!node.R) {
-          lArc = node;
-          break;
-        }
-        node = node.R;
-      } else {
-        if (dxl > -epsilon$4) {
-          lArc = node.P;
-          rArc = node;
-        } else if (dxr > -epsilon$4) {
-          lArc = node;
-          rArc = node.N;
-        } else {
-          lArc = rArc = node;
-        }
-        break;
-      }
-    }
-  }
-
-  createCell(site);
-  var newArc = createBeach(site);
-  beaches.insert(lArc, newArc);
-
-  if (!lArc && !rArc) return;
-
-  if (lArc === rArc) {
-    detachCircle(lArc);
-    rArc = createBeach(lArc.site);
-    beaches.insert(newArc, rArc);
-    newArc.edge = rArc.edge = createEdge(lArc.site, newArc.site);
-    attachCircle(lArc);
-    attachCircle(rArc);
-    return;
-  }
-
-  if (!rArc) { // && lArc
-    newArc.edge = createEdge(lArc.site, newArc.site);
-    return;
-  }
-
-  // else lArc !== rArc
-  detachCircle(lArc);
-  detachCircle(rArc);
-
-  var lSite = lArc.site,
-      ax = lSite[0],
-      ay = lSite[1],
-      bx = site[0] - ax,
-      by = site[1] - ay,
-      rSite = rArc.site,
-      cx = rSite[0] - ax,
-      cy = rSite[1] - ay,
-      d = 2 * (bx * cy - by * cx),
-      hb = bx * bx + by * by,
-      hc = cx * cx + cy * cy,
-      vertex = [(cy * hb - by * hc) / d + ax, (bx * hc - cx * hb) / d + ay];
-
-  setEdgeEnd(rArc.edge, lSite, rSite, vertex);
-  newArc.edge = createEdge(lSite, site, null, vertex);
-  rArc.edge = createEdge(site, rSite, null, vertex);
-  attachCircle(lArc);
-  attachCircle(rArc);
-}
-
-function leftBreakPoint(arc, directrix) {
-  var site = arc.site,
-      rfocx = site[0],
-      rfocy = site[1],
-      pby2 = rfocy - directrix;
-
-  if (!pby2) return rfocx;
-
-  var lArc = arc.P;
-  if (!lArc) return -Infinity;
-
-  site = lArc.site;
-  var lfocx = site[0],
-      lfocy = site[1],
-      plby2 = lfocy - directrix;
-
-  if (!plby2) return lfocx;
-
-  var hl = lfocx - rfocx,
-      aby2 = 1 / pby2 - 1 / plby2,
-      b = hl / plby2;
-
-  if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
-
-  return (rfocx + lfocx) / 2;
-}
-
-function rightBreakPoint(arc, directrix) {
-  var rArc = arc.N;
-  if (rArc) return leftBreakPoint(rArc, directrix);
-  var site = arc.site;
-  return site[1] === directrix ? site[0] : Infinity;
-}
-
-var epsilon$4 = 1e-6;
-var epsilon2$2 = 1e-12;
-var beaches;
-var cells;
-var circles;
-var edges;
-
-function triangleArea(a, b, c) {
-  return (a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]);
-}
-
-function lexicographic(a, b) {
-  return b[1] - a[1]
-      || b[0] - a[0];
-}
-
-function Diagram(sites, extent) {
-  var site = sites.sort(lexicographic).pop(),
-      x,
-      y,
-      circle;
-
-  edges = [];
-  cells = new Array(sites.length);
-  beaches = new RedBlackTree;
-  circles = new RedBlackTree;
-
-  while (true) {
-    circle = firstCircle;
-    if (site && (!circle || site[1] < circle.y || (site[1] === circle.y && site[0] < circle.x))) {
-      if (site[0] !== x || site[1] !== y) {
-        addBeach(site);
-        x = site[0], y = site[1];
-      }
-      site = sites.pop();
-    } else if (circle) {
-      removeBeach(circle.arc);
-    } else {
-      break;
-    }
-  }
-
-  sortCellHalfedges();
-
-  if (extent) {
-    var x0 = +extent[0][0],
-        y0 = +extent[0][1],
-        x1 = +extent[1][0],
-        y1 = +extent[1][1];
-    clipEdges(x0, y0, x1, y1);
-    clipCells(x0, y0, x1, y1);
-  }
-
-  this.edges = edges;
-  this.cells = cells;
-
-  beaches =
-  circles =
-  edges =
-  cells = null;
-}
-
-Diagram.prototype = {
-  constructor: Diagram,
-
-  polygons: function() {
-    var edges = this.edges;
-
-    return this.cells.map(function(cell) {
-      var polygon = cell.halfedges.map(function(i) { return cellHalfedgeStart(cell, edges[i]); });
-      polygon.data = cell.site.data;
-      return polygon;
-    });
-  },
-
-  triangles: function() {
-    var triangles = [],
-        edges = this.edges;
-
-    this.cells.forEach(function(cell, i) {
-      if (!(m = (halfedges = cell.halfedges).length)) return;
-      var site = cell.site,
-          halfedges,
-          j = -1,
-          m,
-          s0,
-          e1 = edges[halfedges[m - 1]],
-          s1 = e1.left === site ? e1.right : e1.left;
-
-      while (++j < m) {
-        s0 = s1;
-        e1 = edges[halfedges[j]];
-        s1 = e1.left === site ? e1.right : e1.left;
-        if (s0 && s1 && i < s0.index && i < s1.index && triangleArea(site, s0, s1) < 0) {
-          triangles.push([site.data, s0.data, s1.data]);
-        }
-      }
-    });
-
-    return triangles;
-  },
-
-  links: function() {
-    return this.edges.filter(function(edge) {
-      return edge.right;
-    }).map(function(edge) {
-      return {
-        source: edge.left.data,
-        target: edge.right.data
-      };
-    });
-  },
-
-  find: function(x, y, radius) {
-    var that = this, i0, i1 = that._found || 0, n = that.cells.length, cell;
-
-    // Use the previously-found cell, or start with an arbitrary one.
-    while (!(cell = that.cells[i1])) if (++i1 >= n) return null;
-    var dx = x - cell.site[0], dy = y - cell.site[1], d2 = dx * dx + dy * dy;
-
-    // Traverse the half-edges to find a closer cell, if any.
-    do {
-      cell = that.cells[i0 = i1], i1 = null;
-      cell.halfedges.forEach(function(e) {
-        var edge = that.edges[e], v = edge.left;
-        if ((v === cell.site || !v) && !(v = edge.right)) return;
-        var vx = x - v[0], vy = y - v[1], v2 = vx * vx + vy * vy;
-        if (v2 < d2) d2 = v2, i1 = v.index;
-      });
-    } while (i1 !== null);
-
-    that._found = i0;
-
-    return radius == null || d2 <= radius * radius ? cell.site : null;
-  }
-};
-
-function voronoi() {
-  var x = x$4,
-      y = y$4,
-      extent = null;
-
-  function voronoi(data) {
-    return new Diagram(data.map(function(d, i) {
-      var s = [Math.round(x(d, i, data) / epsilon$4) * epsilon$4, Math.round(y(d, i, data) / epsilon$4) * epsilon$4];
-      s.index = i;
-      s.data = d;
-      return s;
-    }), extent);
-  }
-
-  voronoi.polygons = function(data) {
-    return voronoi(data).polygons();
-  };
-
-  voronoi.links = function(data) {
-    return voronoi(data).links();
-  };
-
-  voronoi.triangles = function(data) {
-    return voronoi(data).triangles();
-  };
-
-  voronoi.x = function(_) {
-    return arguments.length ? (x = typeof _ === "function" ? _ : constant$c(+_), voronoi) : x;
-  };
-
-  voronoi.y = function(_) {
-    return arguments.length ? (y = typeof _ === "function" ? _ : constant$c(+_), voronoi) : y;
-  };
-
-  voronoi.extent = function(_) {
-    return arguments.length ? (extent = _ == null ? null : [[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]], voronoi) : extent && [[extent[0][0], extent[0][1]], [extent[1][0], extent[1][1]]];
-  };
-
-  voronoi.size = function(_) {
-    return arguments.length ? (extent = _ == null ? null : [[0, 0], [+_[0], +_[1]]], voronoi) : extent && [extent[1][0] - extent[0][0], extent[1][1] - extent[0][1]];
-  };
-
-  return voronoi;
-}
-
-function constant$d(x) {
-  return function() {
-    return x;
-  };
-}
-
-function ZoomEvent(target, type, transform) {
-  this.target = target;
-  this.type = type;
-  this.transform = transform;
+function ZoomEvent(type, {
+  sourceEvent,
+  target,
+  transform,
+  dispatch
+}) {
+  Object.defineProperties(this, {
+    type: {value: type, enumerable: true, configurable: true},
+    sourceEvent: {value: sourceEvent, enumerable: true, configurable: true},
+    target: {value: target, enumerable: true, configurable: true},
+    transform: {value: transform, enumerable: true, configurable: true},
+    _: {value: dispatch}
+  });
 }
 
 function Transform(k, x, y) {
@@ -17641,30 +19593,31 @@
   }
 };
 
-var identity$9 = new Transform(1, 0, 0);
+var identity = new Transform(1, 0, 0);
 
-transform$1.prototype = Transform.prototype;
+transform.prototype = Transform.prototype;
 
-function transform$1(node) {
-  while (!node.__zoom) if (!(node = node.parentNode)) return identity$9;
+function transform(node) {
+  while (!node.__zoom) if (!(node = node.parentNode)) return identity;
   return node.__zoom;
 }
 
-function nopropagation$2() {
-  exports.event.stopImmediatePropagation();
+function nopropagation(event) {
+  event.stopImmediatePropagation();
 }
 
-function noevent$2() {
-  exports.event.preventDefault();
-  exports.event.stopImmediatePropagation();
+function noevent(event) {
+  event.preventDefault();
+  event.stopImmediatePropagation();
 }
 
 // Ignore right-click, since that should open the context menu.
-function defaultFilter$2() {
-  return !exports.event.ctrlKey && !exports.event.button;
+// except for pinch-to-zoom, which is sent as a wheel+ctrlKey event
+function defaultFilter(event) {
+  return (!event.ctrlKey || event.type === 'wheel') && !event.button;
 }
 
-function defaultExtent$1() {
+function defaultExtent() {
   var e = this;
   if (e instanceof SVGElement) {
     e = e.ownerSVGElement || e;
@@ -17678,14 +19631,14 @@
 }
 
 function defaultTransform() {
-  return this.__zoom || identity$9;
+  return this.__zoom || identity;
 }
 
-function defaultWheelDelta() {
-  return -exports.event.deltaY * (exports.event.deltaMode === 1 ? 0.05 : exports.event.deltaMode ? 1 : 0.002);
+function defaultWheelDelta(event) {
+  return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * (event.ctrlKey ? 10 : 1);
 }
 
-function defaultTouchable$2() {
+function defaultTouchable() {
   return navigator.maxTouchPoints || ("ontouchstart" in this);
 }
 
@@ -17701,60 +19654,62 @@
 }
 
 function zoom() {
-  var filter = defaultFilter$2,
-      extent = defaultExtent$1,
+  var filter = defaultFilter,
+      extent = defaultExtent,
       constrain = defaultConstrain,
       wheelDelta = defaultWheelDelta,
-      touchable = defaultTouchable$2,
+      touchable = defaultTouchable,
       scaleExtent = [0, Infinity],
       translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],
       duration = 250,
       interpolate = interpolateZoom,
       listeners = dispatch("start", "zoom", "end"),
       touchstarting,
+      touchfirst,
       touchending,
       touchDelay = 500,
       wheelDelay = 150,
-      clickDistance2 = 0;
+      clickDistance2 = 0,
+      tapDistance = 10;
 
   function zoom(selection) {
     selection
         .property("__zoom", defaultTransform)
-        .on("wheel.zoom", wheeled)
+        .on("wheel.zoom", wheeled, {passive: false})
         .on("mousedown.zoom", mousedowned)
         .on("dblclick.zoom", dblclicked)
       .filter(touchable)
         .on("touchstart.zoom", touchstarted)
         .on("touchmove.zoom", touchmoved)
         .on("touchend.zoom touchcancel.zoom", touchended)
-        .style("touch-action", "none")
         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
   }
 
-  zoom.transform = function(collection, transform, point) {
+  zoom.transform = function(collection, transform, point, event) {
     var selection = collection.selection ? collection.selection() : collection;
     selection.property("__zoom", defaultTransform);
     if (collection !== selection) {
-      schedule(collection, transform, point);
+      schedule(collection, transform, point, event);
     } else {
       selection.interrupt().each(function() {
         gesture(this, arguments)
-            .start()
-            .zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform)
-            .end();
+          .event(event)
+          .start()
+          .zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform)
+          .end();
       });
     }
   };
 
-  zoom.scaleBy = function(selection, k, p) {
+  zoom.scaleBy = function(selection, k, p, event) {
     zoom.scaleTo(selection, function() {
       var k0 = this.__zoom.k,
           k1 = typeof k === "function" ? k.apply(this, arguments) : k;
       return k0 * k1;
-    }, p);
+    }, p, event);
   };
 
-  zoom.scaleTo = function(selection, k, p) {
+  zoom.scaleTo = function(selection, k, p, event) {
     zoom.transform(selection, function() {
       var e = extent.apply(this, arguments),
           t0 = this.__zoom,
@@ -17762,28 +19717,28 @@
           p1 = t0.invert(p0),
           k1 = typeof k === "function" ? k.apply(this, arguments) : k;
       return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
-    }, p);
+    }, p, event);
   };
 
-  zoom.translateBy = function(selection, x, y) {
+  zoom.translateBy = function(selection, x, y, event) {
     zoom.transform(selection, function() {
       return constrain(this.__zoom.translate(
         typeof x === "function" ? x.apply(this, arguments) : x,
         typeof y === "function" ? y.apply(this, arguments) : y
       ), extent.apply(this, arguments), translateExtent);
-    });
+    }, null, event);
   };
 
-  zoom.translateTo = function(selection, x, y, p) {
+  zoom.translateTo = function(selection, x, y, p, event) {
     zoom.transform(selection, function() {
       var e = extent.apply(this, arguments),
           t = this.__zoom,
           p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p;
-      return constrain(identity$9.translate(p0[0], p0[1]).scale(t.k).translate(
+      return constrain(identity.translate(p0[0], p0[1]).scale(t.k).translate(
         typeof x === "function" ? -x.apply(this, arguments) : -x,
         typeof y === "function" ? -y.apply(this, arguments) : -y
       ), e, translateExtent);
-    }, p);
+    }, p, event);
   };
 
   function scale(transform, k) {
@@ -17800,14 +19755,14 @@
     return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
   }
 
-  function schedule(transition, transform, point) {
+  function schedule(transition, transform, point, event) {
     transition
-        .on("start.zoom", function() { gesture(this, arguments).start(); })
-        .on("interrupt.zoom end.zoom", function() { gesture(this, arguments).end(); })
+        .on("start.zoom", function() { gesture(this, arguments).event(event).start(); })
+        .on("interrupt.zoom end.zoom", function() { gesture(this, arguments).event(event).end(); })
         .tween("zoom", function() {
           var that = this,
               args = arguments,
-              g = gesture(that, args),
+              g = gesture(that, args).event(event),
               e = extent.apply(that, args),
               p = point == null ? centroid(e) : typeof point === "function" ? point.apply(that, args) : point,
               w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
@@ -17830,11 +19785,16 @@
     this.that = that;
     this.args = args;
     this.active = 0;
+    this.sourceEvent = null;
     this.extent = extent.apply(that, args);
     this.taps = 0;
   }
 
   Gesture.prototype = {
+    event: function(event) {
+      if (event) this.sourceEvent = event;
+      return this;
+    },
     start: function() {
       if (++this.active === 1) {
         this.that.__zooming = this;
@@ -17858,16 +19818,28 @@
       return this;
     },
     emit: function(type) {
-      customEvent(new ZoomEvent(zoom, type, this.that.__zoom), listeners.apply, listeners, [type, this.that, this.args]);
+      var d = select(this.that).datum();
+      listeners.call(
+        type,
+        this.that,
+        new ZoomEvent(type, {
+          sourceEvent: this.sourceEvent,
+          target: zoom,
+          type,
+          transform: this.that.__zoom,
+          dispatch: listeners
+        }),
+        d
+      );
     }
   };
 
-  function wheeled() {
+  function wheeled(event, ...args) {
     if (!filter.apply(this, arguments)) return;
-    var g = gesture(this, arguments),
+    var g = gesture(this, args).event(event),
         t = this.__zoom,
         k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),
-        p = mouse(this);
+        p = pointer(event);
 
     // If the mouse is in the same location as before, reuse it.
     // If there were recent wheel events, reset the wheel idle timeout.
@@ -17888,7 +19860,7 @@
       g.start();
     }
 
-    noevent$2();
+    noevent(event);
     g.wheel = setTimeout(wheelidled, wheelDelay);
     g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
 
@@ -17898,60 +19870,62 @@
     }
   }
 
-  function mousedowned() {
+  function mousedowned(event, ...args) {
     if (touchending || !filter.apply(this, arguments)) return;
-    var g = gesture(this, arguments, true),
-        v = select(exports.event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true),
-        p = mouse(this),
-        x0 = exports.event.clientX,
-        y0 = exports.event.clientY;
+    var currentTarget = event.currentTarget,
+        g = gesture(this, args, true).event(event),
+        v = select(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true),
+        p = pointer(event, currentTarget),
+        x0 = event.clientX,
+        y0 = event.clientY;
 
-    dragDisable(exports.event.view);
-    nopropagation$2();
+    dragDisable(event.view);
+    nopropagation(event);
     g.mouse = [p, this.__zoom.invert(p)];
     interrupt(this);
     g.start();
 
-    function mousemoved() {
-      noevent$2();
+    function mousemoved(event) {
+      noevent(event);
       if (!g.moved) {
-        var dx = exports.event.clientX - x0, dy = exports.event.clientY - y0;
+        var dx = event.clientX - x0, dy = event.clientY - y0;
         g.moved = dx * dx + dy * dy > clickDistance2;
       }
-      g.zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = mouse(g.that), g.mouse[1]), g.extent, translateExtent));
+      g.event(event)
+       .zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = pointer(event, currentTarget), g.mouse[1]), g.extent, translateExtent));
     }
 
-    function mouseupped() {
+    function mouseupped(event) {
       v.on("mousemove.zoom mouseup.zoom", null);
-      yesdrag(exports.event.view, g.moved);
-      noevent$2();
-      g.end();
+      yesdrag(event.view, g.moved);
+      noevent(event);
+      g.event(event).end();
     }
   }
 
-  function dblclicked() {
+  function dblclicked(event, ...args) {
     if (!filter.apply(this, arguments)) return;
     var t0 = this.__zoom,
-        p0 = mouse(this),
+        p0 = pointer(event.changedTouches ? event.changedTouches[0] : event, this),
         p1 = t0.invert(p0),
-        k1 = t0.k * (exports.event.shiftKey ? 0.5 : 2),
-        t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, arguments), translateExtent);
+        k1 = t0.k * (event.shiftKey ? 0.5 : 2),
+        t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, args), translateExtent);
 
-    noevent$2();
-    if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0);
-    else select(this).call(zoom.transform, t1);
+    noevent(event);
+    if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0, event);
+    else select(this).call(zoom.transform, t1, p0, event);
   }
 
-  function touchstarted() {
+  function touchstarted(event, ...args) {
     if (!filter.apply(this, arguments)) return;
-    var touches = exports.event.touches,
+    var touches = event.touches,
         n = touches.length,
-        g = gesture(this, arguments, exports.event.changedTouches.length === n),
+        g = gesture(this, args, event.changedTouches.length === n).event(event),
         started, i, t, p;
 
-    nopropagation$2();
+    nopropagation(event);
     for (i = 0; i < n; ++i) {
-      t = touches[i], p = touch(this, touches, t.identifier);
+      t = touches[i], p = pointer(t, this);
       p = [p, this.__zoom.invert(p), t.identifier];
       if (!g.touch0) g.touch0 = p, started = true, g.taps = 1 + !!touchstarting;
       else if (!g.touch1 && g.touch0[2] !== p[2]) g.touch1 = p, g.taps = 0;
@@ -17960,23 +19934,21 @@
     if (touchstarting) touchstarting = clearTimeout(touchstarting);
 
     if (started) {
-      if (g.taps < 2) touchstarting = setTimeout(function() { touchstarting = null; }, touchDelay);
+      if (g.taps < 2) touchfirst = p[0], touchstarting = setTimeout(function() { touchstarting = null; }, touchDelay);
       interrupt(this);
       g.start();
     }
   }
 
-  function touchmoved() {
+  function touchmoved(event, ...args) {
     if (!this.__zooming) return;
-    var g = gesture(this, arguments),
-        touches = exports.event.changedTouches,
+    var g = gesture(this, args).event(event),
+        touches = event.changedTouches,
         n = touches.length, i, t, p, l;
 
-    noevent$2();
-    if (touchstarting) touchstarting = clearTimeout(touchstarting);
-    g.taps = 0;
+    noevent(event);
     for (i = 0; i < n; ++i) {
-      t = touches[i], p = touch(this, touches, t.identifier);
+      t = touches[i], p = pointer(t, this);
       if (g.touch0 && g.touch0[2] === t.identifier) g.touch0[0] = p;
       else if (g.touch1 && g.touch1[2] === t.identifier) g.touch1[0] = p;
     }
@@ -17992,16 +19964,17 @@
     }
     else if (g.touch0) p = g.touch0[0], l = g.touch0[1];
     else return;
+
     g.zoom("touch", constrain(translate(t, p, l), g.extent, translateExtent));
   }
 
-  function touchended() {
+  function touchended(event, ...args) {
     if (!this.__zooming) return;
-    var g = gesture(this, arguments),
-        touches = exports.event.changedTouches,
+    var g = gesture(this, args).event(event),
+        touches = event.changedTouches,
         n = touches.length, i, t;
 
-    nopropagation$2();
+    nopropagation(event);
     if (touchending) clearTimeout(touchending);
     touchending = setTimeout(function() { touchending = null; }, touchDelay);
     for (i = 0; i < n; ++i) {
@@ -18015,26 +19988,29 @@
       g.end();
       // If this was a dbltap, reroute to the (optional) dblclick.zoom handler.
       if (g.taps === 2) {
-        var p = select(this).on("dblclick.zoom");
-        if (p) p.apply(this, arguments);
+        t = pointer(t, this);
+        if (Math.hypot(touchfirst[0] - t[0], touchfirst[1] - t[1]) < tapDistance) {
+          var p = select(this).on("dblclick.zoom");
+          if (p) p.apply(this, arguments);
+        }
       }
     }
   }
 
   zoom.wheelDelta = function(_) {
-    return arguments.length ? (wheelDelta = typeof _ === "function" ? _ : constant$d(+_), zoom) : wheelDelta;
+    return arguments.length ? (wheelDelta = typeof _ === "function" ? _ : constant(+_), zoom) : wheelDelta;
   };
 
   zoom.filter = function(_) {
-    return arguments.length ? (filter = typeof _ === "function" ? _ : constant$d(!!_), zoom) : filter;
+    return arguments.length ? (filter = typeof _ === "function" ? _ : constant(!!_), zoom) : filter;
   };
 
   zoom.touchable = function(_) {
-    return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$d(!!_), zoom) : touchable;
+    return arguments.length ? (touchable = typeof _ === "function" ? _ : constant(!!_), zoom) : touchable;
   };
 
   zoom.extent = function(_) {
-    return arguments.length ? (extent = typeof _ === "function" ? _ : constant$d([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
+    return arguments.length ? (extent = typeof _ === "function" ? _ : constant([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
   };
 
   zoom.scaleExtent = function(_) {
@@ -18066,40 +20042,59 @@
     return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2);
   };
 
+  zoom.tapDistance = function(_) {
+    return arguments.length ? (tapDistance = +_, zoom) : tapDistance;
+  };
+
   return zoom;
 }
 
+exports.Adder = Adder;
+exports.Delaunay = Delaunay;
 exports.FormatSpecifier = FormatSpecifier;
+exports.InternMap = InternMap;
+exports.InternSet = InternSet;
+exports.Node = Node$1;
+exports.Path = Path$1;
+exports.Voronoi = Voronoi;
+exports.ZoomTransform = Transform;
 exports.active = active;
 exports.arc = arc;
-exports.area = area$3;
+exports.area = area;
 exports.areaRadial = areaRadial;
-exports.ascending = ascending;
+exports.ascending = ascending$3;
 exports.autoType = autoType;
 exports.axisBottom = axisBottom;
 exports.axisLeft = axisLeft;
 exports.axisRight = axisRight;
 exports.axisTop = axisTop;
-exports.bisect = bisectRight;
+exports.bin = bin;
+exports.bisect = bisect;
+exports.bisectCenter = bisectCenter;
 exports.bisectLeft = bisectLeft;
 exports.bisectRight = bisectRight;
 exports.bisector = bisector;
 exports.blob = blob;
+exports.blur = blur;
+exports.blur2 = blur2;
+exports.blurImage = blurImage;
 exports.brush = brush;
 exports.brushSelection = brushSelection;
 exports.brushX = brushX;
 exports.brushY = brushY;
 exports.buffer = buffer;
 exports.chord = chord;
-exports.clientPoint = point;
+exports.chordDirected = chordDirected;
+exports.chordTranspose = chordTranspose;
 exports.cluster = cluster;
 exports.color = color;
 exports.contourDensity = density;
-exports.contours = contours;
-exports.create = create;
+exports.contours = Contours;
+exports.count = count$1;
+exports.create = create$1;
 exports.creator = creator;
-exports.cross = cross;
-exports.csv = csv$1;
+exports.cross = cross$2;
+exports.csv = csv;
 exports.csvFormat = csvFormat;
 exports.csvFormatBody = csvFormatBody;
 exports.csvFormatRow = csvFormatRow;
@@ -18107,10 +20102,13 @@
 exports.csvFormatValue = csvFormatValue;
 exports.csvParse = csvParse;
 exports.csvParseRows = csvParseRows;
-exports.cubehelix = cubehelix;
-exports.curveBasis = basis$2;
-exports.curveBasisClosed = basisClosed$1;
+exports.cubehelix = cubehelix$3;
+exports.cumsum = cumsum;
+exports.curveBasis = basis;
+exports.curveBasisClosed = basisClosed;
 exports.curveBasisOpen = basisOpen;
+exports.curveBumpX = bumpX;
+exports.curveBumpY = bumpY;
 exports.curveBundle = bundle;
 exports.curveCardinal = cardinal;
 exports.curveCardinalClosed = cardinalClosed;
@@ -18126,9 +20124,10 @@
 exports.curveStep = step;
 exports.curveStepAfter = stepAfter;
 exports.curveStepBefore = stepBefore;
-exports.customEvent = customEvent;
-exports.descending = descending;
+exports.descending = descending$2;
 exports.deviation = deviation;
+exports.difference = difference;
+exports.disjoint = disjoint;
 exports.dispatch = dispatch;
 exports.drag = drag;
 exports.dragDisable = dragDisable;
@@ -18172,32 +20171,37 @@
 exports.easeSinIn = sinIn;
 exports.easeSinInOut = sinInOut;
 exports.easeSinOut = sinOut;
-exports.entries = entries;
-exports.extent = extent;
-exports.forceCenter = center$1;
+exports.every = every;
+exports.extent = extent$1;
+exports.fcumsum = fcumsum;
+exports.filter = filter$1;
+exports.flatGroup = flatGroup;
+exports.flatRollup = flatRollup;
+exports.forceCenter = center;
 exports.forceCollide = collide;
-exports.forceLink = link;
+exports.forceLink = link$2;
 exports.forceManyBody = manyBody;
-exports.forceRadial = radial;
+exports.forceRadial = radial$1;
 exports.forceSimulation = simulation;
-exports.forceX = x$2;
-exports.forceY = y$2;
-exports.formatDefaultLocale = defaultLocale;
-exports.formatLocale = formatLocale;
+exports.forceX = x$1;
+exports.forceY = y$1;
+exports.formatDefaultLocale = defaultLocale$1;
+exports.formatLocale = formatLocale$1;
 exports.formatSpecifier = formatSpecifier;
+exports.fsum = fsum;
 exports.geoAlbers = albers;
 exports.geoAlbersUsa = albersUsa;
-exports.geoArea = area$1;
+exports.geoArea = area$2;
 exports.geoAzimuthalEqualArea = azimuthalEqualArea;
 exports.geoAzimuthalEqualAreaRaw = azimuthalEqualAreaRaw;
 exports.geoAzimuthalEquidistant = azimuthalEquidistant;
 exports.geoAzimuthalEquidistantRaw = azimuthalEquidistantRaw;
 exports.geoBounds = bounds;
-exports.geoCentroid = centroid;
-exports.geoCircle = circle;
+exports.geoCentroid = centroid$1;
+exports.geoCircle = circle$1;
 exports.geoClipAntimeridian = clipAntimeridian;
 exports.geoClipCircle = clipCircle;
-exports.geoClipExtent = extent$1;
+exports.geoClipExtent = extent;
 exports.geoClipRectangle = clipRectangle;
 exports.geoConicConformal = conicConformal;
 exports.geoConicConformalRaw = conicConformalRaw;
@@ -18215,8 +20219,8 @@
 exports.geoGnomonicRaw = gnomonicRaw;
 exports.geoGraticule = graticule;
 exports.geoGraticule10 = graticule10;
-exports.geoIdentity = identity$5;
-exports.geoInterpolate = interpolate$1;
+exports.geoIdentity = identity$4;
+exports.geoInterpolate = interpolate;
 exports.geoLength = length$1;
 exports.geoMercator = mercator;
 exports.geoMercatorRaw = mercatorRaw;
@@ -18224,27 +20228,34 @@
 exports.geoNaturalEarth1Raw = naturalEarth1Raw;
 exports.geoOrthographic = orthographic;
 exports.geoOrthographicRaw = orthographicRaw;
-exports.geoPath = index$1;
+exports.geoPath = index$2;
 exports.geoProjection = projection;
 exports.geoProjectionMutator = projectionMutator;
 exports.geoRotation = rotation;
 exports.geoStereographic = stereographic;
 exports.geoStereographicRaw = stereographicRaw;
 exports.geoStream = geoStream;
-exports.geoTransform = transform;
+exports.geoTransform = transform$1;
 exports.geoTransverseMercator = transverseMercator;
 exports.geoTransverseMercatorRaw = transverseMercatorRaw;
 exports.gray = gray;
-exports.hcl = hcl;
+exports.greatest = greatest;
+exports.greatestIndex = greatestIndex;
+exports.group = group;
+exports.groupSort = groupSort;
+exports.groups = groups;
+exports.hcl = hcl$2;
 exports.hierarchy = hierarchy;
-exports.histogram = histogram;
-exports.hsl = hsl;
+exports.histogram = bin;
+exports.hsl = hsl$2;
 exports.html = html;
 exports.image = image;
-exports.interpolate = interpolateValue;
-exports.interpolateArray = array$1;
-exports.interpolateBasis = basis$1;
-exports.interpolateBasisClosed = basisClosed;
+exports.index = index$4;
+exports.indexes = indexes;
+exports.interpolate = interpolate$2;
+exports.interpolateArray = array$3;
+exports.interpolateBasis = basis$2;
+exports.interpolateBasisClosed = basisClosed$1;
 exports.interpolateBlues = Blues;
 exports.interpolateBrBG = BrBG;
 exports.interpolateBuGn = BuGn;
@@ -18252,24 +20263,24 @@
 exports.interpolateCividis = cividis;
 exports.interpolateCool = cool;
 exports.interpolateCubehelix = cubehelix$2;
-exports.interpolateCubehelixDefault = cubehelix$3;
+exports.interpolateCubehelixDefault = cubehelix;
 exports.interpolateCubehelixLong = cubehelixLong;
-exports.interpolateDate = date;
+exports.interpolateDate = date$1;
 exports.interpolateDiscrete = discrete;
 exports.interpolateGnBu = GnBu;
 exports.interpolateGreens = Greens;
 exports.interpolateGreys = Greys;
-exports.interpolateHcl = hcl$2;
+exports.interpolateHcl = hcl$1;
 exports.interpolateHclLong = hclLong;
-exports.interpolateHsl = hsl$2;
+exports.interpolateHsl = hsl$1;
 exports.interpolateHslLong = hslLong;
-exports.interpolateHue = hue$1;
+exports.interpolateHue = hue;
 exports.interpolateInferno = inferno;
-exports.interpolateLab = lab$1;
+exports.interpolateLab = lab;
 exports.interpolateMagma = magma;
 exports.interpolateNumber = interpolateNumber;
 exports.interpolateNumberArray = numberArray;
-exports.interpolateObject = object;
+exports.interpolateObject = object$1;
 exports.interpolateOrRd = OrRd;
 exports.interpolateOranges = Oranges;
 exports.interpolatePRGn = PRGn;
@@ -18305,78 +20316,109 @@
 exports.interpolateYlOrRd = YlOrRd;
 exports.interpolateZoom = interpolateZoom;
 exports.interrupt = interrupt;
-exports.interval = interval$1;
-exports.isoFormat = formatIso;
-exports.isoParse = parseIso;
+exports.intersection = intersection;
+exports.interval = interval;
+exports.isoFormat = formatIso$1;
+exports.isoParse = parseIso$1;
 exports.json = json;
-exports.keys = keys;
-exports.lab = lab;
+exports.lab = lab$1;
 exports.lch = lch;
+exports.least = least;
+exports.leastIndex = leastIndex;
 exports.line = line;
 exports.lineRadial = lineRadial$1;
+exports.link = link;
 exports.linkHorizontal = linkHorizontal;
 exports.linkRadial = linkRadial;
 exports.linkVertical = linkVertical;
-exports.local = local;
+exports.local = local$1;
 exports.map = map$1;
 exports.matcher = matcher;
-exports.max = max;
+exports.max = max$3;
+exports.maxIndex = maxIndex;
 exports.mean = mean;
 exports.median = median;
+exports.medianIndex = medianIndex;
 exports.merge = merge;
-exports.min = min;
-exports.mouse = mouse;
+exports.min = min$2;
+exports.minIndex = minIndex;
+exports.mode = mode;
 exports.namespace = namespace;
 exports.namespaces = namespaces;
-exports.nest = nest;
+exports.nice = nice$1;
 exports.now = now;
-exports.pack = index$2;
+exports.pack = index$1;
 exports.packEnclose = enclose;
 exports.packSiblings = siblings;
 exports.pairs = pairs;
 exports.partition = partition;
 exports.path = path;
+exports.pathRound = pathRound;
 exports.permute = permute;
 exports.pie = pie;
 exports.piecewise = piecewise;
 exports.pointRadial = pointRadial;
-exports.polygonArea = area$2;
-exports.polygonCentroid = centroid$1;
-exports.polygonContains = contains$2;
+exports.pointer = pointer;
+exports.pointers = pointers;
+exports.polygonArea = area$1;
+exports.polygonCentroid = centroid;
+exports.polygonContains = contains;
 exports.polygonHull = hull;
-exports.polygonLength = length$2;
+exports.polygonLength = length;
 exports.precisionFixed = precisionFixed;
 exports.precisionPrefix = precisionPrefix;
 exports.precisionRound = precisionRound;
 exports.quadtree = quadtree;
-exports.quantile = threshold;
-exports.quantize = quantize;
+exports.quantile = quantile$1;
+exports.quantileIndex = quantileIndex;
+exports.quantileSorted = quantileSorted;
+exports.quantize = quantize$1;
+exports.quickselect = quickselect;
 exports.radialArea = areaRadial;
 exports.radialLine = lineRadial$1;
 exports.randomBates = bates;
-exports.randomExponential = exponential$1;
+exports.randomBernoulli = bernoulli;
+exports.randomBeta = beta;
+exports.randomBinomial = binomial;
+exports.randomCauchy = cauchy;
+exports.randomExponential = exponential;
+exports.randomGamma = gamma;
+exports.randomGeometric = geometric;
+exports.randomInt = int;
 exports.randomIrwinHall = irwinHall;
+exports.randomLcg = lcg;
 exports.randomLogNormal = logNormal;
+exports.randomLogistic = logistic;
 exports.randomNormal = normal;
+exports.randomPareto = pareto;
+exports.randomPoisson = poisson;
 exports.randomUniform = uniform;
-exports.range = sequence;
+exports.randomWeibull = weibull;
+exports.range = range$2;
+exports.rank = rank;
+exports.reduce = reduce;
+exports.reverse = reverse$1;
 exports.rgb = rgb;
-exports.ribbon = ribbon;
+exports.ribbon = ribbon$1;
+exports.ribbonArrow = ribbonArrow;
+exports.rollup = rollup;
+exports.rollups = rollups;
 exports.scaleBand = band;
-exports.scaleDiverging = diverging;
+exports.scaleDiverging = diverging$1;
 exports.scaleDivergingLog = divergingLog;
 exports.scaleDivergingPow = divergingPow;
 exports.scaleDivergingSqrt = divergingSqrt;
 exports.scaleDivergingSymlog = divergingSymlog;
-exports.scaleIdentity = identity$7;
+exports.scaleIdentity = identity$2;
 exports.scaleImplicit = implicit;
-exports.scaleLinear = linear$2;
-exports.scaleLog = log$1;
+exports.scaleLinear = linear;
+exports.scaleLog = log;
 exports.scaleOrdinal = ordinal;
-exports.scalePoint = point$1;
-exports.scalePow = pow$1;
+exports.scalePoint = point$4;
+exports.scalePow = pow;
 exports.scaleQuantile = quantile;
-exports.scaleQuantize = quantize$1;
+exports.scaleQuantize = quantize;
+exports.scaleRadial = radial;
 exports.scaleSequential = sequential;
 exports.scaleSequentialLog = sequentialLog;
 exports.scaleSequentialPow = sequentialPow;
@@ -18385,136 +20427,149 @@
 exports.scaleSequentialSymlog = sequentialSymlog;
 exports.scaleSqrt = sqrt$1;
 exports.scaleSymlog = symlog;
-exports.scaleThreshold = threshold$1;
+exports.scaleThreshold = threshold;
 exports.scaleTime = time;
 exports.scaleUtc = utcTime;
 exports.scan = scan;
 exports.schemeAccent = Accent;
-exports.schemeBlues = scheme$l;
-exports.schemeBrBG = scheme;
-exports.schemeBuGn = scheme$9;
-exports.schemeBuPu = scheme$a;
+exports.schemeBlues = scheme$5;
+exports.schemeBrBG = scheme$q;
+exports.schemeBuGn = scheme$h;
+exports.schemeBuPu = scheme$g;
 exports.schemeCategory10 = category10;
 exports.schemeDark2 = Dark2;
-exports.schemeGnBu = scheme$b;
-exports.schemeGreens = scheme$m;
-exports.schemeGreys = scheme$n;
-exports.schemeOrRd = scheme$c;
-exports.schemeOranges = scheme$q;
-exports.schemePRGn = scheme$1;
+exports.schemeGnBu = scheme$f;
+exports.schemeGreens = scheme$4;
+exports.schemeGreys = scheme$3;
+exports.schemeOrRd = scheme$e;
+exports.schemeOranges = scheme;
+exports.schemePRGn = scheme$p;
 exports.schemePaired = Paired;
 exports.schemePastel1 = Pastel1;
 exports.schemePastel2 = Pastel2;
-exports.schemePiYG = scheme$2;
-exports.schemePuBu = scheme$e;
+exports.schemePiYG = scheme$o;
+exports.schemePuBu = scheme$c;
 exports.schemePuBuGn = scheme$d;
-exports.schemePuOr = scheme$3;
-exports.schemePuRd = scheme$f;
-exports.schemePurples = scheme$o;
-exports.schemeRdBu = scheme$4;
-exports.schemeRdGy = scheme$5;
-exports.schemeRdPu = scheme$g;
-exports.schemeRdYlBu = scheme$6;
-exports.schemeRdYlGn = scheme$7;
-exports.schemeReds = scheme$p;
+exports.schemePuOr = scheme$n;
+exports.schemePuRd = scheme$b;
+exports.schemePurples = scheme$2;
+exports.schemeRdBu = scheme$m;
+exports.schemeRdGy = scheme$l;
+exports.schemeRdPu = scheme$a;
+exports.schemeRdYlBu = scheme$k;
+exports.schemeRdYlGn = scheme$j;
+exports.schemeReds = scheme$1;
 exports.schemeSet1 = Set1;
 exports.schemeSet2 = Set2;
 exports.schemeSet3 = Set3;
-exports.schemeSpectral = scheme$8;
+exports.schemeSpectral = scheme$i;
 exports.schemeTableau10 = Tableau10;
-exports.schemeYlGn = scheme$i;
-exports.schemeYlGnBu = scheme$h;
-exports.schemeYlOrBr = scheme$j;
-exports.schemeYlOrRd = scheme$k;
+exports.schemeYlGn = scheme$8;
+exports.schemeYlGnBu = scheme$9;
+exports.schemeYlOrBr = scheme$7;
+exports.schemeYlOrRd = scheme$6;
 exports.select = select;
 exports.selectAll = selectAll;
 exports.selection = selection;
 exports.selector = selector;
 exports.selectorAll = selectorAll;
-exports.set = set$2;
-exports.shuffle = shuffle;
+exports.shuffle = shuffle$1;
+exports.shuffler = shuffler;
+exports.some = some;
+exports.sort = sort;
 exports.stack = stack;
-exports.stackOffsetDiverging = diverging$1;
+exports.stackOffsetDiverging = diverging;
 exports.stackOffsetExpand = expand;
 exports.stackOffsetNone = none$1;
 exports.stackOffsetSilhouette = silhouette;
 exports.stackOffsetWiggle = wiggle;
 exports.stackOrderAppearance = appearance;
-exports.stackOrderAscending = ascending$3;
-exports.stackOrderDescending = descending$2;
+exports.stackOrderAscending = ascending;
+exports.stackOrderDescending = descending;
 exports.stackOrderInsideOut = insideOut;
-exports.stackOrderNone = none$2;
+exports.stackOrderNone = none;
 exports.stackOrderReverse = reverse;
 exports.stratify = stratify;
 exports.style = styleValue;
-exports.sum = sum;
+exports.subset = subset;
+exports.sum = sum$2;
+exports.superset = superset;
 exports.svg = svg;
-exports.symbol = symbol;
-exports.symbolCircle = circle$2;
-exports.symbolCross = cross$2;
+exports.symbol = Symbol$1;
+exports.symbolAsterisk = asterisk;
+exports.symbolCircle = circle;
+exports.symbolCross = cross;
 exports.symbolDiamond = diamond;
+exports.symbolDiamond2 = diamond2;
+exports.symbolPlus = plus;
 exports.symbolSquare = square;
+exports.symbolSquare2 = square2;
 exports.symbolStar = star;
+exports.symbolTimes = times;
 exports.symbolTriangle = triangle;
+exports.symbolTriangle2 = triangle2;
 exports.symbolWye = wye;
-exports.symbols = symbols;
+exports.symbolX = times;
+exports.symbols = symbolsFill;
+exports.symbolsFill = symbolsFill;
+exports.symbolsStroke = symbolsStroke;
 exports.text = text;
-exports.thresholdFreedmanDiaconis = freedmanDiaconis;
-exports.thresholdScott = scott;
+exports.thresholdFreedmanDiaconis = thresholdFreedmanDiaconis;
+exports.thresholdScott = thresholdScott;
 exports.thresholdSturges = thresholdSturges;
 exports.tickFormat = tickFormat;
 exports.tickIncrement = tickIncrement;
 exports.tickStep = tickStep;
 exports.ticks = ticks;
-exports.timeDay = day;
-exports.timeDays = days;
-exports.timeFormatDefaultLocale = defaultLocale$1;
-exports.timeFormatLocale = formatLocale$1;
-exports.timeFriday = friday;
-exports.timeFridays = fridays;
-exports.timeHour = hour;
-exports.timeHours = hours;
-exports.timeInterval = newInterval;
+exports.timeDay = timeDay;
+exports.timeDays = timeDays;
+exports.timeFormatDefaultLocale = defaultLocale;
+exports.timeFormatLocale = formatLocale;
+exports.timeFriday = timeFriday;
+exports.timeFridays = timeFridays;
+exports.timeHour = timeHour;
+exports.timeHours = timeHours;
+exports.timeInterval = timeInterval;
 exports.timeMillisecond = millisecond;
 exports.timeMilliseconds = milliseconds;
-exports.timeMinute = minute;
-exports.timeMinutes = minutes;
-exports.timeMonday = monday;
-exports.timeMondays = mondays;
-exports.timeMonth = month;
-exports.timeMonths = months;
-exports.timeSaturday = saturday;
-exports.timeSaturdays = saturdays;
+exports.timeMinute = timeMinute;
+exports.timeMinutes = timeMinutes;
+exports.timeMonday = timeMonday;
+exports.timeMondays = timeMondays;
+exports.timeMonth = timeMonth;
+exports.timeMonths = timeMonths;
+exports.timeSaturday = timeSaturday;
+exports.timeSaturdays = timeSaturdays;
 exports.timeSecond = second;
 exports.timeSeconds = seconds;
-exports.timeSunday = sunday;
-exports.timeSundays = sundays;
-exports.timeThursday = thursday;
-exports.timeThursdays = thursdays;
-exports.timeTuesday = tuesday;
-exports.timeTuesdays = tuesdays;
-exports.timeWednesday = wednesday;
-exports.timeWednesdays = wednesdays;
-exports.timeWeek = sunday;
-exports.timeWeeks = sundays;
-exports.timeYear = year;
-exports.timeYears = years;
-exports.timeout = timeout$1;
+exports.timeSunday = timeSunday;
+exports.timeSundays = timeSundays;
+exports.timeThursday = timeThursday;
+exports.timeThursdays = timeThursdays;
+exports.timeTickInterval = timeTickInterval;
+exports.timeTicks = timeTicks;
+exports.timeTuesday = timeTuesday;
+exports.timeTuesdays = timeTuesdays;
+exports.timeWednesday = timeWednesday;
+exports.timeWednesdays = timeWednesdays;
+exports.timeWeek = timeSunday;
+exports.timeWeeks = timeSundays;
+exports.timeYear = timeYear;
+exports.timeYears = timeYears;
+exports.timeout = timeout;
 exports.timer = timer;
 exports.timerFlush = timerFlush;
-exports.touch = touch;
-exports.touches = touches;
 exports.transition = transition;
 exports.transpose = transpose;
 exports.tree = tree;
-exports.treemap = index$3;
+exports.treemap = index;
 exports.treemapBinary = binary;
 exports.treemapDice = treemapDice;
 exports.treemapResquarify = resquarify;
 exports.treemapSlice = treemapSlice;
 exports.treemapSliceDice = sliceDice;
 exports.treemapSquarify = squarify;
-exports.tsv = tsv$1;
+exports.tsv = tsv;
 exports.tsvFormat = tsvFormat;
 exports.tsvFormatBody = tsvFormatBody;
 exports.tsvFormatRow = tsvFormatRow;
@@ -18522,6 +20577,9 @@
 exports.tsvFormatValue = tsvFormatValue;
 exports.tsvParse = tsvParse;
 exports.tsvParseRows = tsvParseRows;
+exports.union = union;
+exports.unixDay = unixDay;
+exports.unixDays = unixDays;
 exports.utcDay = utcDay;
 exports.utcDays = utcDays;
 exports.utcFriday = utcFriday;
@@ -18544,6 +20602,8 @@
 exports.utcSundays = utcSundays;
 exports.utcThursday = utcThursday;
 exports.utcThursdays = utcThursdays;
+exports.utcTickInterval = utcTickInterval;
+exports.utcTicks = utcTicks;
 exports.utcTuesday = utcTuesday;
 exports.utcTuesdays = utcTuesdays;
 exports.utcWednesday = utcWednesday;
@@ -18552,17 +20612,13 @@
 exports.utcWeeks = utcSundays;
 exports.utcYear = utcYear;
 exports.utcYears = utcYears;
-exports.values = values;
 exports.variance = variance;
 exports.version = version;
-exports.voronoi = voronoi;
 exports.window = defaultView;
 exports.xml = xml;
 exports.zip = zip;
 exports.zoom = zoom;
-exports.zoomIdentity = identity$9;
-exports.zoomTransform = transform$1;
-
-Object.defineProperty(exports, '__esModule', { value: true });
+exports.zoomIdentity = identity;
+exports.zoomTransform = transform;
 
 }));
diff --git a/third_party/d3/src/d3.min.js b/third_party/d3/src/d3.min.js
index 344d26cc..2c10135 100644
--- a/third_party/d3/src/d3.min.js
+++ b/third_party/d3/src/d3.min.js
@@ -1,2 +1,2 @@
-// https://d3js.org v5.16.0 Copyright 2020 Mike Bostock
-!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t=t||self).d3=t.d3||{})}(this,function(t){"use strict";function n(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function e(t){var e;return 1===t.length&&(e=t,t=function(t,r){return n(e(t),r)}),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)>0?i=o:r=o+1}return r}}}var r=e(n),i=r.right,o=r.left;function a(t,n){return[t,n]}function u(t){return null===t?NaN:+t}function c(t,n){var e,r,i=t.length,o=0,a=-1,c=0,f=0;if(null==n)for(;++a<i;)isNaN(e=u(t[a]))||(f+=(r=e-c)*(e-(c+=r/++o)));else for(;++a<i;)isNaN(e=u(n(t[a],a,t)))||(f+=(r=e-c)*(e-(c+=r/++o)));if(o>1)return f/(o-1)}function f(t,n){var e=c(t,n);return e?Math.sqrt(e):e}function s(t,n){var e,r,i,o=t.length,a=-1;if(null==n){for(;++a<o;)if(null!=(e=t[a])&&e>=e)for(r=i=e;++a<o;)null!=(e=t[a])&&(r>e&&(r=e),i<e&&(i=e))}else for(;++a<o;)if(null!=(e=n(t[a],a,t))&&e>=e)for(r=i=e;++a<o;)null!=(e=n(t[a],a,t))&&(r>e&&(r=e),i<e&&(i=e));return[r,i]}var l=Array.prototype,h=l.slice,d=l.map;function p(t){return function(){return t}}function v(t){return t}function g(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o}var y=Math.sqrt(50),_=Math.sqrt(10),b=Math.sqrt(2);function m(t,n,e){var r,i,o,a,u=-1;if(e=+e,(t=+t)===(n=+n)&&e>0)return[t];if((r=n<t)&&(i=t,t=n,n=i),0===(a=x(t,n,e))||!isFinite(a))return[];if(a>0)for(t=Math.ceil(t/a),n=Math.floor(n/a),o=new Array(i=Math.ceil(n-t+1));++u<i;)o[u]=(t+u)*a;else for(t=Math.floor(t*a),n=Math.ceil(n*a),o=new Array(i=Math.ceil(t-n+1));++u<i;)o[u]=(t-u)/a;return r&&o.reverse(),o}function x(t,n,e){var r=(n-t)/Math.max(0,e),i=Math.floor(Math.log(r)/Math.LN10),o=r/Math.pow(10,i);return i>=0?(o>=y?10:o>=_?5:o>=b?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=y?10:o>=_?5:o>=b?2:1)}function w(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=y?i*=10:o>=_?i*=5:o>=b&&(i*=2),n<t?-i:i}function M(t){return Math.ceil(Math.log(t.length)/Math.LN2)+1}function N(t,n,e){if(null==e&&(e=u),r=t.length){if((n=+n)<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),a=+e(t[o],o,t);return a+(+e(t[o+1],o+1,t)-a)*(i-o)}}function T(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&e>r&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&e>r&&(r=e);return r}function A(t){for(var n,e,r,i=t.length,o=-1,a=0;++o<i;)a+=t[o].length;for(e=new Array(a);--i>=0;)for(n=(r=t[i]).length;--n>=0;)e[--a]=r[n];return e}function S(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&r>e&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&r>e&&(r=e);return r}function k(t){if(!(i=t.length))return[];for(var n=-1,e=S(t,E),r=new Array(e);++n<e;)for(var i,o=-1,a=r[n]=new Array(i);++o<i;)a[o]=t[o][n];return r}function E(t){return t.length}var C=Array.prototype.slice;function P(t){return t}var z=1,R=2,D=3,q=4,L=1e-6;function U(t){return"translate("+(t+.5)+",0)"}function O(t){return"translate(0,"+(t+.5)+")"}function B(){return!this.__axis}function F(t,n){var e=[],r=null,i=null,o=6,a=6,u=3,c=t===z||t===q?-1:1,f=t===q||t===R?"x":"y",s=t===z||t===D?U:O;function l(l){var h=null==r?n.ticks?n.ticks.apply(n,e):n.domain():r,d=null==i?n.tickFormat?n.tickFormat.apply(n,e):P:i,p=Math.max(o,0)+u,v=n.range(),g=+v[0]+.5,y=+v[v.length-1]+.5,_=(n.bandwidth?function(t){var n=Math.max(0,t.bandwidth()-1)/2;return t.round()&&(n=Math.round(n)),function(e){return+t(e)+n}}:function(t){return function(n){return+t(n)}})(n.copy()),b=l.selection?l.selection():l,m=b.selectAll(".domain").data([null]),x=b.selectAll(".tick").data(h,n).order(),w=x.exit(),M=x.enter().append("g").attr("class","tick"),N=x.select("line"),T=x.select("text");m=m.merge(m.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),x=x.merge(M),N=N.merge(M.append("line").attr("stroke","currentColor").attr(f+"2",c*o)),T=T.merge(M.append("text").attr("fill","currentColor").attr(f,c*p).attr("dy",t===z?"0em":t===D?"0.71em":"0.32em")),l!==b&&(m=m.transition(l),x=x.transition(l),N=N.transition(l),T=T.transition(l),w=w.transition(l).attr("opacity",L).attr("transform",function(t){return isFinite(t=_(t))?s(t):this.getAttribute("transform")}),M.attr("opacity",L).attr("transform",function(t){var n=this.parentNode.__axis;return s(n&&isFinite(n=n(t))?n:_(t))})),w.remove(),m.attr("d",t===q||t==R?a?"M"+c*a+","+g+"H0.5V"+y+"H"+c*a:"M0.5,"+g+"V"+y:a?"M"+g+","+c*a+"V0.5H"+y+"V"+c*a:"M"+g+",0.5H"+y),x.attr("opacity",1).attr("transform",function(t){return s(_(t))}),N.attr(f+"2",c*o),T.attr(f,c*p).text(d),b.filter(B).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===R?"start":t===q?"end":"middle"),b.each(function(){this.__axis=_})}return l.scale=function(t){return arguments.length?(n=t,l):n},l.ticks=function(){return e=C.call(arguments),l},l.tickArguments=function(t){return arguments.length?(e=null==t?[]:C.call(t),l):e.slice()},l.tickValues=function(t){return arguments.length?(r=null==t?null:C.call(t),l):r&&r.slice()},l.tickFormat=function(t){return arguments.length?(i=t,l):i},l.tickSize=function(t){return arguments.length?(o=a=+t,l):o},l.tickSizeInner=function(t){return arguments.length?(o=+t,l):o},l.tickSizeOuter=function(t){return arguments.length?(a=+t,l):a},l.tickPadding=function(t){return arguments.length?(u=+t,l):u},l}var Y={value:function(){}};function I(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+"")||t in r||/[\s.]/.test(t))throw new Error("illegal type: "+t);r[t]=[]}return new H(r)}function H(t){this._=t}function j(t,n){return t.trim().split(/^|\s+/).map(function(t){var e="",r=t.indexOf(".");if(r>=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}function X(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function V(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=Y,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}H.prototype=I.prototype={constructor:H,on:function(t,n){var e,r=this._,i=j(t+"",r),o=-1,a=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o<a;)if(e=(t=i[o]).type)r[e]=V(r[e],t.name,n);else if(null==n)for(e in r)r[e]=V(r[e],t.name,null);return this}for(;++o<a;)if((e=(t=i[o]).type)&&(e=X(r[e],t.name)))return e},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new H(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=0,e=(r=this._[t]).length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var G="http://www.w3.org/1999/xhtml",$={svg:"http://www.w3.org/2000/svg",xhtml:G,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function W(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),$.hasOwnProperty(n)?{space:$[n],local:t}:t}function Z(t){var n=W(t);return(n.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===G&&n.documentElement.namespaceURI===G?n.createElement(t):n.createElementNS(e,t)}})(n)}function Q(){}function K(t){return null==t?Q:function(){return this.querySelector(t)}}function J(){return[]}function tt(t){return null==t?J:function(){return this.querySelectorAll(t)}}function nt(t){return function(){return this.matches(t)}}function et(t){return new Array(t.length)}function rt(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}rt.prototype={constructor:rt,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var it="$";function ot(t,n,e,r,i,o){for(var a,u=0,c=n.length,f=o.length;u<f;++u)(a=n[u])?(a.__data__=o[u],r[u]=a):e[u]=new rt(t,o[u]);for(;u<c;++u)(a=n[u])&&(i[u]=a)}function at(t,n,e,r,i,o,a){var u,c,f,s={},l=n.length,h=o.length,d=new Array(l);for(u=0;u<l;++u)(c=n[u])&&(d[u]=f=it+a.call(c,c.__data__,u,n),f in s?i[u]=c:s[f]=c);for(u=0;u<h;++u)(c=s[f=it+a.call(t,o[u],u,o)])?(r[u]=c,c.__data__=o[u],s[f]=null):e[u]=new rt(t,o[u]);for(u=0;u<l;++u)(c=n[u])&&s[d[u]]===c&&(i[u]=c)}function ut(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function ct(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function ft(t,n){return t.style.getPropertyValue(n)||ct(t).getComputedStyle(t,null).getPropertyValue(n)}function st(t){return t.trim().split(/^|\s+/)}function lt(t){return t.classList||new ht(t)}function ht(t){this._node=t,this._names=st(t.getAttribute("class")||"")}function dt(t,n){for(var e=lt(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function pt(t,n){for(var e=lt(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function vt(){this.textContent=""}function gt(){this.innerHTML=""}function yt(){this.nextSibling&&this.parentNode.appendChild(this)}function _t(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function bt(){return null}function mt(){var t=this.parentNode;t&&t.removeChild(this)}function xt(){var t=this.cloneNode(!1),n=this.parentNode;return n?n.insertBefore(t,this.nextSibling):t}function wt(){var t=this.cloneNode(!0),n=this.parentNode;return n?n.insertBefore(t,this.nextSibling):t}ht.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Mt={};(t.event=null,"undefined"!=typeof document)&&("onmouseenter"in document.documentElement||(Mt={mouseenter:"mouseover",mouseleave:"mouseout"}));function Nt(t,n,e){return t=Tt(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function Tt(n,e,r){return function(i){var o=t.event;t.event=i;try{n.call(this,this.__data__,e,r)}finally{t.event=o}}}function At(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.capture);++i?n.length=i:delete this.__on}}}function St(t,n,e){var r=Mt.hasOwnProperty(t.type)?Nt:Tt;return function(i,o,a){var u,c=this.__on,f=r(n,o,a);if(c)for(var s=0,l=c.length;s<l;++s)if((u=c[s]).type===t.type&&u.name===t.name)return this.removeEventListener(u.type,u.listener,u.capture),this.addEventListener(u.type,u.listener=f,u.capture=e),void(u.value=n);this.addEventListener(t.type,f,e),u={type:t.type,name:t.name,value:n,listener:f,capture:e},c?c.push(u):this.__on=[u]}}function kt(n,e,r,i){var o=t.event;n.sourceEvent=t.event,t.event=n;try{return e.apply(r,i)}finally{t.event=o}}function Et(t,n,e){var r=ct(t),i=r.CustomEvent;"function"==typeof i?i=new i(n,e):(i=r.document.createEvent("Event"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}var Ct=[null];function Pt(t,n){this._groups=t,this._parents=n}function zt(){return new Pt([[document.documentElement]],Ct)}function Rt(t){return"string"==typeof t?new Pt([[document.querySelector(t)]],[document.documentElement]):new Pt([[t]],Ct)}Pt.prototype=zt.prototype={constructor:Pt,select:function(t){"function"!=typeof t&&(t=K(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a,u=n[i],c=u.length,f=r[i]=new Array(c),s=0;s<c;++s)(o=u[s])&&(a=t.call(o,o.__data__,s,u))&&("__data__"in o&&(a.__data__=o.__data__),f[s]=a);return new Pt(r,this._parents)},selectAll:function(t){"function"!=typeof t&&(t=tt(t));for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var a,u=n[o],c=u.length,f=0;f<c;++f)(a=u[f])&&(r.push(t.call(a,a.__data__,f,u)),i.push(a));return new Pt(r,i)},filter:function(t){"function"!=typeof t&&(t=nt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,c=r[i]=[],f=0;f<u;++f)(o=a[f])&&t.call(o,o.__data__,f,a)&&c.push(o);return new Pt(r,this._parents)},data:function(t,n){if(!t)return d=new Array(this.size()),f=-1,this.each(function(t){d[++f]=t}),d;var e=n?at:ot,r=this._parents,i=this._groups;"function"!=typeof t&&(t=function(t){return function(){return t}}(t));for(var o=i.length,a=new Array(o),u=new Array(o),c=new Array(o),f=0;f<o;++f){var s=r[f],l=i[f],h=l.length,d=t.call(s,s&&s.__data__,f,r),p=d.length,v=u[f]=new Array(p),g=a[f]=new Array(p);e(s,l,v,g,c[f]=new Array(h),d,n);for(var y,_,b=0,m=0;b<p;++b)if(y=v[b]){for(b>=m&&(m=b+1);!(_=g[m])&&++m<p;);y._next=_||null}}return(a=new Pt(a,r))._enter=u,a._exit=c,a},enter:function(){return new Pt(this._enter||this._groups.map(et),this._parents)},exit:function(){return new Pt(this._exit||this._groups.map(et),this._parents)},join:function(t,n,e){var r=this.enter(),i=this,o=this.exit();return r="function"==typeof t?t(r):r.append(t+""),null!=n&&(i=n(i)),null==e?o.remove():e(o),r&&i?r.merge(i).order():i},merge:function(t){for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),a=new Array(r),u=0;u<o;++u)for(var c,f=n[u],s=e[u],l=f.length,h=a[u]=new Array(l),d=0;d<l;++d)(c=f[d]||s[d])&&(h[d]=c);for(;u<r;++u)a[u]=n[u];return new Pt(a,this._parents)},order:function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,a=i[o];--o>=0;)(r=i[o])&&(a&&4^r.compareDocumentPosition(a)&&a.parentNode.insertBefore(r,a),a=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=ut);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o<r;++o){for(var a,u=e[o],c=u.length,f=i[o]=new Array(c),s=0;s<c;++s)(a=u[s])&&(f[s]=a);f.sort(n)}return new Pt(i,this._parents).order()},call:function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},nodes:function(){var t=new Array(this.size()),n=-1;return this.each(function(){t[++n]=this}),t},node:function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var a=r[i];if(a)return a}return null},size:function(){var t=0;return this.each(function(){++t}),t},empty:function(){return!this.node()},each:function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],a=0,u=o.length;a<u;++a)(i=o[a])&&t.call(i,i.__data__,a,o);return this},attr:function(t,n){var e=W(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}}:"function"==typeof n?e.local?function(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}:function(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}:e.local?function(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}:function(t,n){return function(){this.setAttribute(t,n)}})(e,n))},style:function(t,n,e){return arguments.length>1?this.each((null==n?function(t){return function(){this.style.removeProperty(t)}}:"function"==typeof n?function(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}:function(t,n,e){return function(){this.style.setProperty(t,n,e)}})(t,n,null==e?"":e)):ft(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?function(t){return function(){delete this[t]}}:"function"==typeof n?function(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}:function(t,n){return function(){this[t]=n}})(t,n)):this.node()[t]},classed:function(t,n){var e=st(t+"");if(arguments.length<2){for(var r=lt(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each(("function"==typeof n?function(t,n){return function(){(n.apply(this,arguments)?dt:pt)(this,t)}}:n?function(t){return function(){dt(this,t)}}:function(t){return function(){pt(this,t)}})(e,n))},text:function(t){return arguments.length?this.each(null==t?vt:("function"==typeof t?function(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}}:function(t){return function(){this.textContent=t}})(t)):this.node().textContent},html:function(t){return arguments.length?this.each(null==t?gt:("function"==typeof t?function(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}}:function(t){return function(){this.innerHTML=t}})(t)):this.node().innerHTML},raise:function(){return this.each(yt)},lower:function(){return this.each(_t)},append:function(t){var n="function"==typeof t?t:Z(t);return this.select(function(){return this.appendChild(n.apply(this,arguments))})},insert:function(t,n){var e="function"==typeof t?t:Z(t),r=null==n?bt:"function"==typeof n?n:K(n);return this.select(function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)})},remove:function(){return this.each(mt)},clone:function(t){return this.select(t?wt:xt)},datum:function(t){return arguments.length?this.property("__data__",t):this.node().__data__},on:function(t,n,e){var r,i,o=function(t){return t.trim().split(/^|\s+/).map(function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}(t+""),a=o.length;if(!(arguments.length<2)){for(u=n?St:At,null==e&&(e=!1),r=0;r<a;++r)this.each(u(o[r],n,e));return this}var u=this.node().__on;if(u)for(var c,f=0,s=u.length;f<s;++f)for(r=0,c=u[f];r<a;++r)if((i=o[r]).type===c.type&&i.name===c.name)return c.value},dispatch:function(t,n){return this.each(("function"==typeof n?function(t,n){return function(){return Et(this,t,n.apply(this,arguments))}}:function(t,n){return function(){return Et(this,t,n)}})(t,n))}};var Dt=0;function qt(){return new Lt}function Lt(){this._="@"+(++Dt).toString(36)}function Ut(){for(var n,e=t.event;n=e.sourceEvent;)e=n;return e}function Ot(t,n){var e=t.ownerSVGElement||t;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=n.clientX,r.y=n.clientY,[(r=r.matrixTransform(t.getScreenCTM().inverse())).x,r.y]}var i=t.getBoundingClientRect();return[n.clientX-i.left-t.clientLeft,n.clientY-i.top-t.clientTop]}function Bt(t){var n=Ut();return n.changedTouches&&(n=n.changedTouches[0]),Ot(t,n)}function Ft(t,n,e){arguments.length<3&&(e=n,n=Ut().changedTouches);for(var r,i=0,o=n?n.length:0;i<o;++i)if((r=n[i]).identifier===e)return Ot(t,r);return null}function Yt(){t.event.stopImmediatePropagation()}function It(){t.event.preventDefault(),t.event.stopImmediatePropagation()}function Ht(t){var n=t.document.documentElement,e=Rt(t).on("dragstart.drag",It,!0);"onselectstart"in n?e.on("selectstart.drag",It,!0):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect="none")}function jt(t,n){var e=t.document.documentElement,r=Rt(t).on("dragstart.drag",null);n&&(r.on("click.drag",It,!0),setTimeout(function(){r.on("click.drag",null)},0)),"onselectstart"in e?r.on("selectstart.drag",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}function Xt(t){return function(){return t}}function Vt(t,n,e,r,i,o,a,u,c,f){this.target=t,this.type=n,this.subject=e,this.identifier=r,this.active=i,this.x=o,this.y=a,this.dx=u,this.dy=c,this._=f}function Gt(){return!t.event.ctrlKey&&!t.event.button}function $t(){return this.parentNode}function Wt(n){return null==n?{x:t.event.x,y:t.event.y}:n}function Zt(){return navigator.maxTouchPoints||"ontouchstart"in this}function Qt(t,n,e){t.prototype=n.prototype=e,e.constructor=t}function Kt(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function Jt(){}Lt.prototype=qt.prototype={constructor:Lt,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}},Vt.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var tn="\\s*([+-]?\\d+)\\s*",nn="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",en="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",rn=/^#([0-9a-f]{3,8})$/,on=new RegExp("^rgb\\("+[tn,tn,tn]+"\\)$"),an=new RegExp("^rgb\\("+[en,en,en]+"\\)$"),un=new RegExp("^rgba\\("+[tn,tn,tn,nn]+"\\)$"),cn=new RegExp("^rgba\\("+[en,en,en,nn]+"\\)$"),fn=new RegExp("^hsl\\("+[nn,en,en]+"\\)$"),sn=new RegExp("^hsla\\("+[nn,en,en,nn]+"\\)$"),ln={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};function hn(){return this.rgb().formatHex()}function dn(){return this.rgb().formatRgb()}function pn(t){var n,e;return t=(t+"").trim().toLowerCase(),(n=rn.exec(t))?(e=n[1].length,n=parseInt(n[1],16),6===e?vn(n):3===e?new bn(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):8===e?gn(n>>24&255,n>>16&255,n>>8&255,(255&n)/255):4===e?gn(n>>12&15|n>>8&240,n>>8&15|n>>4&240,n>>4&15|240&n,((15&n)<<4|15&n)/255):null):(n=on.exec(t))?new bn(n[1],n[2],n[3],1):(n=an.exec(t))?new bn(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=un.exec(t))?gn(n[1],n[2],n[3],n[4]):(n=cn.exec(t))?gn(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=fn.exec(t))?Mn(n[1],n[2]/100,n[3]/100,1):(n=sn.exec(t))?Mn(n[1],n[2]/100,n[3]/100,n[4]):ln.hasOwnProperty(t)?vn(ln[t]):"transparent"===t?new bn(NaN,NaN,NaN,0):null}function vn(t){return new bn(t>>16&255,t>>8&255,255&t,1)}function gn(t,n,e,r){return r<=0&&(t=n=e=NaN),new bn(t,n,e,r)}function yn(t){return t instanceof Jt||(t=pn(t)),t?new bn((t=t.rgb()).r,t.g,t.b,t.opacity):new bn}function _n(t,n,e,r){return 1===arguments.length?yn(t):new bn(t,n,e,null==r?1:r)}function bn(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function mn(){return"#"+wn(this.r)+wn(this.g)+wn(this.b)}function xn(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function wn(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function Mn(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new An(t,n,e,r)}function Nn(t){if(t instanceof An)return new An(t.h,t.s,t.l,t.opacity);if(t instanceof Jt||(t=pn(t)),!t)return new An;if(t instanceof An)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),a=NaN,u=o-i,c=(o+i)/2;return u?(a=n===o?(e-r)/u+6*(e<r):e===o?(r-n)/u+2:(n-e)/u+4,u/=c<.5?o+i:2-o-i,a*=60):u=c>0&&c<1?0:a,new An(a,u,c,t.opacity)}function Tn(t,n,e,r){return 1===arguments.length?Nn(t):new An(t,n,e,null==r?1:r)}function An(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Sn(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}Qt(Jt,pn,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:hn,formatHex:hn,formatHsl:function(){return Nn(this).formatHsl()},formatRgb:dn,toString:dn}),Qt(bn,_n,Kt(Jt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new bn(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new bn(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:mn,formatHex:mn,formatRgb:xn,toString:xn})),Qt(An,Tn,Kt(Jt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new An(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new An(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new bn(Sn(t>=240?t-240:t+120,i,r),Sn(t,i,r),Sn(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));var kn=Math.PI/180,En=180/Math.PI,Cn=.96422,Pn=1,zn=.82521,Rn=4/29,Dn=6/29,qn=3*Dn*Dn,Ln=Dn*Dn*Dn;function Un(t){if(t instanceof Bn)return new Bn(t.l,t.a,t.b,t.opacity);if(t instanceof Vn)return Gn(t);t instanceof bn||(t=yn(t));var n,e,r=Hn(t.r),i=Hn(t.g),o=Hn(t.b),a=Fn((.2225045*r+.7168786*i+.0606169*o)/Pn);return r===i&&i===o?n=e=a:(n=Fn((.4360747*r+.3850649*i+.1430804*o)/Cn),e=Fn((.0139322*r+.0971045*i+.7141733*o)/zn)),new Bn(116*a-16,500*(n-a),200*(a-e),t.opacity)}function On(t,n,e,r){return 1===arguments.length?Un(t):new Bn(t,n,e,null==r?1:r)}function Bn(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function Fn(t){return t>Ln?Math.pow(t,1/3):t/qn+Rn}function Yn(t){return t>Dn?t*t*t:qn*(t-Rn)}function In(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Hn(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function jn(t){if(t instanceof Vn)return new Vn(t.h,t.c,t.l,t.opacity);if(t instanceof Bn||(t=Un(t)),0===t.a&&0===t.b)return new Vn(NaN,0<t.l&&t.l<100?0:NaN,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*En;return new Vn(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function Xn(t,n,e,r){return 1===arguments.length?jn(t):new Vn(t,n,e,null==r?1:r)}function Vn(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}function Gn(t){if(isNaN(t.h))return new Bn(t.l,0,0,t.opacity);var n=t.h*kn;return new Bn(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}Qt(Bn,On,Kt(Jt,{brighter:function(t){return new Bn(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new Bn(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new bn(In(3.1338561*(n=Cn*Yn(n))-1.6168667*(t=Pn*Yn(t))-.4906146*(e=zn*Yn(e))),In(-.9787684*n+1.9161415*t+.033454*e),In(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),Qt(Vn,Xn,Kt(Jt,{brighter:function(t){return new Vn(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new Vn(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return Gn(this).rgb()}}));var $n=-.14861,Wn=1.78277,Zn=-.29227,Qn=-.90649,Kn=1.97294,Jn=Kn*Qn,te=Kn*Wn,ne=Wn*Zn-Qn*$n;function ee(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof re)return new re(t.h,t.s,t.l,t.opacity);t instanceof bn||(t=yn(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(ne*r+Jn*n-te*e)/(ne+Jn-te),o=r-i,a=(Kn*(e-i)-Zn*o)/Qn,u=Math.sqrt(a*a+o*o)/(Kn*i*(1-i)),c=u?Math.atan2(a,o)*En-120:NaN;return new re(c<0?c+360:c,u,i,t.opacity)}(t):new re(t,n,e,null==r?1:r)}function re(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function ie(t,n,e,r,i){var o=t*t,a=o*t;return((1-3*t+3*o-a)*n+(4-6*o+3*a)*e+(1+3*t+3*o-3*a)*r+a*i)/6}function oe(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],a=r>0?t[r-1]:2*i-o,u=r<n-1?t[r+2]:2*o-i;return ie((e-r/n)*n,a,i,o,u)}}function ae(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],a=t[(r+1)%n],u=t[(r+2)%n];return ie((e-r/n)*n,i,o,a,u)}}function ue(t){return function(){return t}}function ce(t,n){return function(e){return t+e*n}}function fe(t,n){var e=n-t;return e?ce(t,e>180||e<-180?e-360*Math.round(e/360):e):ue(isNaN(t)?n:t)}function se(t){return 1==(t=+t)?le:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):ue(isNaN(n)?e:n)}}function le(t,n){var e=n-t;return e?ce(t,e):ue(isNaN(t)?n:t)}Qt(re,ee,Kt(Jt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new re(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new re(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*kn,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new bn(255*(n+e*($n*r+Wn*i)),255*(n+e*(Zn*r+Qn*i)),255*(n+e*(Kn*r)),this.opacity)}}));var he=function t(n){var e=se(n);function r(t,n){var r=e((t=_n(t)).r,(n=_n(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),a=le(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=a(n),t+""}}return r.gamma=t,r}(1);function de(t){return function(n){var e,r,i=n.length,o=new Array(i),a=new Array(i),u=new Array(i);for(e=0;e<i;++e)r=_n(n[e]),o[e]=r.r||0,a[e]=r.g||0,u[e]=r.b||0;return o=t(o),a=t(a),u=t(u),r.opacity=1,function(t){return r.r=o(t),r.g=a(t),r.b=u(t),r+""}}}var pe=de(oe),ve=de(ae);function ge(t,n){n||(n=[]);var e,r=t?Math.min(n.length,t.length):0,i=n.slice();return function(o){for(e=0;e<r;++e)i[e]=t[e]*(1-o)+n[e]*o;return i}}function ye(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)}function _e(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(i),a=new Array(r);for(e=0;e<i;++e)o[e]=Te(t[e],n[e]);for(;e<r;++e)a[e]=n[e];return function(t){for(e=0;e<i;++e)a[e]=o[e](t);return a}}function be(t,n){var e=new Date;return t=+t,n=+n,function(r){return e.setTime(t*(1-r)+n*r),e}}function me(t,n){return t=+t,n=+n,function(e){return t*(1-e)+n*e}}function xe(t,n){var e,r={},i={};for(e in null!==t&&"object"==typeof t||(t={}),null!==n&&"object"==typeof n||(n={}),n)e in t?r[e]=Te(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}}var we=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,Me=new RegExp(we.source,"g");function Ne(t,n){var e,r,i,o=we.lastIndex=Me.lastIndex=0,a=-1,u=[],c=[];for(t+="",n+="";(e=we.exec(t))&&(r=Me.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(e=e[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,c.push({i:a,x:me(e,r)})),o=Me.lastIndex;return o<n.length&&(i=n.slice(o),u[a]?u[a]+=i:u[++a]=i),u.length<2?c[0]?function(t){return function(n){return t(n)+""}}(c[0].x):function(t){return function(){return t}}(n):(n=c.length,function(t){for(var e,r=0;r<n;++r)u[(e=c[r]).i]=e.x(t);return u.join("")})}function Te(t,n){var e,r=typeof n;return null==n||"boolean"===r?ue(n):("number"===r?me:"string"===r?(e=pn(n))?(n=e,he):Ne:n instanceof pn?he:n instanceof Date?be:ye(n)?ge:Array.isArray(n)?_e:"function"!=typeof n.valueOf&&"function"!=typeof n.toString||isNaN(n)?xe:me)(t,n)}function Ae(t,n){return t=+t,n=+n,function(e){return Math.round(t*(1-e)+n*e)}}var Se,ke,Ee,Ce,Pe=180/Math.PI,ze={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function Re(t,n,e,r,i,o){var a,u,c;return(a=Math.sqrt(t*t+n*n))&&(t/=a,n/=a),(c=t*e+n*r)&&(e-=t*c,r-=n*c),(u=Math.sqrt(e*e+r*r))&&(e/=u,r/=u,c/=u),t*r<n*e&&(t=-t,n=-n,c=-c,a=-a),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*Pe,skewX:Math.atan(c)*Pe,scaleX:a,scaleY:u}}function De(t,n,e,r){function i(t){return t.length?t.pop()+" ":""}return function(o,a){var u=[],c=[];return o=t(o),a=t(a),function(t,r,i,o,a,u){if(t!==i||r!==o){var c=a.push("translate(",null,n,null,e);u.push({i:c-4,x:me(t,i)},{i:c-2,x:me(r,o)})}else(i||o)&&a.push("translate("+i+n+o+e)}(o.translateX,o.translateY,a.translateX,a.translateY,u,c),function(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:me(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,a.rotate,u,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:me(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,a.skewX,u,c),function(t,n,e,r,o,a){if(t!==e||n!==r){var u=o.push(i(o)+"scale(",null,",",null,")");a.push({i:u-4,x:me(t,e)},{i:u-2,x:me(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,a.scaleX,a.scaleY,u,c),o=a=null,function(t){for(var n,e=-1,r=c.length;++e<r;)u[(n=c[e]).i]=n.x(t);return u.join("")}}}var qe=De(function(t){return"none"===t?ze:(Se||(Se=document.createElement("DIV"),ke=document.documentElement,Ee=document.defaultView),Se.style.transform=t,t=Ee.getComputedStyle(ke.appendChild(Se),null).getPropertyValue("transform"),ke.removeChild(Se),Re(+(t=t.slice(7,-1).split(","))[0],+t[1],+t[2],+t[3],+t[4],+t[5]))},"px, ","px)","deg)"),Le=De(function(t){return null==t?ze:(Ce||(Ce=document.createElementNS("http://www.w3.org/2000/svg","g")),Ce.setAttribute("transform",t),(t=Ce.transform.baseVal.consolidate())?Re((t=t.matrix).a,t.b,t.c,t.d,t.e,t.f):ze)},", ",")",")"),Ue=Math.SQRT2,Oe=2,Be=4,Fe=1e-12;function Ye(t){return((t=Math.exp(t))+1/t)/2}function Ie(t,n){var e,r,i=t[0],o=t[1],a=t[2],u=n[0],c=n[1],f=n[2],s=u-i,l=c-o,h=s*s+l*l;if(h<Fe)r=Math.log(f/a)/Ue,e=function(t){return[i+t*s,o+t*l,a*Math.exp(Ue*t*r)]};else{var d=Math.sqrt(h),p=(f*f-a*a+Be*h)/(2*a*Oe*d),v=(f*f-a*a-Be*h)/(2*f*Oe*d),g=Math.log(Math.sqrt(p*p+1)-p),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-g)/Ue,e=function(t){var n=t*r,e=Ye(g),u=a/(Oe*d)*(e*function(t){return((t=Math.exp(2*t))-1)/(t+1)}(Ue*n+g)-function(t){return((t=Math.exp(t))-1/t)/2}(g));return[i+u*s,o+u*l,a*e/Ye(Ue*n+g)]}}return e.duration=1e3*r,e}function He(t){return function(n,e){var r=t((n=Tn(n)).h,(e=Tn(e)).h),i=le(n.s,e.s),o=le(n.l,e.l),a=le(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var je=He(fe),Xe=He(le);function Ve(t){return function(n,e){var r=t((n=Xn(n)).h,(e=Xn(e)).h),i=le(n.c,e.c),o=le(n.l,e.l),a=le(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var Ge=Ve(fe),$e=Ve(le);function We(t){return function n(e){function r(n,r){var i=t((n=ee(n)).h,(r=ee(r)).h),o=le(n.s,r.s),a=le(n.l,r.l),u=le(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=a(Math.pow(t,e)),n.opacity=u(t),n+""}}return e=+e,r.gamma=n,r}(1)}var Ze=We(fe),Qe=We(le);var Ke,Je,tr=0,nr=0,er=0,rr=1e3,ir=0,or=0,ar=0,ur="object"==typeof performance&&performance.now?performance:Date,cr="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function fr(){return or||(cr(sr),or=ur.now()+ar)}function sr(){or=0}function lr(){this._call=this._time=this._next=null}function hr(t,n,e){var r=new lr;return r.restart(t,n,e),r}function dr(){fr(),++tr;for(var t,n=Ke;n;)(t=or-n._time)>=0&&n._call.call(null,t),n=n._next;--tr}function pr(){or=(ir=ur.now())+ar,tr=nr=0;try{dr()}finally{tr=0,function(){var t,n,e=Ke,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Ke=n);Je=t,gr(r)}(),or=0}}function vr(){var t=ur.now(),n=t-ir;n>rr&&(ar-=n,ir=t)}function gr(t){tr||(nr&&(nr=clearTimeout(nr)),t-or>24?(t<1/0&&(nr=setTimeout(pr,t-ur.now()-ar)),er&&(er=clearInterval(er))):(er||(ir=ur.now(),er=setInterval(vr,rr)),tr=1,cr(pr)))}function yr(t,n,e){var r=new lr;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r}lr.prototype=hr.prototype={constructor:lr,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?fr():+e)+(null==n?0:+n),this._next||Je===this||(Je?Je._next=this:Ke=this,Je=this),this._call=t,this._time=e,gr()},stop:function(){this._call&&(this._call=null,this._time=1/0,gr())}};var _r=I("start","end","cancel","interrupt"),br=[],mr=0,xr=1,wr=2,Mr=3,Nr=4,Tr=5,Ar=6;function Sr(t,n,e,r,i,o){var a=t.__transition;if(a){if(e in a)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(c){var f,s,l,h;if(e.state!==xr)return u();for(f in i)if((h=i[f]).name===e.name){if(h.state===Mr)return yr(o);h.state===Nr?(h.state=Ar,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[f]):+f<n&&(h.state=Ar,h.timer.stop(),h.on.call("cancel",t,t.__data__,h.index,h.group),delete i[f])}if(yr(function(){e.state===Mr&&(e.state=Nr,e.timer.restart(a,e.delay,e.time),a(c))}),e.state=wr,e.on.call("start",t,t.__data__,e.index,e.group),e.state===wr){for(e.state=Mr,r=new Array(l=e.tween.length),f=0,s=-1;f<l;++f)(h=e.tween[f].value.call(t,t.__data__,e.index,e.group))&&(r[++s]=h);r.length=s+1}}function a(n){for(var i=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(u),e.state=Tr,1),o=-1,a=r.length;++o<a;)r[o].call(t,i);e.state===Tr&&(e.on.call("end",t,t.__data__,e.index,e.group),u())}function u(){for(var r in e.state=Ar,e.timer.stop(),delete i[n],i)return;delete t.__transition}i[n]=e,e.timer=hr(function(t){e.state=xr,e.timer.restart(o,e.delay,e.time),e.delay<=t&&o(t-e.delay)},0,e.time)}(t,e,{name:n,index:r,group:i,on:_r,tween:br,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:mr})}function kr(t,n){var e=Cr(t,n);if(e.state>mr)throw new Error("too late; already scheduled");return e}function Er(t,n){var e=Cr(t,n);if(e.state>Mr)throw new Error("too late; already running");return e}function Cr(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}function Pr(t,n){var e,r,i,o=t.__transition,a=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>wr&&e.state<Tr,e.state=Ar,e.timer.stop(),e.on.call(r?"interrupt":"cancel",t,t.__data__,e.index,e.group),delete o[i]):a=!1;a&&delete t.__transition}}function zr(t,n,e){var r=t._id;return t.each(function(){var t=Er(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)}),function(t){return Cr(t,r).value[n]}}function Rr(t,n){var e;return("number"==typeof n?me:n instanceof pn?he:(e=pn(n))?(n=e,he):Ne)(t,n)}var Dr=zt.prototype.constructor;function qr(t){return function(){this.style.removeProperty(t)}}var Lr=0;function Ur(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function Or(t){return zt().transition(t)}function Br(){return++Lr}var Fr=zt.prototype;function Yr(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function Ir(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}Ur.prototype=Or.prototype={constructor:Ur,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=K(t));for(var r=this._groups,i=r.length,o=new Array(i),a=0;a<i;++a)for(var u,c,f=r[a],s=f.length,l=o[a]=new Array(s),h=0;h<s;++h)(u=f[h])&&(c=t.call(u,u.__data__,h,f))&&("__data__"in u&&(c.__data__=u.__data__),l[h]=c,Sr(l[h],n,e,h,l,Cr(u,e)));return new Ur(o,this._parents,n,e)},selectAll:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=tt(t));for(var r=this._groups,i=r.length,o=[],a=[],u=0;u<i;++u)for(var c,f=r[u],s=f.length,l=0;l<s;++l)if(c=f[l]){for(var h,d=t.call(c,c.__data__,l,f),p=Cr(c,e),v=0,g=d.length;v<g;++v)(h=d[v])&&Sr(h,n,e,v,d,p);o.push(d),a.push(c)}return new Ur(o,a,n,e)},filter:function(t){"function"!=typeof t&&(t=nt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,c=r[i]=[],f=0;f<u;++f)(o=a[f])&&t.call(o,o.__data__,f,a)&&c.push(o);return new Ur(r,this._parents,this._name,this._id)},merge:function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),a=new Array(r),u=0;u<o;++u)for(var c,f=n[u],s=e[u],l=f.length,h=a[u]=new Array(l),d=0;d<l;++d)(c=f[d]||s[d])&&(h[d]=c);for(;u<r;++u)a[u]=n[u];return new Ur(a,this._parents,this._name,this._id)},selection:function(){return new Dr(this._groups,this._parents)},transition:function(){for(var t=this._name,n=this._id,e=Br(),r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],c=u.length,f=0;f<c;++f)if(a=u[f]){var s=Cr(a,n);Sr(a,t,e,f,u,{time:s.time+s.delay+s.duration,delay:0,duration:s.duration,ease:s.ease})}return new Ur(r,this._parents,t,e)},call:Fr.call,nodes:Fr.nodes,node:Fr.node,size:Fr.size,empty:Fr.empty,each:Fr.each,on:function(t,n){var e=this._id;return arguments.length<2?Cr(this.node(),e).on.on(t):this.each(function(t,n,e){var r,i,o=function(t){return(t+"").trim().split(/^|\s+/).every(function(t){var n=t.indexOf(".");return n>=0&&(t=t.slice(0,n)),!t||"start"===t})}(n)?kr:Er;return function(){var a=o(this,t),u=a.on;u!==r&&(i=(r=u).copy()).on(n,e),a.on=i}}(e,t,n))},attr:function(t,n){var e=W(t),r="transform"===e?Le:Rr;return this.attrTween(t,"function"==typeof n?(e.local?function(t,n,e){var r,i,o;return function(){var a,u,c=e(this);if(null!=c)return(a=this.getAttributeNS(t.space,t.local))===(u=c+"")?null:a===r&&u===i?o:(i=u,o=n(r=a,c));this.removeAttributeNS(t.space,t.local)}}:function(t,n,e){var r,i,o;return function(){var a,u,c=e(this);if(null!=c)return(a=this.getAttribute(t))===(u=c+"")?null:a===r&&u===i?o:(i=u,o=n(r=a,c));this.removeAttribute(t)}})(e,r,zr(this,"attr."+t,n)):null==n?(e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}})(e):(e.local?function(t,n,e){var r,i,o=e+"";return function(){var a=this.getAttributeNS(t.space,t.local);return a===o?null:a===r?i:i=n(r=a,e)}}:function(t,n,e){var r,i,o=e+"";return function(){var a=this.getAttribute(t);return a===o?null:a===r?i:i=n(r=a,e)}})(e,r,n))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=W(t);return this.tween(e,(r.local?function(t,n){var e,r;function i(){var i=n.apply(this,arguments);return i!==r&&(e=(r=i)&&function(t,n){return function(e){this.setAttributeNS(t.space,t.local,n.call(this,e))}}(t,i)),e}return i._value=n,i}:function(t,n){var e,r;function i(){var i=n.apply(this,arguments);return i!==r&&(e=(r=i)&&function(t,n){return function(e){this.setAttribute(t,n.call(this,e))}}(t,i)),e}return i._value=n,i})(r,n))},style:function(t,n,e){var r="transform"==(t+="")?qe:Rr;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=ft(this,t),a=(this.style.removeProperty(t),ft(this,t));return o===a?null:o===e&&a===r?i:i=n(e=o,r=a)}}(t,r)).on("end.style."+t,qr(t)):"function"==typeof n?this.styleTween(t,function(t,n,e){var r,i,o;return function(){var a=ft(this,t),u=e(this),c=u+"";return null==u&&(this.style.removeProperty(t),c=u=ft(this,t)),a===c?null:a===r&&c===i?o:(i=c,o=n(r=a,u))}}(t,r,zr(this,"style."+t,n))).each(function(t,n){var e,r,i,o,a="style."+n,u="end."+a;return function(){var c=Er(this,t),f=c.on,s=null==c.value[a]?o||(o=qr(n)):void 0;f===e&&i===s||(r=(e=f).copy()).on(u,i=s),c.on=r}}(this._id,t)):this.styleTween(t,function(t,n,e){var r,i,o=e+"";return function(){var a=ft(this,t);return a===o?null:a===r?i:i=n(r=a,e)}}(t,r,n),e).on("end.style."+t,null)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){var r,i;function o(){var o=n.apply(this,arguments);return o!==i&&(r=(i=o)&&function(t,n,e){return function(r){this.style.setProperty(t,n.call(this,r),e)}}(t,o,e)),r}return o._value=n,o}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(zr(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},textTween:function(t){var n="text";if(arguments.length<1)return(n=this.tween(n))&&n._value;if(null==t)return this.tween(n,null);if("function"!=typeof t)throw new Error;return this.tween(n,function(t){var n,e;function r(){var r=t.apply(this,arguments);return r!==e&&(n=(e=r)&&function(t){return function(n){this.textContent=t.call(this,n)}}(r)),n}return r._value=t,r}(t))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=Cr(this.node(),e).tween,o=0,a=i.length;o<a;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?function(t,n){var e,r;return function(){var i=Er(this,t),o=i.tween;if(o!==e)for(var a=0,u=(r=e=o).length;a<u;++a)if(r[a].name===n){(r=r.slice()).splice(a,1);break}i.tween=r}}:function(t,n,e){var r,i;if("function"!=typeof e)throw new Error;return function(){var o=Er(this,t),a=o.tween;if(a!==r){i=(r=a).slice();for(var u={name:n,value:e},c=0,f=i.length;c<f;++c)if(i[c].name===n){i[c]=u;break}c===f&&i.push(u)}o.tween=i}})(e,t,n))},delay:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?function(t,n){return function(){kr(this,t).delay=+n.apply(this,arguments)}}:function(t,n){return n=+n,function(){kr(this,t).delay=n}})(n,t)):Cr(this.node(),n).delay},duration:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?function(t,n){return function(){Er(this,t).duration=+n.apply(this,arguments)}}:function(t,n){return n=+n,function(){Er(this,t).duration=n}})(n,t)):Cr(this.node(),n).duration},ease:function(t){var n=this._id;return arguments.length?this.each(function(t,n){if("function"!=typeof n)throw new Error;return function(){Er(this,t).ease=n}}(n,t)):Cr(this.node(),n).ease},end:function(){var t,n,e=this,r=e._id,i=e.size();return new Promise(function(o,a){var u={value:a},c={value:function(){0==--i&&o()}};e.each(function(){var e=Er(this,r),i=e.on;i!==t&&((n=(t=i).copy())._.cancel.push(u),n._.interrupt.push(u),n._.end.push(c)),e.on=n})})}};var Hr=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(3),jr=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(3),Xr=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(3),Vr=Math.PI,Gr=Vr/2;function $r(t){return(1-Math.cos(Vr*t))/2}function Wr(t){return((t*=2)<=1?Math.pow(2,10*t-10):2-Math.pow(2,10-10*t))/2}function Zr(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}var Qr=4/11,Kr=6/11,Jr=8/11,ti=.75,ni=9/11,ei=10/11,ri=.9375,ii=21/22,oi=63/64,ai=1/Qr/Qr;function ui(t){return(t=+t)<Qr?ai*t*t:t<Jr?ai*(t-=Kr)*t+ti:t<ei?ai*(t-=ni)*t+ri:ai*(t-=ii)*t+oi}var ci=function t(n){function e(t){return t*t*((n+1)*t-n)}return n=+n,e.overshoot=t,e}(1.70158),fi=function t(n){function e(t){return--t*t*((n+1)*t+n)+1}return n=+n,e.overshoot=t,e}(1.70158),si=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(1.70158),li=2*Math.PI,hi=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=li);function i(t){return n*Math.pow(2,10*--t)*Math.sin((r-t)/e)}return i.amplitude=function(n){return t(n,e*li)},i.period=function(e){return t(n,e)},i}(1,.3),di=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=li);function i(t){return 1-n*Math.pow(2,-10*(t=+t))*Math.sin((t+r)/e)}return i.amplitude=function(n){return t(n,e*li)},i.period=function(e){return t(n,e)},i}(1,.3),pi=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=li);function i(t){return((t=2*t-1)<0?n*Math.pow(2,10*t)*Math.sin((r-t)/e):2-n*Math.pow(2,-10*t)*Math.sin((r+t)/e))/2}return i.amplitude=function(n){return t(n,e*li)},i.period=function(e){return t(n,e)},i}(1,.3),vi={time:null,delay:0,duration:250,ease:Ir};function gi(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))return vi.time=fr(),vi;return e}zt.prototype.interrupt=function(t){return this.each(function(){Pr(this,t)})},zt.prototype.transition=function(t){var n,e;t instanceof Ur?(n=t._id,t=t._name):(n=Br(),(e=vi).time=fr(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],c=u.length,f=0;f<c;++f)(a=u[f])&&Sr(a,t,n,f,u,e||gi(a,n));return new Ur(r,this._parents,t,n)};var yi=[null];function _i(t){return function(){return t}}function bi(t,n,e){this.target=t,this.type=n,this.selection=e}function mi(){t.event.stopImmediatePropagation()}function xi(){t.event.preventDefault(),t.event.stopImmediatePropagation()}var wi={name:"drag"},Mi={name:"space"},Ni={name:"handle"},Ti={name:"center"};function Ai(t){return[+t[0],+t[1]]}function Si(t){return[Ai(t[0]),Ai(t[1])]}var ki={name:"x",handles:["w","e"].map(Li),input:function(t,n){return null==t?null:[[+t[0],n[0][1]],[+t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},Ei={name:"y",handles:["n","s"].map(Li),input:function(t,n){return null==t?null:[[n[0][0],+t[0]],[n[1][0],+t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},Ci={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(Li),input:function(t){return null==t?null:Si(t)},output:function(t){return t}},Pi={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},zi={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},Ri={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},Di={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},qi={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function Li(t){return{type:t}}function Ui(){return!t.event.ctrlKey&&!t.event.button}function Oi(){var t=this.ownerSVGElement||this;return t.hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function Bi(){return navigator.maxTouchPoints||"ontouchstart"in this}function Fi(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function Yi(n){var e,r=Oi,i=Ui,o=Bi,a=!0,u=I("start","brush","end"),c=6;function f(t){var e=t.property("__brush",g).selectAll(".overlay").data([Li("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",Pi.overlay).merge(e).each(function(){var t=Fi(this).extent;Rt(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])}),t.selectAll(".selection").data([Li("selection")]).enter().append("rect").attr("class","selection").attr("cursor",Pi.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var r=t.selectAll(".handle").data(n.handles,function(t){return t.type});r.exit().remove(),r.enter().append("rect").attr("class",function(t){return"handle handle--"+t.type}).attr("cursor",function(t){return Pi[t.type]}),t.each(s).attr("fill","none").attr("pointer-events","all").on("mousedown.brush",d).filter(o).on("touchstart.brush",d).on("touchmove.brush",p).on("touchend.brush touchcancel.brush",v).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function s(){var t=Rt(this),n=Fi(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",function(t){return"e"===t.type[t.type.length-1]?n[1][0]-c/2:n[0][0]-c/2}).attr("y",function(t){return"s"===t.type[0]?n[1][1]-c/2:n[0][1]-c/2}).attr("width",function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+c:c}).attr("height",function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+c:c})):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function l(t,n,e){return!e&&t.__brush.emitter||new h(t,n)}function h(t,n){this.that=t,this.args=n,this.state=t.__brush,this.active=0}function d(){if((!e||t.event.touches)&&i.apply(this,arguments)){var r,o,u,c,f,h,d,p,v,g,y,_,b=this,m=t.event.target.__data__.type,x="selection"===(a&&t.event.metaKey?m="overlay":m)?wi:a&&t.event.altKey?Ti:Ni,w=n===Ei?null:Di[m],M=n===ki?null:qi[m],N=Fi(b),T=N.extent,A=N.selection,S=T[0][0],k=T[0][1],E=T[1][0],C=T[1][1],P=0,z=0,R=w&&M&&a&&t.event.shiftKey,D=t.event.touches?(_=t.event.changedTouches[0].identifier,function(n){return Ft(n,t.event.touches,_)}):Bt,q=D(b),L=q,U=l(b,arguments,!0).beforestart();"overlay"===m?(A&&(v=!0),N.selection=A=[[r=n===Ei?S:q[0],u=n===ki?k:q[1]],[f=n===Ei?E:r,d=n===ki?C:u]]):(r=A[0][0],u=A[0][1],f=A[1][0],d=A[1][1]),o=r,c=u,h=f,p=d;var O=Rt(b).attr("pointer-events","none"),B=O.selectAll(".overlay").attr("cursor",Pi[m]);if(t.event.touches)U.moved=Y,U.ended=H;else{var F=Rt(t.event.view).on("mousemove.brush",Y,!0).on("mouseup.brush",H,!0);a&&F.on("keydown.brush",function(){switch(t.event.keyCode){case 16:R=w&&M;break;case 18:x===Ni&&(w&&(f=h-P*w,r=o+P*w),M&&(d=p-z*M,u=c+z*M),x=Ti,I());break;case 32:x!==Ni&&x!==Ti||(w<0?f=h-P:w>0&&(r=o-P),M<0?d=p-z:M>0&&(u=c-z),x=Mi,B.attr("cursor",Pi.selection),I());break;default:return}xi()},!0).on("keyup.brush",function(){switch(t.event.keyCode){case 16:R&&(g=y=R=!1,I());break;case 18:x===Ti&&(w<0?f=h:w>0&&(r=o),M<0?d=p:M>0&&(u=c),x=Ni,I());break;case 32:x===Mi&&(t.event.altKey?(w&&(f=h-P*w,r=o+P*w),M&&(d=p-z*M,u=c+z*M),x=Ti):(w<0?f=h:w>0&&(r=o),M<0?d=p:M>0&&(u=c),x=Ni),B.attr("cursor",Pi[m]),I());break;default:return}xi()},!0),Ht(t.event.view)}mi(),Pr(b),s.call(b),U.start()}function Y(){var t=D(b);!R||g||y||(Math.abs(t[0]-L[0])>Math.abs(t[1]-L[1])?y=!0:g=!0),L=t,v=!0,xi(),I()}function I(){var t;switch(P=L[0]-q[0],z=L[1]-q[1],x){case Mi:case wi:w&&(P=Math.max(S-r,Math.min(E-f,P)),o=r+P,h=f+P),M&&(z=Math.max(k-u,Math.min(C-d,z)),c=u+z,p=d+z);break;case Ni:w<0?(P=Math.max(S-r,Math.min(E-r,P)),o=r+P,h=f):w>0&&(P=Math.max(S-f,Math.min(E-f,P)),o=r,h=f+P),M<0?(z=Math.max(k-u,Math.min(C-u,z)),c=u+z,p=d):M>0&&(z=Math.max(k-d,Math.min(C-d,z)),c=u,p=d+z);break;case Ti:w&&(o=Math.max(S,Math.min(E,r-P*w)),h=Math.max(S,Math.min(E,f+P*w))),M&&(c=Math.max(k,Math.min(C,u-z*M)),p=Math.max(k,Math.min(C,d+z*M)))}h<o&&(w*=-1,t=r,r=f,f=t,t=o,o=h,h=t,m in zi&&B.attr("cursor",Pi[m=zi[m]])),p<c&&(M*=-1,t=u,u=d,d=t,t=c,c=p,p=t,m in Ri&&B.attr("cursor",Pi[m=Ri[m]])),N.selection&&(A=N.selection),g&&(o=A[0][0],h=A[1][0]),y&&(c=A[0][1],p=A[1][1]),A[0][0]===o&&A[0][1]===c&&A[1][0]===h&&A[1][1]===p||(N.selection=[[o,c],[h,p]],s.call(b),U.brush())}function H(){if(mi(),t.event.touches){if(t.event.touches.length)return;e&&clearTimeout(e),e=setTimeout(function(){e=null},500)}else jt(t.event.view,v),F.on("keydown.brush keyup.brush mousemove.brush mouseup.brush",null);O.attr("pointer-events","all"),B.attr("cursor",Pi.overlay),N.selection&&(A=N.selection),function(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}(A)&&(N.selection=null,s.call(b)),U.end()}}function p(){l(this,arguments).moved()}function v(){l(this,arguments).ended()}function g(){var t=this.__brush||{selection:null};return t.extent=Si(r.apply(this,arguments)),t.dim=n,t}return f.move=function(t,e){t.selection?t.on("start.brush",function(){l(this,arguments).beforestart().start()}).on("interrupt.brush end.brush",function(){l(this,arguments).end()}).tween("brush",function(){var t=this,r=t.__brush,i=l(t,arguments),o=r.selection,a=n.input("function"==typeof e?e.apply(this,arguments):e,r.extent),u=Te(o,a);function c(n){r.selection=1===n&&null===a?null:u(n),s.call(t),i.brush()}return null!==o&&null!==a?c:c(1)}):t.each(function(){var t=this,r=arguments,i=t.__brush,o=n.input("function"==typeof e?e.apply(t,r):e,i.extent),a=l(t,r).beforestart();Pr(t),i.selection=null===o?null:o,s.call(t),a.start().brush().end()})},f.clear=function(t){f.move(t,null)},h.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting?(this.starting=!1,this.emit("start")):this.emit("brush"),this},brush:function(){return this.emit("brush"),this},end:function(){return 0==--this.active&&(delete this.state.emitter,this.emit("end")),this},emit:function(t){kt(new bi(f,t,n.output(this.state.selection)),u.apply,u,[t,this.that,this.args])}},f.extent=function(t){return arguments.length?(r="function"==typeof t?t:_i(Si(t)),f):r},f.filter=function(t){return arguments.length?(i="function"==typeof t?t:_i(!!t),f):i},f.touchable=function(t){return arguments.length?(o="function"==typeof t?t:_i(!!t),f):o},f.handleSize=function(t){return arguments.length?(c=+t,f):c},f.keyModifiers=function(t){return arguments.length?(a=!!t,f):a},f.on=function(){var t=u.on.apply(u,arguments);return t===u?f:t},f}var Ii=Math.cos,Hi=Math.sin,ji=Math.PI,Xi=ji/2,Vi=2*ji,Gi=Math.max;function $i(t){return function(n,e){return t(n.source.value+n.target.value,e.source.value+e.target.value)}}var Wi=Array.prototype.slice;function Zi(t){return function(){return t}}var Qi=Math.PI,Ki=2*Qi,Ji=Ki-1e-6;function to(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function no(){return new to}function eo(t){return t.source}function ro(t){return t.target}function io(t){return t.radius}function oo(t){return t.startAngle}function ao(t){return t.endAngle}to.prototype=no.prototype={constructor:to,moveTo:function(t,n){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,n){this._+="L"+(this._x1=+t)+","+(this._y1=+n)},quadraticCurveTo:function(t,n,e,r){this._+="Q"+ +t+","+ +n+","+(this._x1=+e)+","+(this._y1=+r)},bezierCurveTo:function(t,n,e,r,i,o){this._+="C"+ +t+","+ +n+","+ +e+","+ +r+","+(this._x1=+i)+","+(this._y1=+o)},arcTo:function(t,n,e,r,i){t=+t,n=+n,e=+e,r=+r,i=+i;var o=this._x1,a=this._y1,u=e-t,c=r-n,f=o-t,s=a-n,l=f*f+s*s;if(i<0)throw new Error("negative radius: "+i);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=n);else if(l>1e-6)if(Math.abs(s*u-c*f)>1e-6&&i){var h=e-o,d=r-a,p=u*u+c*c,v=h*h+d*d,g=Math.sqrt(p),y=Math.sqrt(l),_=i*Math.tan((Qi-Math.acos((p+l-v)/(2*g*y)))/2),b=_/y,m=_/g;Math.abs(b-1)>1e-6&&(this._+="L"+(t+b*f)+","+(n+b*s)),this._+="A"+i+","+i+",0,0,"+ +(s*h>f*d)+","+(this._x1=t+m*u)+","+(this._y1=n+m*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n,o=!!o;var a=(e=+e)*Math.cos(r),u=e*Math.sin(r),c=t+a,f=n+u,s=1^o,l=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+f:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-f)>1e-6)&&(this._+="L"+c+","+f),e&&(l<0&&(l=l%Ki+Ki),l>Ji?this._+="A"+e+","+e+",0,1,"+s+","+(t-a)+","+(n-u)+"A"+e+","+e+",0,1,"+s+","+(this._x1=c)+","+(this._y1=f):l>1e-6&&(this._+="A"+e+","+e+",0,"+ +(l>=Qi)+","+s+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};function uo(){}function co(t,n){var e=new uo;if(t instanceof uo)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(null==n)for(;++i<o;)e.set(i,t[i]);else for(;++i<o;)e.set(n(r=t[i],i,t),r)}else if(t)for(var a in t)e.set(a,t[a]);return e}function fo(){return{}}function so(t,n,e){t[n]=e}function lo(){return co()}function ho(t,n,e){t.set(n,e)}function po(){}uo.prototype=co.prototype={constructor:uo,has:function(t){return"$"+t in this},get:function(t){return this["$"+t]},set:function(t,n){return this["$"+t]=n,this},remove:function(t){var n="$"+t;return n in this&&delete this[n]},clear:function(){for(var t in this)"$"===t[0]&&delete this[t]},keys:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(n.slice(1));return t},values:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(this[n]);return t},entries:function(){var t=[];for(var n in this)"$"===n[0]&&t.push({key:n.slice(1),value:this[n]});return t},size:function(){var t=0;for(var n in this)"$"===n[0]&&++t;return t},empty:function(){for(var t in this)if("$"===t[0])return!1;return!0},each:function(t){for(var n in this)"$"===n[0]&&t(this[n],n.slice(1),this)}};var vo=co.prototype;function go(t,n){var e=new po;if(t instanceof po)t.each(function(t){e.add(t)});else if(t){var r=-1,i=t.length;if(null==n)for(;++r<i;)e.add(t[r]);else for(;++r<i;)e.add(n(t[r],r,t))}return e}po.prototype=go.prototype={constructor:po,has:vo.has,add:function(t){return this["$"+(t+="")]=t,this},remove:vo.remove,clear:vo.clear,values:vo.keys,size:vo.size,empty:vo.empty,each:vo.each};var yo=Array.prototype.slice;function _o(t,n){return t-n}function bo(t){return function(){return t}}function mo(t,n){for(var e,r=-1,i=n.length;++r<i;)if(e=xo(t,n[r]))return e;return 0}function xo(t,n){for(var e=n[0],r=n[1],i=-1,o=0,a=t.length,u=a-1;o<a;u=o++){var c=t[o],f=c[0],s=c[1],l=t[u],h=l[0],d=l[1];if(wo(c,l,n))return 0;s>r!=d>r&&e<(h-f)*(r-s)/(d-s)+f&&(i=-i)}return i}function wo(t,n,e){var r,i,o,a;return function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])==(e[0]-t[0])*(n[1]-t[1])}(t,n,e)&&(i=t[r=+(t[0]===n[0])],o=e[r],a=n[r],i<=o&&o<=a||a<=o&&o<=i)}function Mo(){}var No=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]];function To(){var t=1,n=1,e=M,r=u;function i(t){var n=e(t);if(Array.isArray(n))n=n.slice().sort(_o);else{var r=s(t),i=r[0],a=r[1];n=w(i,a,n),n=g(Math.floor(i/n)*n,Math.floor(a/n)*n,n)}return n.map(function(n){return o(t,n)})}function o(e,i){var o=[],u=[];return function(e,r,i){var o,u,c,f,s,l,h=new Array,d=new Array;o=u=-1,f=e[0]>=r,No[f<<1].forEach(p);for(;++o<t-1;)c=f,f=e[o+1]>=r,No[c|f<<1].forEach(p);No[f<<0].forEach(p);for(;++u<n-1;){for(o=-1,f=e[u*t+t]>=r,s=e[u*t]>=r,No[f<<1|s<<2].forEach(p);++o<t-1;)c=f,f=e[u*t+t+o+1]>=r,l=s,s=e[u*t+o+1]>=r,No[c|f<<1|s<<2|l<<3].forEach(p);No[f|s<<3].forEach(p)}o=-1,s=e[u*t]>=r,No[s<<2].forEach(p);for(;++o<t-1;)l=s,s=e[u*t+o+1]>=r,No[s<<2|l<<3].forEach(p);function p(t){var n,e,r=[t[0][0]+o,t[0][1]+u],c=[t[1][0]+o,t[1][1]+u],f=a(r),s=a(c);(n=d[f])?(e=h[s])?(delete d[n.end],delete h[e.start],n===e?(n.ring.push(c),i(n.ring)):h[n.start]=d[e.end]={start:n.start,end:e.end,ring:n.ring.concat(e.ring)}):(delete d[n.end],n.ring.push(c),d[n.end=s]=n):(n=h[s])?(e=d[f])?(delete h[n.start],delete d[e.end],n===e?(n.ring.push(c),i(n.ring)):h[e.start]=d[n.end]={start:e.start,end:n.end,ring:e.ring.concat(n.ring)}):(delete h[n.start],n.ring.unshift(r),h[n.start=f]=n):h[f]=d[s]={start:f,end:s,ring:[r,c]}}No[s<<3].forEach(p)}(e,i,function(t){r(t,e,i),function(t){for(var n=0,e=t.length,r=t[e-1][1]*t[0][0]-t[e-1][0]*t[0][1];++n<e;)r+=t[n-1][1]*t[n][0]-t[n-1][0]*t[n][1];return r}(t)>0?o.push([t]):u.push(t)}),u.forEach(function(t){for(var n,e=0,r=o.length;e<r;++e)if(-1!==mo((n=o[e])[0],t))return void n.push(t)}),{type:"MultiPolygon",value:i,coordinates:o}}function a(n){return 2*n[0]+n[1]*(t+1)*4}function u(e,r,i){e.forEach(function(e){var o,a=e[0],u=e[1],c=0|a,f=0|u,s=r[f*t+c];a>0&&a<t&&c===a&&(o=r[f*t+c-1],e[0]=a+(i-o)/(s-o)-.5),u>0&&u<n&&f===u&&(o=r[(f-1)*t+c],e[1]=u+(i-o)/(s-o)-.5)})}return i.contour=o,i.size=function(e){if(!arguments.length)return[t,n];var r=Math.ceil(e[0]),o=Math.ceil(e[1]);if(!(r>0&&o>0))throw new Error("invalid size");return t=r,n=o,i},i.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?bo(yo.call(t)):bo(t),i):e},i.smooth=function(t){return arguments.length?(r=t?u:Mo,i):r===u},i}function Ao(t,n,e){for(var r=t.width,i=t.height,o=1+(e<<1),a=0;a<i;++a)for(var u=0,c=0;u<r+e;++u)u<r&&(c+=t.data[u+a*r]),u>=e&&(u>=o&&(c-=t.data[u-o+a*r]),n.data[u-e+a*r]=c/Math.min(u+1,r-1+o-u,o))}function So(t,n,e){for(var r=t.width,i=t.height,o=1+(e<<1),a=0;a<r;++a)for(var u=0,c=0;u<i+e;++u)u<i&&(c+=t.data[a+u*r]),u>=e&&(u>=o&&(c-=t.data[a+(u-o)*r]),n.data[a+(u-e)*r]=c/Math.min(u+1,i-1+o-u,o))}function ko(t){return t[0]}function Eo(t){return t[1]}function Co(){return 1}var Po={},zo={},Ro=34,Do=10,qo=13;function Lo(t){return new Function("d","return {"+t.map(function(t,n){return JSON.stringify(t)+": d["+n+'] || ""'}).join(",")+"}")}function Uo(t){var n=Object.create(null),e=[];return t.forEach(function(t){for(var r in t)r in n||e.push(n[r]=r)}),e}function Oo(t,n){var e=t+"",r=e.length;return r<n?new Array(n-r+1).join(0)+e:e}function Bo(t){var n=t.getUTCHours(),e=t.getUTCMinutes(),r=t.getUTCSeconds(),i=t.getUTCMilliseconds();return isNaN(t)?"Invalid Date":function(t){return t<0?"-"+Oo(-t,6):t>9999?"+"+Oo(t,6):Oo(t,4)}(t.getUTCFullYear())+"-"+Oo(t.getUTCMonth()+1,2)+"-"+Oo(t.getUTCDate(),2)+(i?"T"+Oo(n,2)+":"+Oo(e,2)+":"+Oo(r,2)+"."+Oo(i,3)+"Z":r?"T"+Oo(n,2)+":"+Oo(e,2)+":"+Oo(r,2)+"Z":e||n?"T"+Oo(n,2)+":"+Oo(e,2)+"Z":"")}function Fo(t){var n=new RegExp('["'+t+"\n\r]"),e=t.charCodeAt(0);function r(t,n){var r,i=[],o=t.length,a=0,u=0,c=o<=0,f=!1;function s(){if(c)return zo;if(f)return f=!1,Po;var n,r,i=a;if(t.charCodeAt(i)===Ro){for(;a++<o&&t.charCodeAt(a)!==Ro||t.charCodeAt(++a)===Ro;);return(n=a)>=o?c=!0:(r=t.charCodeAt(a++))===Do?f=!0:r===qo&&(f=!0,t.charCodeAt(a)===Do&&++a),t.slice(i+1,n-1).replace(/""/g,'"')}for(;a<o;){if((r=t.charCodeAt(n=a++))===Do)f=!0;else if(r===qo)f=!0,t.charCodeAt(a)===Do&&++a;else if(r!==e)continue;return t.slice(i,n)}return c=!0,t.slice(i,o)}for(t.charCodeAt(o-1)===Do&&--o,t.charCodeAt(o-1)===qo&&--o;(r=s())!==zo;){for(var l=[];r!==Po&&r!==zo;)l.push(r),r=s();n&&null==(l=n(l,u++))||i.push(l)}return i}function i(n,e){return n.map(function(n){return e.map(function(t){return a(n[t])}).join(t)})}function o(n){return n.map(a).join(t)}function a(t){return null==t?"":t instanceof Date?Bo(t):n.test(t+="")?'"'+t.replace(/"/g,'""')+'"':t}return{parse:function(t,n){var e,i,o=r(t,function(t,r){if(e)return e(t,r-1);i=t,e=n?function(t,n){var e=Lo(t);return function(r,i){return n(e(r),i,t)}}(t,n):Lo(t)});return o.columns=i||[],o},parseRows:r,format:function(n,e){return null==e&&(e=Uo(n)),[e.map(a).join(t)].concat(i(n,e)).join("\n")},formatBody:function(t,n){return null==n&&(n=Uo(t)),i(t,n).join("\n")},formatRows:function(t){return t.map(o).join("\n")},formatRow:o,formatValue:a}}var Yo=Fo(","),Io=Yo.parse,Ho=Yo.parseRows,jo=Yo.format,Xo=Yo.formatBody,Vo=Yo.formatRows,Go=Yo.formatRow,$o=Yo.formatValue,Wo=Fo("\t"),Zo=Wo.parse,Qo=Wo.parseRows,Ko=Wo.format,Jo=Wo.formatBody,ta=Wo.formatRows,na=Wo.formatRow,ea=Wo.formatValue;var ra=new Date("2019-01-01T00:00").getHours()||new Date("2019-07-01T00:00").getHours();function ia(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.blob()}function oa(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.arrayBuffer()}function aa(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.text()}function ua(t,n){return fetch(t,n).then(aa)}function ca(t){return function(n,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=void 0),ua(n,e).then(function(n){return t(n,r)})}}var fa=ca(Io),sa=ca(Zo);function la(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.json()}function ha(t){return function(n,e){return ua(n,e).then(function(n){return(new DOMParser).parseFromString(n,t)})}}var da=ha("application/xml"),pa=ha("text/html"),va=ha("image/svg+xml");function ga(t){return function(){return t}}function ya(){return 1e-6*(Math.random()-.5)}function _a(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,a,u,c,f,s,l,h,d=t._root,p={data:r},v=t._x0,g=t._y0,y=t._x1,_=t._y1;if(!d)return t._root=p,t;for(;d.length;)if((f=n>=(o=(v+y)/2))?v=o:y=o,(s=e>=(a=(g+_)/2))?g=a:_=a,i=d,!(d=d[l=s<<1|f]))return i[l]=p,t;if(u=+t._x.call(null,d.data),c=+t._y.call(null,d.data),n===u&&e===c)return p.next=d,i?i[l]=p:t._root=p,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(f=n>=(o=(v+y)/2))?v=o:y=o,(s=e>=(a=(g+_)/2))?g=a:_=a}while((l=s<<1|f)==(h=(c>=a)<<1|u>=o));return i[h]=d,i[l]=p,t}function ba(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i}function ma(t){return t[0]}function xa(t){return t[1]}function wa(t,n,e){var r=new Ma(null==n?ma:n,null==e?xa:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Ma(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function Na(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var Ta=wa.prototype=Ma.prototype;function Aa(t){return t.x+t.vx}function Sa(t){return t.y+t.vy}function ka(t){return t.index}function Ea(t,n){var e=t.get(n);if(!e)throw new Error("missing: "+n);return e}function Ca(t){return t.x}function Pa(t){return t.y}Ta.copy=function(){var t,n,e=new Ma(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=Na(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=Na(n));return e},Ta.add=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return _a(this.cover(n,e),n,e,t)},Ta.addAll=function(t){var n,e,r,i,o=t.length,a=new Array(o),u=new Array(o),c=1/0,f=1/0,s=-1/0,l=-1/0;for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(a[e]=r,u[e]=i,r<c&&(c=r),r>s&&(s=r),i<f&&(f=i),i>l&&(l=i));if(c>s||f>l)return this;for(this.cover(c,f).cover(s,l),e=0;e<o;++e)_a(this,a[e],u[e],t[e]);return this},Ta.cover=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{for(var a,u,c=i-e,f=this._root;e>t||t>=i||r>n||n>=o;)switch(u=(n<r)<<1|t<e,(a=new Array(4))[u]=f,f=a,c*=2,u){case 0:i=e+c,o=r+c;break;case 1:e=i-c,o=r+c;break;case 2:i=e+c,r=o-c;break;case 3:e=i-c,r=o-c}this._root&&this._root.length&&(this._root=f)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},Ta.data=function(){var t=[];return this.visit(function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)}),t},Ta.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},Ta.find=function(t,n,e){var r,i,o,a,u,c,f,s=this._x0,l=this._y0,h=this._x1,d=this._y1,p=[],v=this._root;for(v&&p.push(new ba(v,s,l,h,d)),null==e?e=1/0:(s=t-e,l=n-e,h=t+e,d=n+e,e*=e);c=p.pop();)if(!(!(v=c.node)||(i=c.x0)>h||(o=c.y0)>d||(a=c.x1)<s||(u=c.y1)<l))if(v.length){var g=(i+a)/2,y=(o+u)/2;p.push(new ba(v[3],g,y,a,u),new ba(v[2],i,y,g,u),new ba(v[1],g,o,a,y),new ba(v[0],i,o,g,y)),(f=(n>=y)<<1|t>=g)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-f],p[p.length-1-f]=c)}else{var _=t-+this._x.call(null,v.data),b=n-+this._y.call(null,v.data),m=_*_+b*b;if(m<e){var x=Math.sqrt(e=m);s=t-x,l=n-x,h=t+x,d=n+x,r=v.data}}return r},Ta.remove=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(a=+this._y.call(null,t)))return this;var n,e,r,i,o,a,u,c,f,s,l,h,d=this._root,p=this._x0,v=this._y0,g=this._x1,y=this._y1;if(!d)return this;if(d.length)for(;;){if((f=o>=(u=(p+g)/2))?p=u:g=u,(s=a>=(c=(v+y)/2))?v=c:y=c,n=d,!(d=d[l=s<<1|f]))return this;if(!d.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[h]=d:this._root=d),this):(this._root=i,this)},Ta.removeAll=function(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this},Ta.root=function(){return this._root},Ta.size=function(){var t=0;return this.visit(function(n){if(!n.length)do{++t}while(n=n.next)}),t},Ta.visit=function(t){var n,e,r,i,o,a,u=[],c=this._root;for(c&&u.push(new ba(c,this._x0,this._y0,this._x1,this._y1));n=u.pop();)if(!t(c=n.node,r=n.x0,i=n.y0,o=n.x1,a=n.y1)&&c.length){var f=(r+o)/2,s=(i+a)/2;(e=c[3])&&u.push(new ba(e,f,s,o,a)),(e=c[2])&&u.push(new ba(e,r,s,f,a)),(e=c[1])&&u.push(new ba(e,f,i,o,s)),(e=c[0])&&u.push(new ba(e,r,i,f,s))}return this},Ta.visitAfter=function(t){var n,e=[],r=[];for(this._root&&e.push(new ba(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,a=n.x0,u=n.y0,c=n.x1,f=n.y1,s=(a+c)/2,l=(u+f)/2;(o=i[0])&&e.push(new ba(o,a,u,s,l)),(o=i[1])&&e.push(new ba(o,s,u,c,l)),(o=i[2])&&e.push(new ba(o,a,l,s,f)),(o=i[3])&&e.push(new ba(o,s,l,c,f))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},Ta.x=function(t){return arguments.length?(this._x=t,this):this._x},Ta.y=function(t){return arguments.length?(this._y=t,this):this._y};var za=10,Ra=Math.PI*(3-Math.sqrt(5));function Da(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]}function qa(t){return(t=Da(Math.abs(t)))?t[1]:NaN}var La,Ua=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function Oa(t){if(!(n=Ua.exec(t)))throw new Error("invalid format: "+t);var n;return new Ba({fill:n[1],align:n[2],sign:n[3],symbol:n[4],zero:n[5],width:n[6],comma:n[7],precision:n[8]&&n[8].slice(1),trim:n[9],type:n[10]})}function Ba(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function Fa(t,n){var e=Da(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}Oa.prototype=Ba.prototype,Ba.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var Ya={"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return Fa(100*t,n)},r:Fa,s:function(t,n){var e=Da(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(La=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,a=r.length;return o===a?r:o>a?r+new Array(o-a+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+Da(t,Math.max(0,n+o-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}};function Ia(t){return t}var Ha,ja=Array.prototype.map,Xa=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function Va(t){var n,e,r=void 0===t.grouping||void 0===t.thousands?Ia:(n=ja.call(t.grouping,Number),e=t.thousands+"",function(t,r){for(var i=t.length,o=[],a=0,u=n[0],c=0;i>0&&u>0&&(c+u+1>r&&(u=Math.max(1,r-c)),o.push(t.substring(i-=u,i+u)),!((c+=u+1)>r));)u=n[a=(a+1)%n.length];return o.reverse().join(e)}),i=void 0===t.currency?"":t.currency[0]+"",o=void 0===t.currency?"":t.currency[1]+"",a=void 0===t.decimal?".":t.decimal+"",u=void 0===t.numerals?Ia:function(t){return function(n){return n.replace(/[0-9]/g,function(n){return t[+n]})}}(ja.call(t.numerals,String)),c=void 0===t.percent?"%":t.percent+"",f=void 0===t.minus?"-":t.minus+"",s=void 0===t.nan?"NaN":t.nan+"";function l(t){var n=(t=Oa(t)).fill,e=t.align,l=t.sign,h=t.symbol,d=t.zero,p=t.width,v=t.comma,g=t.precision,y=t.trim,_=t.type;"n"===_?(v=!0,_="g"):Ya[_]||(void 0===g&&(g=12),y=!0,_="g"),(d||"0"===n&&"="===e)&&(d=!0,n="0",e="=");var b="$"===h?i:"#"===h&&/[boxX]/.test(_)?"0"+_.toLowerCase():"",m="$"===h?o:/[%p]/.test(_)?c:"",x=Ya[_],w=/[defgprs%]/.test(_);function M(t){var i,o,c,h=b,M=m;if("c"===_)M=x(t)+M,t="";else{var N=(t=+t)<0||1/t<0;if(t=isNaN(t)?s:x(Math.abs(t),g),y&&(t=function(t){t:for(var n,e=t.length,r=1,i=-1;r<e;++r)switch(t[r]){case".":i=n=r;break;case"0":0===i&&(i=r),n=r;break;default:if(!+t[r])break t;i>0&&(i=0)}return i>0?t.slice(0,i)+t.slice(n+1):t}(t)),N&&0==+t&&"+"!==l&&(N=!1),h=(N?"("===l?l:f:"-"===l||"("===l?"":l)+h,M=("s"===_?Xa[8+La/3]:"")+M+(N&&"("===l?")":""),w)for(i=-1,o=t.length;++i<o;)if(48>(c=t.charCodeAt(i))||c>57){M=(46===c?a+t.slice(i+1):t.slice(i))+M,t=t.slice(0,i);break}}v&&!d&&(t=r(t,1/0));var T=h.length+t.length+M.length,A=T<p?new Array(p-T+1).join(n):"";switch(v&&d&&(t=r(A+t,A.length?p-M.length:1/0),A=""),e){case"<":t=h+t+M+A;break;case"=":t=h+A+t+M;break;case"^":t=A.slice(0,T=A.length>>1)+h+t+M+A.slice(T);break;default:t=A+h+t+M}return u(t)}return g=void 0===g?6:/[gprs]/.test(_)?Math.max(1,Math.min(21,g)):Math.max(0,Math.min(20,g)),M.toString=function(){return t+""},M}return{format:l,formatPrefix:function(t,n){var e=l(((t=Oa(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(qa(n)/3))),i=Math.pow(10,-r),o=Xa[8+r/3];return function(t){return e(i*t)+o}}}}function Ga(n){return Ha=Va(n),t.format=Ha.format,t.formatPrefix=Ha.formatPrefix,Ha}function $a(t){return Math.max(0,-qa(Math.abs(t)))}function Wa(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(qa(n)/3)))-qa(Math.abs(t)))}function Za(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,qa(n)-qa(t))+1}function Qa(){return new Ka}function Ka(){this.reset()}Ga({decimal:".",thousands:",",grouping:[3],currency:["$",""],minus:"-"}),Ka.prototype={constructor:Ka,reset:function(){this.s=this.t=0},add:function(t){tu(Ja,t,this.t),tu(this,Ja.s,this.s),this.s?this.t+=Ja.t:this.s=Ja.t},valueOf:function(){return this.s}};var Ja=new Ka;function tu(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}var nu=1e-6,eu=1e-12,ru=Math.PI,iu=ru/2,ou=ru/4,au=2*ru,uu=180/ru,cu=ru/180,fu=Math.abs,su=Math.atan,lu=Math.atan2,hu=Math.cos,du=Math.ceil,pu=Math.exp,vu=Math.log,gu=Math.pow,yu=Math.sin,_u=Math.sign||function(t){return t>0?1:t<0?-1:0},bu=Math.sqrt,mu=Math.tan;function xu(t){return t>1?0:t<-1?ru:Math.acos(t)}function wu(t){return t>1?iu:t<-1?-iu:Math.asin(t)}function Mu(t){return(t=yu(t/2))*t}function Nu(){}function Tu(t,n){t&&Su.hasOwnProperty(t.type)&&Su[t.type](t,n)}var Au={Feature:function(t,n){Tu(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)Tu(e[r].geometry,n)}},Su={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){ku(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)ku(e[r],n,0)},Polygon:function(t,n){Eu(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)Eu(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)Tu(e[r],n)}};function ku(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function Eu(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)ku(t[e],n,1);n.polygonEnd()}function Cu(t,n){t&&Au.hasOwnProperty(t.type)?Au[t.type](t,n):Tu(t,n)}var Pu,zu,Ru,Du,qu,Lu=Qa(),Uu=Qa(),Ou={point:Nu,lineStart:Nu,lineEnd:Nu,polygonStart:function(){Lu.reset(),Ou.lineStart=Bu,Ou.lineEnd=Fu},polygonEnd:function(){var t=+Lu;Uu.add(t<0?au+t:t),this.lineStart=this.lineEnd=this.point=Nu},sphere:function(){Uu.add(au)}};function Bu(){Ou.point=Yu}function Fu(){Iu(Pu,zu)}function Yu(t,n){Ou.point=Iu,Pu=t,zu=n,Ru=t*=cu,Du=hu(n=(n*=cu)/2+ou),qu=yu(n)}function Iu(t,n){var e=(t*=cu)-Ru,r=e>=0?1:-1,i=r*e,o=hu(n=(n*=cu)/2+ou),a=yu(n),u=qu*a,c=Du*o+u*hu(i),f=u*r*yu(i);Lu.add(lu(f,c)),Ru=t,Du=o,qu=a}function Hu(t){return[lu(t[1],t[0]),wu(t[2])]}function ju(t){var n=t[0],e=t[1],r=hu(e);return[r*hu(n),r*yu(n),yu(e)]}function Xu(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function Vu(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function Gu(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function $u(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function Wu(t){var n=bu(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}var Zu,Qu,Ku,Ju,tc,nc,ec,rc,ic,oc,ac,uc,cc,fc,sc,lc,hc,dc,pc,vc,gc,yc,_c,bc,mc,xc,wc=Qa(),Mc={point:Nc,lineStart:Ac,lineEnd:Sc,polygonStart:function(){Mc.point=kc,Mc.lineStart=Ec,Mc.lineEnd=Cc,wc.reset(),Ou.polygonStart()},polygonEnd:function(){Ou.polygonEnd(),Mc.point=Nc,Mc.lineStart=Ac,Mc.lineEnd=Sc,Lu<0?(Zu=-(Ku=180),Qu=-(Ju=90)):wc>nu?Ju=90:wc<-nu&&(Qu=-90),oc[0]=Zu,oc[1]=Ku},sphere:function(){Zu=-(Ku=180),Qu=-(Ju=90)}};function Nc(t,n){ic.push(oc=[Zu=t,Ku=t]),n<Qu&&(Qu=n),n>Ju&&(Ju=n)}function Tc(t,n){var e=ju([t*cu,n*cu]);if(rc){var r=Vu(rc,e),i=Vu([r[1],-r[0],0],r);Wu(i),i=Hu(i);var o,a=t-tc,u=a>0?1:-1,c=i[0]*uu*u,f=fu(a)>180;f^(u*tc<c&&c<u*t)?(o=i[1]*uu)>Ju&&(Ju=o):f^(u*tc<(c=(c+360)%360-180)&&c<u*t)?(o=-i[1]*uu)<Qu&&(Qu=o):(n<Qu&&(Qu=n),n>Ju&&(Ju=n)),f?t<tc?Pc(Zu,t)>Pc(Zu,Ku)&&(Ku=t):Pc(t,Ku)>Pc(Zu,Ku)&&(Zu=t):Ku>=Zu?(t<Zu&&(Zu=t),t>Ku&&(Ku=t)):t>tc?Pc(Zu,t)>Pc(Zu,Ku)&&(Ku=t):Pc(t,Ku)>Pc(Zu,Ku)&&(Zu=t)}else ic.push(oc=[Zu=t,Ku=t]);n<Qu&&(Qu=n),n>Ju&&(Ju=n),rc=e,tc=t}function Ac(){Mc.point=Tc}function Sc(){oc[0]=Zu,oc[1]=Ku,Mc.point=Nc,rc=null}function kc(t,n){if(rc){var e=t-tc;wc.add(fu(e)>180?e+(e>0?360:-360):e)}else nc=t,ec=n;Ou.point(t,n),Tc(t,n)}function Ec(){Ou.lineStart()}function Cc(){kc(nc,ec),Ou.lineEnd(),fu(wc)>nu&&(Zu=-(Ku=180)),oc[0]=Zu,oc[1]=Ku,rc=null}function Pc(t,n){return(n-=t)<0?n+360:n}function zc(t,n){return t[0]-n[0]}function Rc(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var Dc={sphere:Nu,point:qc,lineStart:Uc,lineEnd:Fc,polygonStart:function(){Dc.lineStart=Yc,Dc.lineEnd=Ic},polygonEnd:function(){Dc.lineStart=Uc,Dc.lineEnd=Fc}};function qc(t,n){t*=cu;var e=hu(n*=cu);Lc(e*hu(t),e*yu(t),yu(n))}function Lc(t,n,e){cc+=(t-cc)/++ac,fc+=(n-fc)/ac,sc+=(e-sc)/ac}function Uc(){Dc.point=Oc}function Oc(t,n){t*=cu;var e=hu(n*=cu);bc=e*hu(t),mc=e*yu(t),xc=yu(n),Dc.point=Bc,Lc(bc,mc,xc)}function Bc(t,n){t*=cu;var e=hu(n*=cu),r=e*hu(t),i=e*yu(t),o=yu(n),a=lu(bu((a=mc*o-xc*i)*a+(a=xc*r-bc*o)*a+(a=bc*i-mc*r)*a),bc*r+mc*i+xc*o);uc+=a,lc+=a*(bc+(bc=r)),hc+=a*(mc+(mc=i)),dc+=a*(xc+(xc=o)),Lc(bc,mc,xc)}function Fc(){Dc.point=qc}function Yc(){Dc.point=Hc}function Ic(){jc(yc,_c),Dc.point=qc}function Hc(t,n){yc=t,_c=n,t*=cu,n*=cu,Dc.point=jc;var e=hu(n);bc=e*hu(t),mc=e*yu(t),xc=yu(n),Lc(bc,mc,xc)}function jc(t,n){t*=cu;var e=hu(n*=cu),r=e*hu(t),i=e*yu(t),o=yu(n),a=mc*o-xc*i,u=xc*r-bc*o,c=bc*i-mc*r,f=bu(a*a+u*u+c*c),s=wu(f),l=f&&-s/f;pc+=l*a,vc+=l*u,gc+=l*c,uc+=s,lc+=s*(bc+(bc=r)),hc+=s*(mc+(mc=i)),dc+=s*(xc+(xc=o)),Lc(bc,mc,xc)}function Xc(t){return function(){return t}}function Vc(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return(e=n.invert(e,r))&&t.invert(e[0],e[1])}),e}function Gc(t,n){return[fu(t)>ru?t+Math.round(-t/au)*au:t,n]}function $c(t,n,e){return(t%=au)?n||e?Vc(Zc(t),Qc(n,e)):Zc(t):n||e?Qc(n,e):Gc}function Wc(t){return function(n,e){return[(n+=t)>ru?n-au:n<-ru?n+au:n,e]}}function Zc(t){var n=Wc(t);return n.invert=Wc(-t),n}function Qc(t,n){var e=hu(t),r=yu(t),i=hu(n),o=yu(n);function a(t,n){var a=hu(n),u=hu(t)*a,c=yu(t)*a,f=yu(n),s=f*e+u*r;return[lu(c*i-s*o,u*e-f*r),wu(s*i+c*o)]}return a.invert=function(t,n){var a=hu(n),u=hu(t)*a,c=yu(t)*a,f=yu(n),s=f*i-c*o;return[lu(c*i+f*o,u*e+s*r),wu(s*e-u*r)]},a}function Kc(t){function n(n){return(n=t(n[0]*cu,n[1]*cu))[0]*=uu,n[1]*=uu,n}return t=$c(t[0]*cu,t[1]*cu,t.length>2?t[2]*cu:0),n.invert=function(n){return(n=t.invert(n[0]*cu,n[1]*cu))[0]*=uu,n[1]*=uu,n},n}function Jc(t,n,e,r,i,o){if(e){var a=hu(n),u=yu(n),c=r*e;null==i?(i=n+r*au,o=n-c/2):(i=tf(a,i),o=tf(a,o),(r>0?i<o:i>o)&&(i+=r*au));for(var f,s=i;r>0?s>o:s<o;s-=c)f=Hu([a,-u*hu(s),-u*yu(s)]),t.point(f[0],f[1])}}function tf(t,n){(n=ju(n))[0]-=t,Wu(n);var e=xu(-n[1]);return((-n[2]<0?-e:e)+au-nu)%au}function nf(){var t,n=[];return{point:function(n,e){t.push([n,e])},lineStart:function(){n.push(t=[])},lineEnd:Nu,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}}function ef(t,n){return fu(t[0]-n[0])<nu&&fu(t[1]-n[1])<nu}function rf(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function of(t,n,e,r,i){var o,a,u=[],c=[];if(t.forEach(function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],a=t[n];if(ef(r,a)){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);i.lineEnd()}else u.push(e=new rf(r,t,null,!0)),c.push(e.o=new rf(r,null,e,!1)),u.push(e=new rf(a,t,null,!1)),c.push(e.o=new rf(a,null,e,!0))}}),u.length){for(c.sort(n),af(u),af(c),o=0,a=c.length;o<a;++o)c[o].e=e=!e;for(var f,s,l=u[0];;){for(var h=l,d=!0;h.v;)if((h=h.n)===l)return;f=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(d)for(o=0,a=f.length;o<a;++o)i.point((s=f[o])[0],s[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(d)for(f=h.p.z,o=f.length-1;o>=0;--o)i.point((s=f[o])[0],s[1]);else r(h.x,h.p.x,-1,i);h=h.p}f=(h=h.o).z,d=!d}while(!h.v);i.lineEnd()}}}function af(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}Gc.invert=Gc;var uf=Qa();function cf(t){return fu(t[0])<=ru?t[0]:_u(t[0])*((fu(t[0])+ru)%au-ru)}function ff(t,n){var e=cf(n),r=n[1],i=yu(r),o=[yu(e),-hu(e),0],a=0,u=0;uf.reset(),1===i?r=iu+nu:-1===i&&(r=-iu-nu);for(var c=0,f=t.length;c<f;++c)if(l=(s=t[c]).length)for(var s,l,h=s[l-1],d=cf(h),p=h[1]/2+ou,v=yu(p),g=hu(p),y=0;y<l;++y,d=b,v=x,g=w,h=_){var _=s[y],b=cf(_),m=_[1]/2+ou,x=yu(m),w=hu(m),M=b-d,N=M>=0?1:-1,T=N*M,A=T>ru,S=v*x;if(uf.add(lu(S*N*yu(T),g*w+S*hu(T))),a+=A?M+N*au:M,A^d>=e^b>=e){var k=Vu(ju(h),ju(_));Wu(k);var E=Vu(o,k);Wu(E);var C=(A^M>=0?-1:1)*wu(E[2]);(r>C||r===C&&(k[0]||k[1]))&&(u+=A^M>=0?1:-1)}}return(a<-nu||a<nu&&uf<-nu)^1&u}function sf(t,n,e,r){return function(i){var o,a,u,c=n(i),f=nf(),s=n(f),l=!1,h={point:d,lineStart:v,lineEnd:g,polygonStart:function(){h.point=y,h.lineStart=_,h.lineEnd=b,a=[],o=[]},polygonEnd:function(){h.point=d,h.lineStart=v,h.lineEnd=g,a=A(a);var t=ff(o,r);a.length?(l||(i.polygonStart(),l=!0),of(a,hf,t,e,i)):t&&(l||(i.polygonStart(),l=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),l&&(i.polygonEnd(),l=!1),a=o=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}};function d(n,e){t(n,e)&&i.point(n,e)}function p(t,n){c.point(t,n)}function v(){h.point=p,c.lineStart()}function g(){h.point=d,c.lineEnd()}function y(t,n){u.push([t,n]),s.point(t,n)}function _(){s.lineStart(),u=[]}function b(){y(u[0][0],u[0][1]),s.lineEnd();var t,n,e,r,c=s.clean(),h=f.result(),d=h.length;if(u.pop(),o.push(u),u=null,d)if(1&c){if((n=(e=h[0]).length-1)>0){for(l||(i.polygonStart(),l=!0),i.lineStart(),t=0;t<n;++t)i.point((r=e[t])[0],r[1]);i.lineEnd()}}else d>1&&2&c&&h.push(h.pop().concat(h.shift())),a.push(h.filter(lf))}return h}}function lf(t){return t.length>1}function hf(t,n){return((t=t.x)[0]<0?t[1]-iu-nu:iu-t[1])-((n=n.x)[0]<0?n[1]-iu-nu:iu-n[1])}var df=sf(function(){return!0},function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,a){var u=o>0?ru:-ru,c=fu(o-e);fu(c-ru)<nu?(t.point(e,r=(r+a)/2>0?iu:-iu),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),t.point(o,r),n=0):i!==u&&c>=ru&&(fu(e-i)<nu&&(e-=i*nu),fu(o-u)<nu&&(o-=u*nu),r=function(t,n,e,r){var i,o,a=yu(t-e);return fu(a)>nu?su((yu(n)*(o=hu(r))*yu(e)-yu(r)*(i=hu(n))*yu(t))/(i*o*a)):(n+r)/2}(e,r,o,a),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),n=0),t.point(e=o,r=a),i=u},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}},function(t,n,e,r){var i;if(null==t)i=e*iu,r.point(-ru,i),r.point(0,i),r.point(ru,i),r.point(ru,0),r.point(ru,-i),r.point(0,-i),r.point(-ru,-i),r.point(-ru,0),r.point(-ru,i);else if(fu(t[0]-n[0])>nu){var o=t[0]<n[0]?ru:-ru;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])},[-ru,-iu]);function pf(t){var n=hu(t),e=6*cu,r=n>0,i=fu(n)>nu;function o(t,e){return hu(t)*hu(e)>n}function a(t,e,r){var i=[1,0,0],o=Vu(ju(t),ju(e)),a=Xu(o,o),u=o[0],c=a-u*u;if(!c)return!r&&t;var f=n*a/c,s=-n*u/c,l=Vu(i,o),h=$u(i,f);Gu(h,$u(o,s));var d=l,p=Xu(h,d),v=Xu(d,d),g=p*p-v*(Xu(h,h)-1);if(!(g<0)){var y=bu(g),_=$u(d,(-p-y)/v);if(Gu(_,h),_=Hu(_),!r)return _;var b,m=t[0],x=e[0],w=t[1],M=e[1];x<m&&(b=m,m=x,x=b);var N=x-m,T=fu(N-ru)<nu;if(!T&&M<w&&(b=w,w=M,M=b),T||N<nu?T?w+M>0^_[1]<(fu(_[0]-m)<nu?w:M):w<=_[1]&&_[1]<=M:N>ru^(m<=_[0]&&_[0]<=x)){var A=$u(d,(-p+y)/v);return Gu(A,h),[_,Hu(A)]}}}function u(n,e){var i=r?t:ru-t,o=0;return n<-i?o|=1:n>i&&(o|=2),e<-i?o|=4:e>i&&(o|=8),o}return sf(o,function(t){var n,e,c,f,s;return{lineStart:function(){f=c=!1,s=1},point:function(l,h){var d,p=[l,h],v=o(l,h),g=r?v?0:u(l,h):v?u(l+(l<0?ru:-ru),h):0;if(!n&&(f=c=v)&&t.lineStart(),v!==c&&(!(d=a(n,p))||ef(n,d)||ef(p,d))&&(p[0]+=nu,p[1]+=nu,v=o(p[0],p[1])),v!==c)s=0,v?(t.lineStart(),d=a(p,n),t.point(d[0],d[1])):(d=a(n,p),t.point(d[0],d[1]),t.lineEnd()),n=d;else if(i&&n&&r^v){var y;g&e||!(y=a(p,n,!0))||(s=0,r?(t.lineStart(),t.point(y[0][0],y[0][1]),t.point(y[1][0],y[1][1]),t.lineEnd()):(t.point(y[1][0],y[1][1]),t.lineEnd(),t.lineStart(),t.point(y[0][0],y[0][1])))}!v||n&&ef(n,p)||t.point(p[0],p[1]),n=p,c=v,e=g},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return s|(f&&c)<<1}}},function(n,r,i,o){Jc(o,t,e,i,n,r)},r?[0,-t]:[-ru,t-ru])}var vf=1e9,gf=-vf;function yf(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,u,f){var s=0,l=0;if(null==i||(s=a(i,u))!==(l=a(o,u))||c(i,o)<0^u>0)do{f.point(0===s||3===s?t:e,s>1?r:n)}while((s=(s+u+4)%4)!==l);else f.point(o[0],o[1])}function a(r,i){return fu(r[0]-t)<nu?i>0?0:3:fu(r[0]-e)<nu?i>0?2:1:fu(r[1]-n)<nu?i>0?1:0:i>0?3:2}function u(t,n){return c(t.x,n.x)}function c(t,n){var e=a(t,1),r=a(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(a){var c,f,s,l,h,d,p,v,g,y,_,b=a,m=nf(),x={point:w,lineStart:function(){x.point=M,f&&f.push(s=[]);y=!0,g=!1,p=v=NaN},lineEnd:function(){c&&(M(l,h),d&&g&&m.rejoin(),c.push(m.result()));x.point=w,g&&b.lineEnd()},polygonStart:function(){b=m,c=[],f=[],_=!0},polygonEnd:function(){var n=function(){for(var n=0,e=0,i=f.length;e<i;++e)for(var o,a,u=f[e],c=1,s=u.length,l=u[0],h=l[0],d=l[1];c<s;++c)o=h,a=d,l=u[c],h=l[0],d=l[1],a<=r?d>r&&(h-o)*(r-a)>(d-a)*(t-o)&&++n:d<=r&&(h-o)*(r-a)<(d-a)*(t-o)&&--n;return n}(),e=_&&n,i=(c=A(c)).length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),o(null,null,1,a),a.lineEnd()),i&&of(c,u,n,o,a),a.polygonEnd());b=a,c=f=s=null}};function w(t,n){i(t,n)&&b.point(t,n)}function M(o,a){var u=i(o,a);if(f&&s.push([o,a]),y)l=o,h=a,d=u,y=!1,u&&(b.lineStart(),b.point(o,a));else if(u&&g)b.point(o,a);else{var c=[p=Math.max(gf,Math.min(vf,p)),v=Math.max(gf,Math.min(vf,v))],m=[o=Math.max(gf,Math.min(vf,o)),a=Math.max(gf,Math.min(vf,a))];!function(t,n,e,r,i,o){var a,u=t[0],c=t[1],f=0,s=1,l=n[0]-u,h=n[1]-c;if(a=e-u,l||!(a>0)){if(a/=l,l<0){if(a<f)return;a<s&&(s=a)}else if(l>0){if(a>s)return;a>f&&(f=a)}if(a=i-u,l||!(a<0)){if(a/=l,l<0){if(a>s)return;a>f&&(f=a)}else if(l>0){if(a<f)return;a<s&&(s=a)}if(a=r-c,h||!(a>0)){if(a/=h,h<0){if(a<f)return;a<s&&(s=a)}else if(h>0){if(a>s)return;a>f&&(f=a)}if(a=o-c,h||!(a<0)){if(a/=h,h<0){if(a>s)return;a>f&&(f=a)}else if(h>0){if(a<f)return;a<s&&(s=a)}return f>0&&(t[0]=u+f*l,t[1]=c+f*h),s<1&&(n[0]=u+s*l,n[1]=c+s*h),!0}}}}}(c,m,t,n,e,r)?u&&(b.lineStart(),b.point(o,a),_=!1):(g||(b.lineStart(),b.point(c[0],c[1])),b.point(m[0],m[1]),u||b.lineEnd(),_=!1)}p=o,v=a,g=u}return x}}var _f,bf,mf,xf=Qa(),wf={sphere:Nu,point:Nu,lineStart:function(){wf.point=Nf,wf.lineEnd=Mf},lineEnd:Nu,polygonStart:Nu,polygonEnd:Nu};function Mf(){wf.point=wf.lineEnd=Nu}function Nf(t,n){_f=t*=cu,bf=yu(n*=cu),mf=hu(n),wf.point=Tf}function Tf(t,n){t*=cu;var e=yu(n*=cu),r=hu(n),i=fu(t-_f),o=hu(i),a=r*yu(i),u=mf*e-bf*r*o,c=bf*e+mf*r*o;xf.add(lu(bu(a*a+u*u),c)),_f=t,bf=e,mf=r}function Af(t){return xf.reset(),Cu(t,wf),+xf}var Sf=[null,null],kf={type:"LineString",coordinates:Sf};function Ef(t,n){return Sf[0]=t,Sf[1]=n,Af(kf)}var Cf={Feature:function(t,n){return zf(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)if(zf(e[r].geometry,n))return!0;return!1}},Pf={Sphere:function(){return!0},Point:function(t,n){return Rf(t.coordinates,n)},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Rf(e[r],n))return!0;return!1},LineString:function(t,n){return Df(t.coordinates,n)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Df(e[r],n))return!0;return!1},Polygon:function(t,n){return qf(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(qf(e[r],n))return!0;return!1},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)if(zf(e[r],n))return!0;return!1}};function zf(t,n){return!(!t||!Pf.hasOwnProperty(t.type))&&Pf[t.type](t,n)}function Rf(t,n){return 0===Ef(t,n)}function Df(t,n){for(var e,r,i,o=0,a=t.length;o<a;o++){if(0===(r=Ef(t[o],n)))return!0;if(o>0&&(i=Ef(t[o],t[o-1]))>0&&e<=i&&r<=i&&(e+r-i)*(1-Math.pow((e-r)/i,2))<eu*i)return!0;e=r}return!1}function qf(t,n){return!!ff(t.map(Lf),Uf(n))}function Lf(t){return(t=t.map(Uf)).pop(),t}function Uf(t){return[t[0]*cu,t[1]*cu]}function Of(t,n,e){var r=g(t,n-nu,e).concat(n);return function(t){return r.map(function(n){return[t,n]})}}function Bf(t,n,e){var r=g(t,n-nu,e).concat(n);return function(t){return r.map(function(n){return[n,t]})}}function Ff(){var t,n,e,r,i,o,a,u,c,f,s,l,h=10,d=h,p=90,v=360,y=2.5;function _(){return{type:"MultiLineString",coordinates:b()}}function b(){return g(du(r/p)*p,e,p).map(s).concat(g(du(u/v)*v,a,v).map(l)).concat(g(du(n/h)*h,t,h).filter(function(t){return fu(t%p)>nu}).map(c)).concat(g(du(o/d)*d,i,d).filter(function(t){return fu(t%v)>nu}).map(f))}return _.lines=function(){return b().map(function(t){return{type:"LineString",coordinates:t}})},_.outline=function(){return{type:"Polygon",coordinates:[s(r).concat(l(a).slice(1),s(e).reverse().slice(1),l(u).reverse().slice(1))]}},_.extent=function(t){return arguments.length?_.extentMajor(t).extentMinor(t):_.extentMinor()},_.extentMajor=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],u=+t[0][1],a=+t[1][1],r>e&&(t=r,r=e,e=t),u>a&&(t=u,u=a,a=t),_.precision(y)):[[r,u],[e,a]]},_.extentMinor=function(e){return arguments.length?(n=+e[0][0],t=+e[1][0],o=+e[0][1],i=+e[1][1],n>t&&(e=n,n=t,t=e),o>i&&(e=o,o=i,i=e),_.precision(y)):[[n,o],[t,i]]},_.step=function(t){return arguments.length?_.stepMajor(t).stepMinor(t):_.stepMinor()},_.stepMajor=function(t){return arguments.length?(p=+t[0],v=+t[1],_):[p,v]},_.stepMinor=function(t){return arguments.length?(h=+t[0],d=+t[1],_):[h,d]},_.precision=function(h){return arguments.length?(y=+h,c=Of(o,i,90),f=Bf(n,t,y),s=Of(u,a,90),l=Bf(r,e,y),_):y},_.extentMajor([[-180,-90+nu],[180,90-nu]]).extentMinor([[-180,-80-nu],[180,80+nu]])}function Yf(t){return t}var If,Hf,jf,Xf,Vf=Qa(),Gf=Qa(),$f={point:Nu,lineStart:Nu,lineEnd:Nu,polygonStart:function(){$f.lineStart=Wf,$f.lineEnd=Kf},polygonEnd:function(){$f.lineStart=$f.lineEnd=$f.point=Nu,Vf.add(fu(Gf)),Gf.reset()},result:function(){var t=Vf/2;return Vf.reset(),t}};function Wf(){$f.point=Zf}function Zf(t,n){$f.point=Qf,If=jf=t,Hf=Xf=n}function Qf(t,n){Gf.add(Xf*t-jf*n),jf=t,Xf=n}function Kf(){Qf(If,Hf)}var Jf=1/0,ts=Jf,ns=-Jf,es=ns,rs={point:function(t,n){t<Jf&&(Jf=t);t>ns&&(ns=t);n<ts&&(ts=n);n>es&&(es=n)},lineStart:Nu,lineEnd:Nu,polygonStart:Nu,polygonEnd:Nu,result:function(){var t=[[Jf,ts],[ns,es]];return ns=es=-(ts=Jf=1/0),t}};var is,os,as,us,cs=0,fs=0,ss=0,ls=0,hs=0,ds=0,ps=0,vs=0,gs=0,ys={point:_s,lineStart:bs,lineEnd:ws,polygonStart:function(){ys.lineStart=Ms,ys.lineEnd=Ns},polygonEnd:function(){ys.point=_s,ys.lineStart=bs,ys.lineEnd=ws},result:function(){var t=gs?[ps/gs,vs/gs]:ds?[ls/ds,hs/ds]:ss?[cs/ss,fs/ss]:[NaN,NaN];return cs=fs=ss=ls=hs=ds=ps=vs=gs=0,t}};function _s(t,n){cs+=t,fs+=n,++ss}function bs(){ys.point=ms}function ms(t,n){ys.point=xs,_s(as=t,us=n)}function xs(t,n){var e=t-as,r=n-us,i=bu(e*e+r*r);ls+=i*(as+t)/2,hs+=i*(us+n)/2,ds+=i,_s(as=t,us=n)}function ws(){ys.point=_s}function Ms(){ys.point=Ts}function Ns(){As(is,os)}function Ts(t,n){ys.point=As,_s(is=as=t,os=us=n)}function As(t,n){var e=t-as,r=n-us,i=bu(e*e+r*r);ls+=i*(as+t)/2,hs+=i*(us+n)/2,ds+=i,ps+=(i=us*t-as*n)*(as+t),vs+=i*(us+n),gs+=3*i,_s(as=t,us=n)}function Ss(t){this._context=t}Ss.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,au)}},result:Nu};var ks,Es,Cs,Ps,zs,Rs=Qa(),Ds={point:Nu,lineStart:function(){Ds.point=qs},lineEnd:function(){ks&&Ls(Es,Cs),Ds.point=Nu},polygonStart:function(){ks=!0},polygonEnd:function(){ks=null},result:function(){var t=+Rs;return Rs.reset(),t}};function qs(t,n){Ds.point=Ls,Es=Ps=t,Cs=zs=n}function Ls(t,n){Ps-=t,zs-=n,Rs.add(bu(Ps*Ps+zs*zs)),Ps=t,zs=n}function Us(){this._string=[]}function Os(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function Bs(t){return function(n){var e=new Fs;for(var r in t)e[r]=t[r];return e.stream=n,e}}function Fs(){}function Ys(t,n,e){var r=t.clipExtent&&t.clipExtent();return t.scale(150).translate([0,0]),null!=r&&t.clipExtent(null),Cu(e,t.stream(rs)),n(rs.result()),null!=r&&t.clipExtent(r),t}function Is(t,n,e){return Ys(t,function(e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=Math.min(r/(e[1][0]-e[0][0]),i/(e[1][1]-e[0][1])),a=+n[0][0]+(r-o*(e[1][0]+e[0][0]))/2,u=+n[0][1]+(i-o*(e[1][1]+e[0][1]))/2;t.scale(150*o).translate([a,u])},e)}function Hs(t,n,e){return Is(t,[[0,0],n],e)}function js(t,n,e){return Ys(t,function(e){var r=+n,i=r/(e[1][0]-e[0][0]),o=(r-i*(e[1][0]+e[0][0]))/2,a=-i*e[0][1];t.scale(150*i).translate([o,a])},e)}function Xs(t,n,e){return Ys(t,function(e){var r=+n,i=r/(e[1][1]-e[0][1]),o=-i*e[0][0],a=(r-i*(e[1][1]+e[0][1]))/2;t.scale(150*i).translate([o,a])},e)}Us.prototype={_radius:4.5,_circle:Os(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push("M",t,",",n),this._point=1;break;case 1:this._string.push("L",t,",",n);break;default:null==this._circle&&(this._circle=Os(this._radius)),this._string.push("M",t,",",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}},Fs.prototype={constructor:Fs,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var Vs=16,Gs=hu(30*cu);function $s(t,n){return+n?function(t,n){function e(r,i,o,a,u,c,f,s,l,h,d,p,v,g){var y=f-r,_=s-i,b=y*y+_*_;if(b>4*n&&v--){var m=a+h,x=u+d,w=c+p,M=bu(m*m+x*x+w*w),N=wu(w/=M),T=fu(fu(w)-1)<nu||fu(o-l)<nu?(o+l)/2:lu(x,m),A=t(T,N),S=A[0],k=A[1],E=S-r,C=k-i,P=_*E-y*C;(P*P/b>n||fu((y*E+_*C)/b-.5)>.3||a*h+u*d+c*p<Gs)&&(e(r,i,o,a,u,c,S,k,T,m/=M,x/=M,w,v,g),g.point(S,k),e(S,k,T,m,x,w,f,s,l,h,d,p,v,g))}}return function(n){var r,i,o,a,u,c,f,s,l,h,d,p,v={point:g,lineStart:y,lineEnd:b,polygonStart:function(){n.polygonStart(),v.lineStart=m},polygonEnd:function(){n.polygonEnd(),v.lineStart=y}};function g(e,r){e=t(e,r),n.point(e[0],e[1])}function y(){s=NaN,v.point=_,n.lineStart()}function _(r,i){var o=ju([r,i]),a=t(r,i);e(s,l,f,h,d,p,s=a[0],l=a[1],f=r,h=o[0],d=o[1],p=o[2],Vs,n),n.point(s,l)}function b(){v.point=g,n.lineEnd()}function m(){y(),v.point=x,v.lineEnd=w}function x(t,n){_(r=t,n),i=s,o=l,a=h,u=d,c=p,v.point=_}function w(){e(s,l,f,h,d,p,i,o,r,a,u,c,Vs,n),v.lineEnd=b,b()}return v}}(t,n):function(t){return Bs({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}(t)}var Ws=Bs({point:function(t,n){this.stream.point(t*cu,n*cu)}});function Zs(t,n,e,r,i,o){var a=hu(o),u=yu(o),c=a*t,f=u*t,s=a/t,l=u/t,h=(u*e-a*n)/t,d=(u*n+a*e)/t;function p(t,o){return[c*(t*=r)-f*(o*=i)+n,e-f*t-c*o]}return p.invert=function(t,n){return[r*(s*t-l*n+h),i*(d-l*t-s*n)]},p}function Qs(t){return Ks(function(){return t})()}function Ks(t){var n,e,r,i,o,a,u,c,f,s,l=150,h=480,d=250,p=0,v=0,g=0,y=0,_=0,b=0,m=1,x=1,w=null,M=df,N=null,T=Yf,A=.5;function S(t){return c(t[0]*cu,t[1]*cu)}function k(t){return(t=c.invert(t[0],t[1]))&&[t[0]*uu,t[1]*uu]}function E(){var t=Zs(l,0,0,m,x,b).apply(null,n(p,v)),r=(b?Zs:function(t,n,e,r,i){function o(o,a){return[n+t*(o*=r),e-t*(a*=i)]}return o.invert=function(o,a){return[(o-n)/t*r,(e-a)/t*i]},o})(l,h-t[0],d-t[1],m,x,b);return e=$c(g,y,_),u=Vc(n,r),c=Vc(e,u),a=$s(u,A),C()}function C(){return f=s=null,S}return S.stream=function(t){return f&&s===t?f:f=Ws(function(t){return Bs({point:function(n,e){var r=t(n,e);return this.stream.point(r[0],r[1])}})}(e)(M(a(T(s=t)))))},S.preclip=function(t){return arguments.length?(M=t,w=void 0,C()):M},S.postclip=function(t){return arguments.length?(T=t,N=r=i=o=null,C()):T},S.clipAngle=function(t){return arguments.length?(M=+t?pf(w=t*cu):(w=null,df),C()):w*uu},S.clipExtent=function(t){return arguments.length?(T=null==t?(N=r=i=o=null,Yf):yf(N=+t[0][0],r=+t[0][1],i=+t[1][0],o=+t[1][1]),C()):null==N?null:[[N,r],[i,o]]},S.scale=function(t){return arguments.length?(l=+t,E()):l},S.translate=function(t){return arguments.length?(h=+t[0],d=+t[1],E()):[h,d]},S.center=function(t){return arguments.length?(p=t[0]%360*cu,v=t[1]%360*cu,E()):[p*uu,v*uu]},S.rotate=function(t){return arguments.length?(g=t[0]%360*cu,y=t[1]%360*cu,_=t.length>2?t[2]%360*cu:0,E()):[g*uu,y*uu,_*uu]},S.angle=function(t){return arguments.length?(b=t%360*cu,E()):b*uu},S.reflectX=function(t){return arguments.length?(m=t?-1:1,E()):m<0},S.reflectY=function(t){return arguments.length?(x=t?-1:1,E()):x<0},S.precision=function(t){return arguments.length?(a=$s(u,A=t*t),C()):bu(A)},S.fitExtent=function(t,n){return Is(S,t,n)},S.fitSize=function(t,n){return Hs(S,t,n)},S.fitWidth=function(t,n){return js(S,t,n)},S.fitHeight=function(t,n){return Xs(S,t,n)},function(){return n=t.apply(this,arguments),S.invert=n.invert&&k,E()}}function Js(t){var n=0,e=ru/3,r=Ks(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*cu,e=t[1]*cu):[n*uu,e*uu]},i}function tl(t,n){var e=yu(t),r=(e+yu(n))/2;if(fu(r)<nu)return function(t){var n=hu(t);function e(t,e){return[t*n,yu(e)/n]}return e.invert=function(t,e){return[t/n,wu(e*n)]},e}(t);var i=1+e*(2*r-e),o=bu(i)/r;function a(t,n){var e=bu(i-2*r*yu(n))/r;return[e*yu(t*=r),o-e*hu(t)]}return a.invert=function(t,n){var e=o-n,a=lu(t,fu(e))*_u(e);return e*r<0&&(a-=ru*_u(t)*_u(e)),[a/r,wu((i-(t*t+e*e)*r*r)/(2*r))]},a}function nl(){return Js(tl).scale(155.424).center([0,33.6442])}function el(){return nl().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])}function rl(t){return function(n,e){var r=hu(n),i=hu(e),o=t(r*i);return[o*i*yu(n),o*yu(e)]}}function il(t){return function(n,e){var r=bu(n*n+e*e),i=t(r),o=yu(i),a=hu(i);return[lu(n*o,r*a),wu(r&&e*o/r)]}}var ol=rl(function(t){return bu(2/(1+t))});ol.invert=il(function(t){return 2*wu(t/2)});var al=rl(function(t){return(t=xu(t))&&t/yu(t)});function ul(t,n){return[t,vu(mu((iu+n)/2))]}function cl(t){var n,e,r,i=Qs(t),o=i.center,a=i.scale,u=i.translate,c=i.clipExtent,f=null;function s(){var o=ru*a(),u=i(Kc(i.rotate()).invert([0,0]));return c(null==f?[[u[0]-o,u[1]-o],[u[0]+o,u[1]+o]]:t===ul?[[Math.max(u[0]-o,f),n],[Math.min(u[0]+o,e),r]]:[[f,Math.max(u[1]-o,n)],[e,Math.min(u[1]+o,r)]])}return i.scale=function(t){return arguments.length?(a(t),s()):a()},i.translate=function(t){return arguments.length?(u(t),s()):u()},i.center=function(t){return arguments.length?(o(t),s()):o()},i.clipExtent=function(t){return arguments.length?(null==t?f=n=e=r=null:(f=+t[0][0],n=+t[0][1],e=+t[1][0],r=+t[1][1]),s()):null==f?null:[[f,n],[e,r]]},s()}function fl(t){return mu((iu+t)/2)}function sl(t,n){var e=hu(t),r=t===n?yu(t):vu(e/hu(n))/vu(fl(n)/fl(t)),i=e*gu(fl(t),r)/r;if(!r)return ul;function o(t,n){i>0?n<-iu+nu&&(n=-iu+nu):n>iu-nu&&(n=iu-nu);var e=i/gu(fl(n),r);return[e*yu(r*t),i-e*hu(r*t)]}return o.invert=function(t,n){var e=i-n,o=_u(r)*bu(t*t+e*e),a=lu(t,fu(e))*_u(e);return e*r<0&&(a-=ru*_u(t)*_u(e)),[a/r,2*su(gu(i/o,1/r))-iu]},o}function ll(t,n){return[t,n]}function hl(t,n){var e=hu(t),r=t===n?yu(t):(e-hu(n))/(n-t),i=e/r+t;if(fu(r)<nu)return ll;function o(t,n){var e=i-n,o=r*t;return[e*yu(o),i-e*hu(o)]}return o.invert=function(t,n){var e=i-n,o=lu(t,fu(e))*_u(e);return e*r<0&&(o-=ru*_u(t)*_u(e)),[o/r,i-_u(r)*bu(t*t+e*e)]},o}al.invert=il(function(t){return t}),ul.invert=function(t,n){return[t,2*su(pu(n))-iu]},ll.invert=ll;var dl=1.340264,pl=-.081106,vl=893e-6,gl=.003796,yl=bu(3)/2;function _l(t,n){var e=wu(yl*yu(n)),r=e*e,i=r*r*r;return[t*hu(e)/(yl*(dl+3*pl*r+i*(7*vl+9*gl*r))),e*(dl+pl*r+i*(vl+gl*r))]}function bl(t,n){var e=hu(n),r=hu(t)*e;return[e*yu(t)/r,yu(n)/r]}function ml(t,n){var e=n*n,r=e*e;return[t*(.8707-.131979*e+r*(r*(.003971*e-.001529*r)-.013791)),n*(1.007226+e*(.015085+r*(.028874*e-.044475-.005916*r)))]}function xl(t,n){return[hu(n)*yu(t),yu(n)]}function wl(t,n){var e=hu(n),r=1+hu(t)*e;return[e*yu(t)/r,yu(n)/r]}function Ml(t,n){return[vu(mu((iu+n)/2)),-t]}function Nl(t,n){return t.parent===n.parent?1:2}function Tl(t,n){return t+n.x}function Al(t,n){return Math.max(t,n.y)}function Sl(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function kl(t,n){var e,r,i,o,a,u=new zl(t),c=+t.value&&(u.value=t.value),f=[u];for(null==n&&(n=El);e=f.pop();)if(c&&(e.value=+e.data.value),(i=n(e.data))&&(a=i.length))for(e.children=new Array(a),o=a-1;o>=0;--o)f.push(r=e.children[o]=new zl(i[o])),r.parent=e,r.depth=e.depth+1;return u.eachBefore(Pl)}function El(t){return t.children}function Cl(t){t.data=t.data.data}function Pl(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function zl(t){this.data=t,this.depth=this.height=0,this.parent=null}_l.invert=function(t,n){for(var e,r=n,i=r*r,o=i*i*i,a=0;a<12&&(o=(i=(r-=e=(r*(dl+pl*i+o*(vl+gl*i))-n)/(dl+3*pl*i+o*(7*vl+9*gl*i)))*r)*i*i,!(fu(e)<eu));++a);return[yl*t*(dl+3*pl*i+o*(7*vl+9*gl*i))/hu(r),wu(yu(r)/yl)]},bl.invert=il(su),ml.invert=function(t,n){var e,r=n,i=25;do{var o=r*r,a=o*o;r-=e=(r*(1.007226+o*(.015085+a*(.028874*o-.044475-.005916*a)))-n)/(1.007226+o*(.045255+a*(.259866*o-.311325-.005916*11*a)))}while(fu(e)>nu&&--i>0);return[t/(.8707+(o=r*r)*(o*(o*o*o*(.003971-.001529*o)-.013791)-.131979)),r]},xl.invert=il(wu),wl.invert=il(function(t){return 2*su(t)}),Ml.invert=function(t,n){return[-n,2*su(pu(t))-iu]},zl.prototype=kl.prototype={constructor:zl,count:function(){return this.eachAfter(Sl)},each:function(t){var n,e,r,i,o=this,a=[o];do{for(n=a.reverse(),a=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r<i;++r)a.push(e[r])}while(a.length);return this},eachAfter:function(t){for(var n,e,r,i=this,o=[i],a=[];i=o.pop();)if(a.push(i),n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e]);for(;i=a.pop();)t(i);return this},eachBefore:function(t){for(var n,e,r=this,i=[r];r=i.pop();)if(t(r),n=r.children)for(e=n.length-1;e>=0;--e)i.push(n[e]);return this},sum:function(t){return this.eachAfter(function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e})},sort:function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},path:function(t){for(var n=this,e=function(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;for(t=e.pop(),n=r.pop();t===n;)i=t,t=e.pop(),n=r.pop();return i}(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){var t=[];return this.each(function(n){t.push(n)}),t},leaves:function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},links:function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n},copy:function(){return kl(this).eachBefore(Cl)}};var Rl=Array.prototype.slice;function Dl(t){for(var n,e,r=0,i=(t=function(t){for(var n,e,r=t.length;r;)e=Math.random()*r--|0,n=t[r],t[r]=t[e],t[e]=n;return t}(Rl.call(t))).length,o=[];r<i;)n=t[r],e&&Ul(e,n)?++r:(e=Bl(o=ql(o,n)),r=0);return e}function ql(t,n){var e,r;if(Ol(n,t))return[n];for(e=0;e<t.length;++e)if(Ll(n,t[e])&&Ol(Fl(t[e],n),t))return[t[e],n];for(e=0;e<t.length-1;++e)for(r=e+1;r<t.length;++r)if(Ll(Fl(t[e],t[r]),n)&&Ll(Fl(t[e],n),t[r])&&Ll(Fl(t[r],n),t[e])&&Ol(Yl(t[e],t[r],n),t))return[t[e],t[r],n];throw new Error}function Ll(t,n){var e=t.r-n.r,r=n.x-t.x,i=n.y-t.y;return e<0||e*e<r*r+i*i}function Ul(t,n){var e=t.r-n.r+1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function Ol(t,n){for(var e=0;e<n.length;++e)if(!Ul(t,n[e]))return!1;return!0}function Bl(t){switch(t.length){case 1:return function(t){return{x:t.x,y:t.y,r:t.r}}(t[0]);case 2:return Fl(t[0],t[1]);case 3:return Yl(t[0],t[1],t[2])}}function Fl(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,a=n.y,u=n.r,c=o-e,f=a-r,s=u-i,l=Math.sqrt(c*c+f*f);return{x:(e+o+c/l*s)/2,y:(r+a+f/l*s)/2,r:(l+i+u)/2}}function Yl(t,n,e){var r=t.x,i=t.y,o=t.r,a=n.x,u=n.y,c=n.r,f=e.x,s=e.y,l=e.r,h=r-a,d=r-f,p=i-u,v=i-s,g=c-o,y=l-o,_=r*r+i*i-o*o,b=_-a*a-u*u+c*c,m=_-f*f-s*s+l*l,x=d*p-h*v,w=(p*m-v*b)/(2*x)-r,M=(v*g-p*y)/x,N=(d*b-h*m)/(2*x)-i,T=(h*y-d*g)/x,A=M*M+T*T-1,S=2*(o+w*M+N*T),k=w*w+N*N-o*o,E=-(A?(S+Math.sqrt(S*S-4*A*k))/(2*A):k/S);return{x:r+w+M*E,y:i+N+T*E,r:E}}function Il(t,n,e){var r,i,o,a,u=t.x-n.x,c=t.y-n.y,f=u*u+c*c;f?(i=n.r+e.r,i*=i,a=t.r+e.r,i>(a*=a)?(r=(f+a-i)/(2*f),o=Math.sqrt(Math.max(0,a/f-r*r)),e.x=t.x-r*u-o*c,e.y=t.y-r*c+o*u):(r=(f+i-a)/(2*f),o=Math.sqrt(Math.max(0,i/f-r*r)),e.x=n.x+r*u-o*c,e.y=n.y+r*c+o*u)):(e.x=n.x+e.r,e.y=n.y)}function Hl(t,n){var e=t.r+n.r-1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function jl(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function Xl(t){this._=t,this.next=null,this.previous=null}function Vl(t){if(!(i=t.length))return 0;var n,e,r,i,o,a,u,c,f,s,l;if((n=t[0]).x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;Il(e,n,r=t[2]),n=new Xl(n),e=new Xl(e),r=new Xl(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(u=3;u<i;++u){Il(n._,e._,r=t[u]),r=new Xl(r),c=e.next,f=n.previous,s=e._.r,l=n._.r;do{if(s<=l){if(Hl(c._,r._)){e=c,n.next=e,e.previous=n,--u;continue t}s+=c._.r,c=c.next}else{if(Hl(f._,r._)){(n=f).next=e,e.previous=n,--u;continue t}l+=f._.r,f=f.previous}}while(c!==f.next);for(r.previous=n,r.next=e,n.next=e.previous=e=r,o=jl(n);(r=r.next)!==e;)(a=jl(r))<o&&(n=r,o=a);e=n.next}for(n=[e._],r=e;(r=r.next)!==e;)n.push(r._);for(r=Dl(n),u=0;u<i;++u)(n=t[u]).x-=r.x,n.y-=r.y;return r.r}function Gl(t){return null==t?null:$l(t)}function $l(t){if("function"!=typeof t)throw new Error;return t}function Wl(){return 0}function Zl(t){return function(){return t}}function Ql(t){return Math.sqrt(t.value)}function Kl(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function Jl(t,n){return function(e){if(r=e.children){var r,i,o,a=r.length,u=t(e)*n||0;if(u)for(i=0;i<a;++i)r[i].r+=u;if(o=Vl(r),u)for(i=0;i<a;++i)r[i].r-=u;e.r=o+u}}}function th(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function nh(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)}function eh(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(r-n)/t.value;++u<c;)(o=a[u]).y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*f}var rh="$",ih={depth:-1},oh={};function ah(t){return t.id}function uh(t){return t.parentId}function ch(t,n){return t.parent===n.parent?1:2}function fh(t){var n=t.children;return n?n[0]:t.t}function sh(t){var n=t.children;return n?n[n.length-1]:t.t}function lh(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function hh(t,n,e){return t.a.parent===n.parent?t.a:e}function dh(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function ph(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(i-e)/t.value;++u<c;)(o=a[u]).x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*f}dh.prototype=Object.create(zl.prototype);var vh=(1+Math.sqrt(5))/2;function gh(t,n,e,r,i,o){for(var a,u,c,f,s,l,h,d,p,v,g,y=[],_=n.children,b=0,m=0,x=_.length,w=n.value;b<x;){c=i-e,f=o-r;do{s=_[m++].value}while(!s&&m<x);for(l=h=s,g=s*s*(v=Math.max(f/c,c/f)/(w*t)),p=Math.max(h/g,g/l);m<x;++m){if(s+=u=_[m].value,u<l&&(l=u),u>h&&(h=u),g=s*s*v,(d=Math.max(h/g,g/l))>p){s-=u;break}p=d}y.push(a={value:s,dice:c<f,children:_.slice(b,m)}),a.dice?eh(a,e,r,i,w?r+=f*s/w:o):ph(a,e,r,w?e+=c*s/w:i,o),w-=s,b=m}return y}var yh=function t(n){function e(t,e,r,i,o){gh(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(vh);var _h=function t(n){function e(t,e,r,i,o){if((a=t._squarify)&&a.ratio===n)for(var a,u,c,f,s,l=-1,h=a.length,d=t.value;++l<h;){for(c=(u=a[l]).children,f=u.value=0,s=c.length;f<s;++f)u.value+=c[f].value;u.dice?eh(u,e,r,i,r+=(o-r)*u.value/d):ph(u,e,r,e+=(i-e)*u.value/d,o),d-=u.value}else t._squarify=a=gh(n,t,e,r,i,o),a.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(vh);function bh(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])}function mh(t,n){return t[0]-n[0]||t[1]-n[1]}function xh(t){for(var n=t.length,e=[0,1],r=2,i=2;i<n;++i){for(;r>1&&bh(t[e[r-2]],t[e[r-1]],t[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function wh(){return Math.random()}var Mh=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(wh),Nh=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(wh),Th=function t(n){function e(){var t=Nh.source(n).apply(this,arguments);return function(){return Math.exp(t())}}return e.source=t,e}(wh),Ah=function t(n){function e(t){return function(){for(var e=0,r=0;r<t;++r)e+=n();return e}}return e.source=t,e}(wh),Sh=function t(n){function e(t){var e=Ah.source(n)(t);return function(){return e()/t}}return e.source=t,e}(wh),kh=function t(n){function e(t){return function(){return-Math.log(1-n())/t}}return e.source=t,e}(wh);function Eh(t,n){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(n).domain(t)}return this}function Ch(t,n){switch(arguments.length){case 0:break;case 1:this.interpolator(t);break;default:this.interpolator(n).domain(t)}return this}var Ph=Array.prototype,zh=Ph.map,Rh=Ph.slice,Dh={name:"implicit"};function qh(){var t=co(),n=[],e=[],r=Dh;function i(i){var o=i+"",a=t.get(o);if(!a){if(r!==Dh)return r;t.set(o,a=n.push(i))}return e[(a-1)%e.length]}return i.domain=function(e){if(!arguments.length)return n.slice();n=[],t=co();for(var r,o,a=-1,u=e.length;++a<u;)t.has(o=(r=e[a])+"")||t.set(o,n.push(r));return i},i.range=function(t){return arguments.length?(e=Rh.call(t),i):e.slice()},i.unknown=function(t){return arguments.length?(r=t,i):r},i.copy=function(){return qh(n,e).unknown(r)},Eh.apply(i,arguments),i}function Lh(){var t,n,e=qh().unknown(void 0),r=e.domain,i=e.range,o=[0,1],a=!1,u=0,c=0,f=.5;function s(){var e=r().length,s=o[1]<o[0],l=o[s-0],h=o[1-s];t=(h-l)/Math.max(1,e-u+2*c),a&&(t=Math.floor(t)),l+=(h-l-t*(e-u))*f,n=t*(1-u),a&&(l=Math.round(l),n=Math.round(n));var d=g(e).map(function(n){return l+t*n});return i(s?d.reverse():d)}return delete e.unknown,e.domain=function(t){return arguments.length?(r(t),s()):r()},e.range=function(t){return arguments.length?(o=[+t[0],+t[1]],s()):o.slice()},e.rangeRound=function(t){return o=[+t[0],+t[1]],a=!0,s()},e.bandwidth=function(){return n},e.step=function(){return t},e.round=function(t){return arguments.length?(a=!!t,s()):a},e.padding=function(t){return arguments.length?(u=Math.min(1,c=+t),s()):u},e.paddingInner=function(t){return arguments.length?(u=Math.min(1,t),s()):u},e.paddingOuter=function(t){return arguments.length?(c=+t,s()):c},e.align=function(t){return arguments.length?(f=Math.max(0,Math.min(1,t)),s()):f},e.copy=function(){return Lh(r(),o).round(a).paddingInner(u).paddingOuter(c).align(f)},Eh.apply(s(),arguments)}function Uh(t){return+t}var Oh=[0,1];function Bh(t){return t}function Fh(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:function(t){return function(){return t}}(isNaN(n)?NaN:.5)}function Yh(t){var n,e=t[0],r=t[t.length-1];return e>r&&(n=e,e=r,r=n),function(t){return Math.max(e,Math.min(r,t))}}function Ih(t,n,e){var r=t[0],i=t[1],o=n[0],a=n[1];return i<r?(r=Fh(i,r),o=e(a,o)):(r=Fh(r,i),o=e(o,a)),function(t){return o(r(t))}}function Hh(t,n,e){var r=Math.min(t.length,n.length)-1,o=new Array(r),a=new Array(r),u=-1;for(t[r]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++u<r;)o[u]=Fh(t[u],t[u+1]),a[u]=e(n[u],n[u+1]);return function(n){var e=i(t,n,1,r)-1;return a[e](o[e](n))}}function jh(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp()).unknown(t.unknown())}function Xh(){var t,n,e,r,i,o,a=Oh,u=Oh,c=Te,f=Bh;function s(){return r=Math.min(a.length,u.length)>2?Hh:Ih,i=o=null,l}function l(n){return isNaN(n=+n)?e:(i||(i=r(a.map(t),u,c)))(t(f(n)))}return l.invert=function(e){return f(n((o||(o=r(u,a.map(t),me)))(e)))},l.domain=function(t){return arguments.length?(a=zh.call(t,Uh),f===Bh||(f=Yh(a)),s()):a.slice()},l.range=function(t){return arguments.length?(u=Rh.call(t),s()):u.slice()},l.rangeRound=function(t){return u=Rh.call(t),c=Ae,s()},l.clamp=function(t){return arguments.length?(f=t?Yh(a):Bh,l):f!==Bh},l.interpolate=function(t){return arguments.length?(c=t,s()):c},l.unknown=function(t){return arguments.length?(e=t,l):e},function(e,r){return t=e,n=r,s()}}function Vh(t,n){return Xh()(t,n)}function Gh(n,e,r,i){var o,a=w(n,e,r);switch((i=Oa(null==i?",f":i)).type){case"s":var u=Math.max(Math.abs(n),Math.abs(e));return null!=i.precision||isNaN(o=Wa(a,u))||(i.precision=o),t.formatPrefix(i,u);case"":case"e":case"g":case"p":case"r":null!=i.precision||isNaN(o=Za(a,Math.max(Math.abs(n),Math.abs(e))))||(i.precision=o-("e"===i.type));break;case"f":case"%":null!=i.precision||isNaN(o=$a(a))||(i.precision=o-2*("%"===i.type))}return t.format(i)}function $h(t){var n=t.domain;return t.ticks=function(t){var e=n();return m(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){var r=n();return Gh(r[0],r[r.length-1],null==t?10:t,e)},t.nice=function(e){null==e&&(e=10);var r,i=n(),o=0,a=i.length-1,u=i[o],c=i[a];return c<u&&(r=u,u=c,c=r,r=o,o=a,a=r),(r=x(u,c,e))>0?r=x(u=Math.floor(u/r)*r,c=Math.ceil(c/r)*r,e):r<0&&(r=x(u=Math.ceil(u*r)/r,c=Math.floor(c*r)/r,e)),r>0?(i[o]=Math.floor(u/r)*r,i[a]=Math.ceil(c/r)*r,n(i)):r<0&&(i[o]=Math.ceil(u*r)/r,i[a]=Math.floor(c*r)/r,n(i)),t},t}function Wh(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],a=t[i];return a<o&&(e=r,r=i,i=e,e=o,o=a,a=e),t[r]=n.floor(o),t[i]=n.ceil(a),t}function Zh(t){return Math.log(t)}function Qh(t){return Math.exp(t)}function Kh(t){return-Math.log(-t)}function Jh(t){return-Math.exp(-t)}function td(t){return isFinite(t)?+("1e"+t):t<0?0:t}function nd(t){return function(n){return-t(-n)}}function ed(n){var e,r,i=n(Zh,Qh),o=i.domain,a=10;function u(){return e=function(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),function(n){return Math.log(n)/t})}(a),r=function(t){return 10===t?td:t===Math.E?Math.exp:function(n){return Math.pow(t,n)}}(a),o()[0]<0?(e=nd(e),r=nd(r),n(Kh,Jh)):n(Zh,Qh),i}return i.base=function(t){return arguments.length?(a=+t,u()):a},i.domain=function(t){return arguments.length?(o(t),u()):o()},i.ticks=function(t){var n,i=o(),u=i[0],c=i[i.length-1];(n=c<u)&&(h=u,u=c,c=h);var f,s,l,h=e(u),d=e(c),p=null==t?10:+t,v=[];if(!(a%1)&&d-h<p){if(h=Math.round(h)-1,d=Math.round(d)+1,u>0){for(;h<d;++h)for(s=1,f=r(h);s<a;++s)if(!((l=f*s)<u)){if(l>c)break;v.push(l)}}else for(;h<d;++h)for(s=a-1,f=r(h);s>=1;--s)if(!((l=f*s)<u)){if(l>c)break;v.push(l)}}else v=m(h,d,Math.min(d-h,p)).map(r);return n?v.reverse():v},i.tickFormat=function(n,o){if(null==o&&(o=10===a?".0e":","),"function"!=typeof o&&(o=t.format(o)),n===1/0)return o;null==n&&(n=10);var u=Math.max(1,a*n/i.ticks().length);return function(t){var n=t/r(Math.round(e(t)));return n*a<a-.5&&(n*=a),n<=u?o(t):""}},i.nice=function(){return o(Wh(o(),{floor:function(t){return r(Math.floor(e(t)))},ceil:function(t){return r(Math.ceil(e(t)))}}))},i}function rd(t){return function(n){return Math.sign(n)*Math.log1p(Math.abs(n/t))}}function id(t){return function(n){return Math.sign(n)*Math.expm1(Math.abs(n))*t}}function od(t){var n=1,e=t(rd(n),id(n));return e.constant=function(e){return arguments.length?t(rd(n=+e),id(n)):n},$h(e)}function ad(t){return function(n){return n<0?-Math.pow(-n,t):Math.pow(n,t)}}function ud(t){return t<0?-Math.sqrt(-t):Math.sqrt(t)}function cd(t){return t<0?-t*t:t*t}function fd(t){var n=t(Bh,Bh),e=1;function r(){return 1===e?t(Bh,Bh):.5===e?t(ud,cd):t(ad(e),ad(1/e))}return n.exponent=function(t){return arguments.length?(e=+t,r()):e},$h(n)}function sd(){var t=fd(Xh());return t.copy=function(){return jh(t,sd()).exponent(t.exponent())},Eh.apply(t,arguments),t}var ld=new Date,hd=new Date;function dd(t,n,e,r){function i(n){return t(n=0===arguments.length?new Date:new Date(+n)),n}return i.floor=function(n){return t(n=new Date(+n)),n},i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=function(t,e){return n(t=new Date(+t),null==e?1:Math.floor(e)),t},i.range=function(e,r,o){var a,u=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return u;do{u.push(a=new Date(+e)),n(e,o),t(e)}while(a<e&&e<r);return u},i.filter=function(e){return dd(function(n){if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return ld.setTime(+n),hd.setTime(+r),t(ld),t(hd),Math.floor(e(ld,hd))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}var pd=dd(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});pd.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?dd(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):pd:null};var vd=pd.range,gd=6e4,yd=6048e5,_d=dd(function(t){t.setTime(t-t.getMilliseconds())},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),bd=_d.range,md=dd(function(t){t.setTime(t-t.getMilliseconds()-1e3*t.getSeconds())},function(t,n){t.setTime(+t+n*gd)},function(t,n){return(n-t)/gd},function(t){return t.getMinutes()}),xd=md.range,wd=dd(function(t){t.setTime(t-t.getMilliseconds()-1e3*t.getSeconds()-t.getMinutes()*gd)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()}),Md=wd.range,Nd=dd(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*gd)/864e5},function(t){return t.getDate()-1}),Td=Nd.range;function Ad(t){return dd(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*gd)/yd})}var Sd=Ad(0),kd=Ad(1),Ed=Ad(2),Cd=Ad(3),Pd=Ad(4),zd=Ad(5),Rd=Ad(6),Dd=Sd.range,qd=kd.range,Ld=Ed.range,Ud=Cd.range,Od=Pd.range,Bd=zd.range,Fd=Rd.range,Yd=dd(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),Id=Yd.range,Hd=dd(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()});Hd.every=function(t){return isFinite(t=Math.floor(t))&&t>0?dd(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var jd=Hd.range,Xd=dd(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*gd)},function(t,n){return(n-t)/gd},function(t){return t.getUTCMinutes()}),Vd=Xd.range,Gd=dd(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()}),$d=Gd.range,Wd=dd(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1}),Zd=Wd.range;function Qd(t){return dd(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/yd})}var Kd=Qd(0),Jd=Qd(1),tp=Qd(2),np=Qd(3),ep=Qd(4),rp=Qd(5),ip=Qd(6),op=Kd.range,ap=Jd.range,up=tp.range,cp=np.range,fp=ep.range,sp=rp.range,lp=ip.range,hp=dd(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),dp=hp.range,pp=dd(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()});pp.every=function(t){return isFinite(t=Math.floor(t))&&t>0?dd(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var vp=pp.range;function gp(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function yp(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function _p(t,n,e){return{y:t,m:n,d:e,H:0,M:0,S:0,L:0}}function bp(t){var n=t.dateTime,e=t.date,r=t.time,i=t.periods,o=t.days,a=t.shortDays,u=t.months,c=t.shortMonths,f=Sp(i),s=kp(i),l=Sp(o),h=kp(o),d=Sp(a),p=kp(a),v=Sp(u),g=kp(u),y=Sp(c),_=kp(c),b={a:function(t){return a[t.getDay()]},A:function(t){return o[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return u[t.getMonth()]},c:null,d:Wp,e:Wp,f:tv,H:Zp,I:Qp,j:Kp,L:Jp,m:nv,M:ev,p:function(t){return i[+(t.getHours()>=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:Cv,s:Pv,S:rv,u:iv,U:ov,V:av,w:uv,W:cv,x:null,X:null,y:fv,Y:sv,Z:lv,"%":Ev},m={a:function(t){return a[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return u[t.getUTCMonth()]},c:null,d:hv,e:hv,f:yv,H:dv,I:pv,j:vv,L:gv,m:_v,M:bv,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:Cv,s:Pv,S:mv,u:xv,U:wv,V:Mv,w:Nv,W:Tv,x:null,X:null,y:Av,Y:Sv,Z:kv,"%":Ev},x={a:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=p[r[0].toLowerCase()],e+r[0].length):-1},A:function(t,n,e){var r=l.exec(n.slice(e));return r?(t.w=h[r[0].toLowerCase()],e+r[0].length):-1},b:function(t,n,e){var r=y.exec(n.slice(e));return r?(t.m=_[r[0].toLowerCase()],e+r[0].length):-1},B:function(t,n,e){var r=v.exec(n.slice(e));return r?(t.m=g[r[0].toLowerCase()],e+r[0].length):-1},c:function(t,e,r){return N(t,n,e,r)},d:Bp,e:Bp,f:Xp,H:Yp,I:Yp,j:Fp,L:jp,m:Op,M:Ip,p:function(t,n,e){var r=f.exec(n.slice(e));return r?(t.p=s[r[0].toLowerCase()],e+r[0].length):-1},q:Up,Q:Gp,s:$p,S:Hp,u:Cp,U:Pp,V:zp,w:Ep,W:Rp,x:function(t,n,r){return N(t,e,n,r)},X:function(t,n,e){return N(t,r,n,e)},y:qp,Y:Dp,Z:Lp,"%":Vp};function w(t,n){return function(e){var r,i,o,a=[],u=-1,c=0,f=t.length;for(e instanceof Date||(e=new Date(+e));++u<f;)37===t.charCodeAt(u)&&(a.push(t.slice(c,u)),null!=(i=xp[r=t.charAt(++u)])?r=t.charAt(++u):i="e"===r?" ":"0",(o=n[r])&&(r=o(e,i)),a.push(r),c=u+1);return a.push(t.slice(c,u)),a.join("")}}function M(t,n){return function(e){var r,i,o=_p(1900,void 0,1);if(N(o,t,e+="",0)!=e.length)return null;if("Q"in o)return new Date(o.Q);if("s"in o)return new Date(1e3*o.s+("L"in o?o.L:0));if(!n||"Z"in o||(o.Z=0),"p"in o&&(o.H=o.H%12+12*o.p),void 0===o.m&&(o.m="q"in o?o.q:0),"V"in o){if(o.V<1||o.V>53)return null;"w"in o||(o.w=1),"Z"in o?(i=(r=yp(_p(o.y,0,1))).getUTCDay(),r=i>4||0===i?Jd.ceil(r):Jd(r),r=Wd.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(i=(r=gp(_p(o.y,0,1))).getDay(),r=i>4||0===i?kd.ceil(r):kd(r),r=Nd.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?yp(_p(o.y,0,1)).getUTCDay():gp(_p(o.y,0,1)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,yp(o)):gp(o)}}function N(t,n,e,r){for(var i,o,a=0,u=n.length,c=e.length;a<u;){if(r>=c)return-1;if(37===(i=n.charCodeAt(a++))){if(i=n.charAt(a++),!(o=x[i in xp?n.charAt(a++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}return b.x=w(e,b),b.X=w(r,b),b.c=w(n,b),m.x=w(e,m),m.X=w(r,m),m.c=w(n,m),{format:function(t){var n=w(t+="",b);return n.toString=function(){return t},n},parse:function(t){var n=M(t+="",!1);return n.toString=function(){return t},n},utcFormat:function(t){var n=w(t+="",m);return n.toString=function(){return t},n},utcParse:function(t){var n=M(t+="",!0);return n.toString=function(){return t},n}}}var mp,xp={"-":"",_:" ",0:"0"},wp=/^\s*\d+/,Mp=/^%/,Np=/[\\^$*+?|[\]().{}]/g;function Tp(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function Ap(t){return t.replace(Np,"\\$&")}function Sp(t){return new RegExp("^(?:"+t.map(Ap).join("|")+")","i")}function kp(t){for(var n={},e=-1,r=t.length;++e<r;)n[t[e].toLowerCase()]=e;return n}function Ep(t,n,e){var r=wp.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function Cp(t,n,e){var r=wp.exec(n.slice(e,e+1));return r?(t.u=+r[0],e+r[0].length):-1}function Pp(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.U=+r[0],e+r[0].length):-1}function zp(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.V=+r[0],e+r[0].length):-1}function Rp(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.W=+r[0],e+r[0].length):-1}function Dp(t,n,e){var r=wp.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function qp(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function Lp(t,n,e){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function Up(t,n,e){var r=wp.exec(n.slice(e,e+1));return r?(t.q=3*r[0]-3,e+r[0].length):-1}function Op(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function Bp(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function Fp(t,n,e){var r=wp.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function Yp(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function Ip(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function Hp(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function jp(t,n,e){var r=wp.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function Xp(t,n,e){var r=wp.exec(n.slice(e,e+6));return r?(t.L=Math.floor(r[0]/1e3),e+r[0].length):-1}function Vp(t,n,e){var r=Mp.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function Gp(t,n,e){var r=wp.exec(n.slice(e));return r?(t.Q=+r[0],e+r[0].length):-1}function $p(t,n,e){var r=wp.exec(n.slice(e));return r?(t.s=+r[0],e+r[0].length):-1}function Wp(t,n){return Tp(t.getDate(),n,2)}function Zp(t,n){return Tp(t.getHours(),n,2)}function Qp(t,n){return Tp(t.getHours()%12||12,n,2)}function Kp(t,n){return Tp(1+Nd.count(Hd(t),t),n,3)}function Jp(t,n){return Tp(t.getMilliseconds(),n,3)}function tv(t,n){return Jp(t,n)+"000"}function nv(t,n){return Tp(t.getMonth()+1,n,2)}function ev(t,n){return Tp(t.getMinutes(),n,2)}function rv(t,n){return Tp(t.getSeconds(),n,2)}function iv(t){var n=t.getDay();return 0===n?7:n}function ov(t,n){return Tp(Sd.count(Hd(t)-1,t),n,2)}function av(t,n){var e=t.getDay();return t=e>=4||0===e?Pd(t):Pd.ceil(t),Tp(Pd.count(Hd(t),t)+(4===Hd(t).getDay()),n,2)}function uv(t){return t.getDay()}function cv(t,n){return Tp(kd.count(Hd(t)-1,t),n,2)}function fv(t,n){return Tp(t.getFullYear()%100,n,2)}function sv(t,n){return Tp(t.getFullYear()%1e4,n,4)}function lv(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+Tp(n/60|0,"0",2)+Tp(n%60,"0",2)}function hv(t,n){return Tp(t.getUTCDate(),n,2)}function dv(t,n){return Tp(t.getUTCHours(),n,2)}function pv(t,n){return Tp(t.getUTCHours()%12||12,n,2)}function vv(t,n){return Tp(1+Wd.count(pp(t),t),n,3)}function gv(t,n){return Tp(t.getUTCMilliseconds(),n,3)}function yv(t,n){return gv(t,n)+"000"}function _v(t,n){return Tp(t.getUTCMonth()+1,n,2)}function bv(t,n){return Tp(t.getUTCMinutes(),n,2)}function mv(t,n){return Tp(t.getUTCSeconds(),n,2)}function xv(t){var n=t.getUTCDay();return 0===n?7:n}function wv(t,n){return Tp(Kd.count(pp(t)-1,t),n,2)}function Mv(t,n){var e=t.getUTCDay();return t=e>=4||0===e?ep(t):ep.ceil(t),Tp(ep.count(pp(t),t)+(4===pp(t).getUTCDay()),n,2)}function Nv(t){return t.getUTCDay()}function Tv(t,n){return Tp(Jd.count(pp(t)-1,t),n,2)}function Av(t,n){return Tp(t.getUTCFullYear()%100,n,2)}function Sv(t,n){return Tp(t.getUTCFullYear()%1e4,n,4)}function kv(){return"+0000"}function Ev(){return"%"}function Cv(t){return+t}function Pv(t){return Math.floor(+t/1e3)}function zv(n){return mp=bp(n),t.timeFormat=mp.format,t.timeParse=mp.parse,t.utcFormat=mp.utcFormat,t.utcParse=mp.utcParse,mp}zv({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var Rv=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat("%Y-%m-%dT%H:%M:%S.%LZ");var Dv=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse("%Y-%m-%dT%H:%M:%S.%LZ"),qv=1e3,Lv=60*qv,Uv=60*Lv,Ov=24*Uv,Bv=7*Ov,Fv=30*Ov,Yv=365*Ov;function Iv(t){return new Date(t)}function Hv(t){return t instanceof Date?+t:+new Date(+t)}function jv(t,n,r,i,o,a,u,c,f){var s=Vh(Bh,Bh),l=s.invert,h=s.domain,d=f(".%L"),p=f(":%S"),v=f("%I:%M"),g=f("%I %p"),y=f("%a %d"),_=f("%b %d"),b=f("%B"),m=f("%Y"),x=[[u,1,qv],[u,5,5*qv],[u,15,15*qv],[u,30,30*qv],[a,1,Lv],[a,5,5*Lv],[a,15,15*Lv],[a,30,30*Lv],[o,1,Uv],[o,3,3*Uv],[o,6,6*Uv],[o,12,12*Uv],[i,1,Ov],[i,2,2*Ov],[r,1,Bv],[n,1,Fv],[n,3,3*Fv],[t,1,Yv]];function M(e){return(u(e)<e?d:a(e)<e?p:o(e)<e?v:i(e)<e?g:n(e)<e?r(e)<e?y:_:t(e)<e?b:m)(e)}function N(n,r,i,o){if(null==n&&(n=10),"number"==typeof n){var a=Math.abs(i-r)/n,u=e(function(t){return t[2]}).right(x,a);u===x.length?(o=w(r/Yv,i/Yv,n),n=t):u?(o=(u=x[a/x[u-1][2]<x[u][2]/a?u-1:u])[1],n=u[0]):(o=Math.max(w(r,i,n),1),n=c)}return null==o?n:n.every(o)}return s.invert=function(t){return new Date(l(t))},s.domain=function(t){return arguments.length?h(zh.call(t,Hv)):h().map(Iv)},s.ticks=function(t,n){var e,r=h(),i=r[0],o=r[r.length-1],a=o<i;return a&&(e=i,i=o,o=e),e=(e=N(t,i,o,n))?e.range(i,o+1):[],a?e.reverse():e},s.tickFormat=function(t,n){return null==n?M:f(n)},s.nice=function(t,n){var e=h();return(t=N(t,e[0],e[e.length-1],n))?h(Wh(e,t)):s},s.copy=function(){return jh(s,jv(t,n,r,i,o,a,u,c,f))},s}function Xv(){var t,n,e,r,i,o=0,a=1,u=Bh,c=!1;function f(n){return isNaN(n=+n)?i:u(0===e?.5:(n=(r(n)-t)*e,c?Math.max(0,Math.min(1,n)):n))}return f.domain=function(i){return arguments.length?(t=r(o=+i[0]),n=r(a=+i[1]),e=t===n?0:1/(n-t),f):[o,a]},f.clamp=function(t){return arguments.length?(c=!!t,f):c},f.interpolator=function(t){return arguments.length?(u=t,f):u},f.unknown=function(t){return arguments.length?(i=t,f):i},function(i){return r=i,t=i(o),n=i(a),e=t===n?0:1/(n-t),f}}function Vv(t,n){return n.domain(t.domain()).interpolator(t.interpolator()).clamp(t.clamp()).unknown(t.unknown())}function Gv(){var t=fd(Xv());return t.copy=function(){return Vv(t,Gv()).exponent(t.exponent())},Ch.apply(t,arguments)}function $v(){var t,n,e,r,i,o,a,u=0,c=.5,f=1,s=Bh,l=!1;function h(t){return isNaN(t=+t)?a:(t=.5+((t=+o(t))-n)*(t<n?r:i),s(l?Math.max(0,Math.min(1,t)):t))}return h.domain=function(a){return arguments.length?(t=o(u=+a[0]),n=o(c=+a[1]),e=o(f=+a[2]),r=t===n?0:.5/(n-t),i=n===e?0:.5/(e-n),h):[u,c,f]},h.clamp=function(t){return arguments.length?(l=!!t,h):l},h.interpolator=function(t){return arguments.length?(s=t,h):s},h.unknown=function(t){return arguments.length?(a=t,h):a},function(a){return o=a,t=a(u),n=a(c),e=a(f),r=t===n?0:.5/(n-t),i=n===e?0:.5/(e-n),h}}function Wv(){var t=fd($v());return t.copy=function(){return Vv(t,Wv()).exponent(t.exponent())},Ch.apply(t,arguments)}function Zv(t){for(var n=t.length/6|0,e=new Array(n),r=0;r<n;)e[r]="#"+t.slice(6*r,6*++r);return e}var Qv=Zv("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),Kv=Zv("7fc97fbeaed4fdc086ffff99386cb0f0027fbf5b17666666"),Jv=Zv("1b9e77d95f027570b3e7298a66a61ee6ab02a6761d666666"),tg=Zv("a6cee31f78b4b2df8a33a02cfb9a99e31a1cfdbf6fff7f00cab2d66a3d9affff99b15928"),ng=Zv("fbb4aeb3cde3ccebc5decbe4fed9a6ffffcce5d8bdfddaecf2f2f2"),eg=Zv("b3e2cdfdcdaccbd5e8f4cae4e6f5c9fff2aef1e2cccccccc"),rg=Zv("e41a1c377eb84daf4a984ea3ff7f00ffff33a65628f781bf999999"),ig=Zv("66c2a5fc8d628da0cbe78ac3a6d854ffd92fe5c494b3b3b3"),og=Zv("8dd3c7ffffb3bebadafb807280b1d3fdb462b3de69fccde5d9d9d9bc80bdccebc5ffed6f"),ag=Zv("4e79a7f28e2ce1575976b7b259a14fedc949af7aa1ff9da79c755fbab0ab");function ug(t){return pe(t[t.length-1])}var cg=new Array(3).concat("d8b365f5f5f55ab4ac","a6611adfc27d80cdc1018571","a6611adfc27df5f5f580cdc1018571","8c510ad8b365f6e8c3c7eae55ab4ac01665e","8c510ad8b365f6e8c3f5f5f5c7eae55ab4ac01665e","8c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e","8c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e","5430058c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e003c30","5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30").map(Zv),fg=ug(cg),sg=new Array(3).concat("af8dc3f7f7f77fbf7b","7b3294c2a5cfa6dba0008837","7b3294c2a5cff7f7f7a6dba0008837","762a83af8dc3e7d4e8d9f0d37fbf7b1b7837","762a83af8dc3e7d4e8f7f7f7d9f0d37fbf7b1b7837","762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b7837","762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b7837","40004b762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b783700441b","40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b").map(Zv),lg=ug(sg),hg=new Array(3).concat("e9a3c9f7f7f7a1d76a","d01c8bf1b6dab8e1864dac26","d01c8bf1b6daf7f7f7b8e1864dac26","c51b7de9a3c9fde0efe6f5d0a1d76a4d9221","c51b7de9a3c9fde0eff7f7f7e6f5d0a1d76a4d9221","c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221","c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221","8e0152c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221276419","8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419").map(Zv),dg=ug(hg),pg=new Array(3).concat("998ec3f7f7f7f1a340","5e3c99b2abd2fdb863e66101","5e3c99b2abd2f7f7f7fdb863e66101","542788998ec3d8daebfee0b6f1a340b35806","542788998ec3d8daebf7f7f7fee0b6f1a340b35806","5427888073acb2abd2d8daebfee0b6fdb863e08214b35806","5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b35806","2d004b5427888073acb2abd2d8daebfee0b6fdb863e08214b358067f3b08","2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08").map(Zv),vg=ug(pg),gg=new Array(3).concat("ef8a62f7f7f767a9cf","ca0020f4a58292c5de0571b0","ca0020f4a582f7f7f792c5de0571b0","b2182bef8a62fddbc7d1e5f067a9cf2166ac","b2182bef8a62fddbc7f7f7f7d1e5f067a9cf2166ac","b2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac","b2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac","67001fb2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac053061","67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061").map(Zv),yg=ug(gg),_g=new Array(3).concat("ef8a62ffffff999999","ca0020f4a582bababa404040","ca0020f4a582ffffffbababa404040","b2182bef8a62fddbc7e0e0e09999994d4d4d","b2182bef8a62fddbc7ffffffe0e0e09999994d4d4d","b2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d","b2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d","67001fb2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d1a1a1a","67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a").map(Zv),bg=ug(_g),mg=new Array(3).concat("fc8d59ffffbf91bfdb","d7191cfdae61abd9e92c7bb6","d7191cfdae61ffffbfabd9e92c7bb6","d73027fc8d59fee090e0f3f891bfdb4575b4","d73027fc8d59fee090ffffbfe0f3f891bfdb4575b4","d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4","d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4","a50026d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4313695","a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695").map(Zv),xg=ug(mg),wg=new Array(3).concat("fc8d59ffffbf91cf60","d7191cfdae61a6d96a1a9641","d7191cfdae61ffffbfa6d96a1a9641","d73027fc8d59fee08bd9ef8b91cf601a9850","d73027fc8d59fee08bffffbfd9ef8b91cf601a9850","d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850","d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850","a50026d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850006837","a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837").map(Zv),Mg=ug(wg),Ng=new Array(3).concat("fc8d59ffffbf99d594","d7191cfdae61abdda42b83ba","d7191cfdae61ffffbfabdda42b83ba","d53e4ffc8d59fee08be6f59899d5943288bd","d53e4ffc8d59fee08bffffbfe6f59899d5943288bd","d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd","d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd","9e0142d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd5e4fa2","9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2").map(Zv),Tg=ug(Ng),Ag=new Array(3).concat("e5f5f999d8c92ca25f","edf8fbb2e2e266c2a4238b45","edf8fbb2e2e266c2a42ca25f006d2c","edf8fbccece699d8c966c2a42ca25f006d2c","edf8fbccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b").map(Zv),Sg=ug(Ag),kg=new Array(3).concat("e0ecf49ebcda8856a7","edf8fbb3cde38c96c688419d","edf8fbb3cde38c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b").map(Zv),Eg=ug(kg),Cg=new Array(3).concat("e0f3dba8ddb543a2ca","f0f9e8bae4bc7bccc42b8cbe","f0f9e8bae4bc7bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081").map(Zv),Pg=ug(Cg),zg=new Array(3).concat("fee8c8fdbb84e34a33","fef0d9fdcc8afc8d59d7301f","fef0d9fdcc8afc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000").map(Zv),Rg=ug(zg),Dg=new Array(3).concat("ece2f0a6bddb1c9099","f6eff7bdc9e167a9cf02818a","f6eff7bdc9e167a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636").map(Zv),qg=ug(Dg),Lg=new Array(3).concat("ece7f2a6bddb2b8cbe","f1eef6bdc9e174a9cf0570b0","f1eef6bdc9e174a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858").map(Zv),Ug=ug(Lg),Og=new Array(3).concat("e7e1efc994c7dd1c77","f1eef6d7b5d8df65b0ce1256","f1eef6d7b5d8df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f").map(Zv),Bg=ug(Og),Fg=new Array(3).concat("fde0ddfa9fb5c51b8a","feebe2fbb4b9f768a1ae017e","feebe2fbb4b9f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a").map(Zv),Yg=ug(Fg),Ig=new Array(3).concat("edf8b17fcdbb2c7fb8","ffffcca1dab441b6c4225ea8","ffffcca1dab441b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58").map(Zv),Hg=ug(Ig),jg=new Array(3).concat("f7fcb9addd8e31a354","ffffccc2e69978c679238443","ffffccc2e69978c67931a354006837","ffffccd9f0a3addd8e78c67931a354006837","ffffccd9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529").map(Zv),Xg=ug(jg),Vg=new Array(3).concat("fff7bcfec44fd95f0e","ffffd4fed98efe9929cc4c02","ffffd4fed98efe9929d95f0e993404","ffffd4fee391fec44ffe9929d95f0e993404","ffffd4fee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506").map(Zv),Gg=ug(Vg),$g=new Array(3).concat("ffeda0feb24cf03b20","ffffb2fecc5cfd8d3ce31a1c","ffffb2fecc5cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026").map(Zv),Wg=ug($g),Zg=new Array(3).concat("deebf79ecae13182bd","eff3ffbdd7e76baed62171b5","eff3ffbdd7e76baed63182bd08519c","eff3ffc6dbef9ecae16baed63182bd08519c","eff3ffc6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b").map(Zv),Qg=ug(Zg),Kg=new Array(3).concat("e5f5e0a1d99b31a354","edf8e9bae4b374c476238b45","edf8e9bae4b374c47631a354006d2c","edf8e9c7e9c0a1d99b74c47631a354006d2c","edf8e9c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b").map(Zv),Jg=ug(Kg),ty=new Array(3).concat("f0f0f0bdbdbd636363","f7f7f7cccccc969696525252","f7f7f7cccccc969696636363252525","f7f7f7d9d9d9bdbdbd969696636363252525","f7f7f7d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000").map(Zv),ny=ug(ty),ey=new Array(3).concat("efedf5bcbddc756bb1","f2f0f7cbc9e29e9ac86a51a3","f2f0f7cbc9e29e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d").map(Zv),ry=ug(ey),iy=new Array(3).concat("fee0d2fc9272de2d26","fee5d9fcae91fb6a4acb181d","fee5d9fcae91fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d").map(Zv),oy=ug(iy),ay=new Array(3).concat("fee6cefdae6be6550d","feeddefdbe85fd8d3cd94701","feeddefdbe85fd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704").map(Zv),uy=ug(ay);var cy=Qe(ee(300,.5,0),ee(-240,.5,1)),fy=Qe(ee(-100,.75,.35),ee(80,1.5,.8)),sy=Qe(ee(260,.75,.35),ee(80,1.5,.8)),ly=ee();var hy=_n(),dy=Math.PI/3,py=2*Math.PI/3;function vy(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}var gy=vy(Zv("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),yy=vy(Zv("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),_y=vy(Zv("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),by=vy(Zv("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function my(t){return function(){return t}}var xy=Math.abs,wy=Math.atan2,My=Math.cos,Ny=Math.max,Ty=Math.min,Ay=Math.sin,Sy=Math.sqrt,ky=1e-12,Ey=Math.PI,Cy=Ey/2,Py=2*Ey;function zy(t){return t>=1?Cy:t<=-1?-Cy:Math.asin(t)}function Ry(t){return t.innerRadius}function Dy(t){return t.outerRadius}function qy(t){return t.startAngle}function Ly(t){return t.endAngle}function Uy(t){return t&&t.padAngle}function Oy(t,n,e,r,i,o,a){var u=t-e,c=n-r,f=(a?o:-o)/Sy(u*u+c*c),s=f*c,l=-f*u,h=t+s,d=n+l,p=e+s,v=r+l,g=(h+p)/2,y=(d+v)/2,_=p-h,b=v-d,m=_*_+b*b,x=i-o,w=h*v-p*d,M=(b<0?-1:1)*Sy(Ny(0,x*x*m-w*w)),N=(w*b-_*M)/m,T=(-w*_-b*M)/m,A=(w*b+_*M)/m,S=(-w*_+b*M)/m,k=N-g,E=T-y,C=A-g,P=S-y;return k*k+E*E>C*C+P*P&&(N=A,T=S),{cx:N,cy:T,x01:-s,y01:-l,x11:N*(i/x-1),y11:T*(i/x-1)}}function By(t){this._context=t}function Fy(t){return new By(t)}function Yy(t){return t[0]}function Iy(t){return t[1]}function Hy(){var t=Yy,n=Iy,e=my(!0),r=null,i=Fy,o=null;function a(a){var u,c,f,s=a.length,l=!1;for(null==r&&(o=i(f=no())),u=0;u<=s;++u)!(u<s&&e(c=a[u],u,a))===l&&((l=!l)?o.lineStart():o.lineEnd()),l&&o.point(+t(c,u,a),+n(c,u,a));if(f)return o=null,f+""||null}return a.x=function(n){return arguments.length?(t="function"==typeof n?n:my(+n),a):t},a.y=function(t){return arguments.length?(n="function"==typeof t?t:my(+t),a):n},a.defined=function(t){return arguments.length?(e="function"==typeof t?t:my(!!t),a):e},a.curve=function(t){return arguments.length?(i=t,null!=r&&(o=i(r)),a):i},a.context=function(t){return arguments.length?(null==t?r=o=null:o=i(r=t),a):r},a}function jy(){var t=Yy,n=null,e=my(0),r=Iy,i=my(!0),o=null,a=Fy,u=null;function c(c){var f,s,l,h,d,p=c.length,v=!1,g=new Array(p),y=new Array(p);for(null==o&&(u=a(d=no())),f=0;f<=p;++f){if(!(f<p&&i(h=c[f],f,c))===v)if(v=!v)s=f,u.areaStart(),u.lineStart();else{for(u.lineEnd(),u.lineStart(),l=f-1;l>=s;--l)u.point(g[l],y[l]);u.lineEnd(),u.areaEnd()}v&&(g[f]=+t(h,f,c),y[f]=+e(h,f,c),u.point(n?+n(h,f,c):g[f],r?+r(h,f,c):y[f]))}if(d)return u=null,d+""||null}function f(){return Hy().defined(i).curve(a).context(o)}return c.x=function(e){return arguments.length?(t="function"==typeof e?e:my(+e),n=null,c):t},c.x0=function(n){return arguments.length?(t="function"==typeof n?n:my(+n),c):t},c.x1=function(t){return arguments.length?(n=null==t?null:"function"==typeof t?t:my(+t),c):n},c.y=function(t){return arguments.length?(e="function"==typeof t?t:my(+t),r=null,c):e},c.y0=function(t){return arguments.length?(e="function"==typeof t?t:my(+t),c):e},c.y1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:my(+t),c):r},c.lineX0=c.lineY0=function(){return f().x(t).y(e)},c.lineY1=function(){return f().x(t).y(r)},c.lineX1=function(){return f().x(n).y(e)},c.defined=function(t){return arguments.length?(i="function"==typeof t?t:my(!!t),c):i},c.curve=function(t){return arguments.length?(a=t,null!=o&&(u=a(o)),c):a},c.context=function(t){return arguments.length?(null==t?o=u=null:u=a(o=t),c):o},c}function Xy(t,n){return n<t?-1:n>t?1:n>=t?0:NaN}function Vy(t){return t}By.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var Gy=Wy(Fy);function $y(t){this._curve=t}function Wy(t){function n(n){return new $y(t(n))}return n._curve=t,n}function Zy(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(Wy(t)):n()._curve},t}function Qy(){return Zy(Hy().curve(Gy))}function Ky(){var t=jy().curve(Gy),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return Zy(e())},delete t.lineX0,t.lineEndAngle=function(){return Zy(r())},delete t.lineX1,t.lineInnerRadius=function(){return Zy(i())},delete t.lineY0,t.lineOuterRadius=function(){return Zy(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(Wy(t)):n()._curve},t}function Jy(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]}$y.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var t_=Array.prototype.slice;function n_(t){return t.source}function e_(t){return t.target}function r_(t){var n=n_,e=e_,r=Yy,i=Iy,o=null;function a(){var a,u=t_.call(arguments),c=n.apply(this,u),f=e.apply(this,u);if(o||(o=a=no()),t(o,+r.apply(this,(u[0]=c,u)),+i.apply(this,u),+r.apply(this,(u[0]=f,u)),+i.apply(this,u)),a)return o=null,a+""||null}return a.source=function(t){return arguments.length?(n=t,a):n},a.target=function(t){return arguments.length?(e=t,a):e},a.x=function(t){return arguments.length?(r="function"==typeof t?t:my(+t),a):r},a.y=function(t){return arguments.length?(i="function"==typeof t?t:my(+t),a):i},a.context=function(t){return arguments.length?(o=null==t?null:t,a):o},a}function i_(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n=(n+r)/2,e,n,i,r,i)}function o_(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n,e=(e+i)/2,r,e,r,i)}function a_(t,n,e,r,i){var o=Jy(n,e),a=Jy(n,e=(e+i)/2),u=Jy(r,e),c=Jy(r,i);t.moveTo(o[0],o[1]),t.bezierCurveTo(a[0],a[1],u[0],u[1],c[0],c[1])}var u_={draw:function(t,n){var e=Math.sqrt(n/Ey);t.moveTo(e,0),t.arc(0,0,e,0,Py)}},c_={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},f_=Math.sqrt(1/3),s_=2*f_,l_={draw:function(t,n){var e=Math.sqrt(n/s_),r=e*f_;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},h_=Math.sin(Ey/10)/Math.sin(7*Ey/10),d_=Math.sin(Py/10)*h_,p_=-Math.cos(Py/10)*h_,v_={draw:function(t,n){var e=Math.sqrt(.8908130915292852*n),r=d_*e,i=p_*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var a=Py*o/5,u=Math.cos(a),c=Math.sin(a);t.lineTo(c*e,-u*e),t.lineTo(u*r-c*i,c*r+u*i)}t.closePath()}},g_={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},y_=Math.sqrt(3),__={draw:function(t,n){var e=-Math.sqrt(n/(3*y_));t.moveTo(0,2*e),t.lineTo(-y_*e,-e),t.lineTo(y_*e,-e),t.closePath()}},b_=Math.sqrt(3)/2,m_=1/Math.sqrt(12),x_=3*(m_/2+1),w_={draw:function(t,n){var e=Math.sqrt(n/x_),r=e/2,i=e*m_,o=r,a=e*m_+e,u=-o,c=a;t.moveTo(r,i),t.lineTo(o,a),t.lineTo(u,c),t.lineTo(-.5*r-b_*i,b_*r+-.5*i),t.lineTo(-.5*o-b_*a,b_*o+-.5*a),t.lineTo(-.5*u-b_*c,b_*u+-.5*c),t.lineTo(-.5*r+b_*i,-.5*i-b_*r),t.lineTo(-.5*o+b_*a,-.5*a-b_*o),t.lineTo(-.5*u+b_*c,-.5*c-b_*u),t.closePath()}},M_=[u_,c_,l_,g_,v_,__,w_];function N_(){}function T_(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function A_(t){this._context=t}function S_(t){this._context=t}function k_(t){this._context=t}function E_(t,n){this._basis=new A_(t),this._beta=n}A_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:T_(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:T_(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},S_.prototype={areaStart:N_,areaEnd:N_,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:T_(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},k_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:T_(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},E_.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],a=t[e]-i,u=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*a),this._beta*n[c]+(1-this._beta)*(o+r*u));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var C_=function t(n){function e(t){return 1===n?new A_(t):new E_(t,n)}return e.beta=function(n){return t(+n)},e}(.85);function P_(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function z_(t,n){this._context=t,this._k=(1-n)/6}z_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:P_(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:P_(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var R_=function t(n){function e(t){return new z_(t,n)}return e.tension=function(n){return t(+n)},e}(0);function D_(t,n){this._context=t,this._k=(1-n)/6}D_.prototype={areaStart:N_,areaEnd:N_,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:P_(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var q_=function t(n){function e(t){return new D_(t,n)}return e.tension=function(n){return t(+n)},e}(0);function L_(t,n){this._context=t,this._k=(1-n)/6}L_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:P_(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var U_=function t(n){function e(t){return new L_(t,n)}return e.tension=function(n){return t(+n)},e}(0);function O_(t,n,e){var r=t._x1,i=t._y1,o=t._x2,a=t._y2;if(t._l01_a>ky){var u=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*u-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*u-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>ky){var f=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,s=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*f+t._x1*t._l23_2a-n*t._l12_2a)/s,a=(a*f+t._y1*t._l23_2a-e*t._l12_2a)/s}t._context.bezierCurveTo(r,i,o,a,t._x2,t._y2)}function B_(t,n){this._context=t,this._alpha=n}B_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:O_(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var F_=function t(n){function e(t){return n?new B_(t,n):new z_(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function Y_(t,n){this._context=t,this._alpha=n}Y_.prototype={areaStart:N_,areaEnd:N_,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:O_(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var I_=function t(n){function e(t){return n?new Y_(t,n):new D_(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function H_(t,n){this._context=t,this._alpha=n}H_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:O_(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var j_=function t(n){function e(t){return n?new H_(t,n):new L_(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function X_(t){this._context=t}function V_(t){return t<0?-1:1}function G_(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),a=(e-t._y1)/(i||r<0&&-0),u=(o*i+a*r)/(r+i);return(V_(o)+V_(a))*Math.min(Math.abs(o),Math.abs(a),.5*Math.abs(u))||0}function $_(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function W_(t,n,e){var r=t._x0,i=t._y0,o=t._x1,a=t._y1,u=(o-r)/3;t._context.bezierCurveTo(r+u,i+u*n,o-u,a-u*e,o,a)}function Z_(t){this._context=t}function Q_(t){this._context=new K_(t)}function K_(t){this._context=t}function J_(t){this._context=t}function tb(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),a=new Array(r);for(i[0]=0,o[0]=2,a[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,a[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,a[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,a[n]-=e*a[n-1];for(i[r-1]=a[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(a[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function nb(t,n){this._context=t,this._t=n}function eb(t,n){if((i=t.length)>1)for(var e,r,i,o=1,a=t[n[0]],u=a.length;o<i;++o)for(r=a,a=t[n[o]],e=0;e<u;++e)a[e][1]+=a[e][0]=isNaN(r[e][1])?r[e][0]:r[e][1]}function rb(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e}function ib(t,n){return t[n]}function ob(t){var n=t.map(ab);return rb(t).sort(function(t,e){return n[t]-n[e]})}function ab(t){for(var n,e=-1,r=0,i=t.length,o=-1/0;++e<i;)(n=+t[e][1])>o&&(o=n,r=e);return r}function ub(t){var n=t.map(cb);return rb(t).sort(function(t,e){return n[t]-n[e]})}function cb(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}function fb(t){return function(){return t}}function sb(t){return t[0]}function lb(t){return t[1]}function hb(){this._=null}function db(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function pb(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function vb(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function gb(t){for(;t.L;)t=t.L;return t}function yb(t,n,e,r){var i=[null,null],o=Yb.push(i)-1;return i.left=t,i.right=n,e&&bb(i,t,n,e),r&&bb(i,n,t,r),Bb[t.index].halfedges.push(o),Bb[n.index].halfedges.push(o),i}function _b(t,n,e){var r=[n,e];return r.left=t,r}function bb(t,n,e,r){t[0]||t[1]?t.left===e?t[1]=r:t[0]=r:(t[0]=r,t.left=n,t.right=e)}function mb(t,n,e,r,i){var o,a=t[0],u=t[1],c=a[0],f=a[1],s=0,l=1,h=u[0]-c,d=u[1]-f;if(o=n-c,h||!(o>0)){if(o/=h,h<0){if(o<s)return;o<l&&(l=o)}else if(h>0){if(o>l)return;o>s&&(s=o)}if(o=r-c,h||!(o<0)){if(o/=h,h<0){if(o>l)return;o>s&&(s=o)}else if(h>0){if(o<s)return;o<l&&(l=o)}if(o=e-f,d||!(o>0)){if(o/=d,d<0){if(o<s)return;o<l&&(l=o)}else if(d>0){if(o>l)return;o>s&&(s=o)}if(o=i-f,d||!(o<0)){if(o/=d,d<0){if(o>l)return;o>s&&(s=o)}else if(d>0){if(o<s)return;o<l&&(l=o)}return!(s>0||l<1)||(s>0&&(t[0]=[c+s*h,f+s*d]),l<1&&(t[1]=[c+l*h,f+l*d]),!0)}}}}}function xb(t,n,e,r,i){var o=t[1];if(o)return!0;var a,u,c=t[0],f=t.left,s=t.right,l=f[0],h=f[1],d=s[0],p=s[1],v=(l+d)/2,g=(h+p)/2;if(p===h){if(v<n||v>=r)return;if(l>d){if(c){if(c[1]>=i)return}else c=[v,e];o=[v,i]}else{if(c){if(c[1]<e)return}else c=[v,i];o=[v,e]}}else if(u=g-(a=(l-d)/(p-h))*v,a<-1||a>1)if(l>d){if(c){if(c[1]>=i)return}else c=[(e-u)/a,e];o=[(i-u)/a,i]}else{if(c){if(c[1]<e)return}else c=[(i-u)/a,i];o=[(e-u)/a,e]}else if(h<p){if(c){if(c[0]>=r)return}else c=[n,a*n+u];o=[r,a*r+u]}else{if(c){if(c[0]<n)return}else c=[r,a*r+u];o=[n,a*n+u]}return t[0]=c,t[1]=o,!0}function wb(t,n){var e=t.site,r=n.left,i=n.right;return e===i&&(i=r,r=e),i?Math.atan2(i[1]-r[1],i[0]-r[0]):(e===r?(r=n[1],i=n[0]):(r=n[0],i=n[1]),Math.atan2(r[0]-i[0],i[1]-r[1]))}function Mb(t,n){return n[+(n.left!==t.site)]}function Nb(t,n){return n[+(n.left===t.site)]}X_.prototype={areaStart:N_,areaEnd:N_,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}},Z_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:W_(this,this._t0,$_(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(n=+n,(t=+t)!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,W_(this,$_(this,e=G_(this,t,n)),e);break;default:W_(this,this._t0,e=G_(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(Q_.prototype=Object.create(Z_.prototype)).point=function(t,n){Z_.prototype.point.call(this,n,t)},K_.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},J_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=tb(t),i=tb(n),o=0,a=1;a<e;++o,++a)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[a],n[a]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}},nb.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}},hb.prototype={constructor:hb,insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=gb(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)e===(r=e.U).L?(i=r.R)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(pb(this,e),e=(t=e).U),e.C=!1,r.C=!0,vb(this,r)):(i=r.L)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(vb(this,e),e=(t=e).U),e.C=!1,r.C=!0,pb(this,r)),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,a=t.R;if(e=o?a?gb(a):o:a,i?i.L===t?i.L=e:i.R=e:this._=e,o&&a?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==a?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=a,a.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r)if(t&&t.C)t.C=!1;else{do{if(t===this._)break;if(t===i.L){if((n=i.R).C&&(n.C=!1,i.C=!0,pb(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,vb(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,pb(this,i),t=this._;break}}else if((n=i.L).C&&(n.C=!1,i.C=!0,vb(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,pb(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,vb(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};var Tb,Ab=[];function Sb(){db(this),this.x=this.y=this.arc=this.site=this.cy=null}function kb(t){var n=t.P,e=t.N;if(n&&e){var r=n.site,i=t.site,o=e.site;if(r!==o){var a=i[0],u=i[1],c=r[0]-a,f=r[1]-u,s=o[0]-a,l=o[1]-u,h=2*(c*l-f*s);if(!(h>=-Hb)){var d=c*c+f*f,p=s*s+l*l,v=(l*d-f*p)/h,g=(c*p-s*d)/h,y=Ab.pop()||new Sb;y.arc=t,y.site=i,y.x=v+a,y.y=(y.cy=g+u)+Math.sqrt(v*v+g*g),t.circle=y;for(var _=null,b=Fb._;b;)if(y.y<b.y||y.y===b.y&&y.x<=b.x){if(!b.L){_=b.P;break}b=b.L}else{if(!b.R){_=b;break}b=b.R}Fb.insert(_,y),_||(Tb=y)}}}}function Eb(t){var n=t.circle;n&&(n.P||(Tb=n.N),Fb.remove(n),Ab.push(n),db(n),t.circle=null)}var Cb=[];function Pb(){db(this),this.edge=this.site=this.circle=null}function zb(t){var n=Cb.pop()||new Pb;return n.site=t,n}function Rb(t){Eb(t),Ob.remove(t),Cb.push(t),db(t)}function Db(t){var n=t.circle,e=n.x,r=n.cy,i=[e,r],o=t.P,a=t.N,u=[t];Rb(t);for(var c=o;c.circle&&Math.abs(e-c.circle.x)<Ib&&Math.abs(r-c.circle.cy)<Ib;)o=c.P,u.unshift(c),Rb(c),c=o;u.unshift(c),Eb(c);for(var f=a;f.circle&&Math.abs(e-f.circle.x)<Ib&&Math.abs(r-f.circle.cy)<Ib;)a=f.N,u.push(f),Rb(f),f=a;u.push(f),Eb(f);var s,l=u.length;for(s=1;s<l;++s)f=u[s],c=u[s-1],bb(f.edge,c.site,f.site,i);c=u[0],(f=u[l-1]).edge=yb(c.site,f.site,null,i),kb(c),kb(f)}function qb(t){for(var n,e,r,i,o=t[0],a=t[1],u=Ob._;u;)if((r=Lb(u,a)-o)>Ib)u=u.L;else{if(!((i=o-Ub(u,a))>Ib)){r>-Ib?(n=u.P,e=u):i>-Ib?(n=u,e=u.N):n=e=u;break}if(!u.R){n=u;break}u=u.R}!function(t){Bb[t.index]={site:t,halfedges:[]}}(t);var c=zb(t);if(Ob.insert(n,c),n||e){if(n===e)return Eb(n),e=zb(n.site),Ob.insert(c,e),c.edge=e.edge=yb(n.site,c.site),kb(n),void kb(e);if(e){Eb(n),Eb(e);var f=n.site,s=f[0],l=f[1],h=t[0]-s,d=t[1]-l,p=e.site,v=p[0]-s,g=p[1]-l,y=2*(h*g-d*v),_=h*h+d*d,b=v*v+g*g,m=[(g*_-d*b)/y+s,(h*b-v*_)/y+l];bb(e.edge,f,p,m),c.edge=yb(f,t,null,m),e.edge=yb(t,p,null,m),kb(n),kb(e)}else c.edge=yb(n.site,c.site)}}function Lb(t,n){var e=t.site,r=e[0],i=e[1],o=i-n;if(!o)return r;var a=t.P;if(!a)return-1/0;var u=(e=a.site)[0],c=e[1],f=c-n;if(!f)return u;var s=u-r,l=1/o-1/f,h=s/f;return l?(-h+Math.sqrt(h*h-2*l*(s*s/(-2*f)-c+f/2+i-o/2)))/l+r:(r+u)/2}function Ub(t,n){var e=t.N;if(e)return Lb(e,n);var r=t.site;return r[1]===n?r[0]:1/0}var Ob,Bb,Fb,Yb,Ib=1e-6,Hb=1e-12;function jb(t,n,e){return(t[0]-e[0])*(n[1]-t[1])-(t[0]-n[0])*(e[1]-t[1])}function Xb(t,n){return n[1]-t[1]||n[0]-t[0]}function Vb(t,n){var e,r,i,o=t.sort(Xb).pop();for(Yb=[],Bb=new Array(t.length),Ob=new hb,Fb=new hb;;)if(i=Tb,o&&(!i||o[1]<i.y||o[1]===i.y&&o[0]<i.x))o[0]===e&&o[1]===r||(qb(o),e=o[0],r=o[1]),o=t.pop();else{if(!i)break;Db(i.arc)}if(function(){for(var t,n,e,r,i=0,o=Bb.length;i<o;++i)if((t=Bb[i])&&(r=(n=t.halfedges).length)){var a=new Array(r),u=new Array(r);for(e=0;e<r;++e)a[e]=e,u[e]=wb(t,Yb[n[e]]);for(a.sort(function(t,n){return u[n]-u[t]}),e=0;e<r;++e)u[e]=n[a[e]];for(e=0;e<r;++e)n[e]=u[e]}}(),n){var a=+n[0][0],u=+n[0][1],c=+n[1][0],f=+n[1][1];!function(t,n,e,r){for(var i,o=Yb.length;o--;)xb(i=Yb[o],t,n,e,r)&&mb(i,t,n,e,r)&&(Math.abs(i[0][0]-i[1][0])>Ib||Math.abs(i[0][1]-i[1][1])>Ib)||delete Yb[o]}(a,u,c,f),function(t,n,e,r){var i,o,a,u,c,f,s,l,h,d,p,v,g=Bb.length,y=!0;for(i=0;i<g;++i)if(o=Bb[i]){for(a=o.site,u=(c=o.halfedges).length;u--;)Yb[c[u]]||c.splice(u,1);for(u=0,f=c.length;u<f;)p=(d=Nb(o,Yb[c[u]]))[0],v=d[1],l=(s=Mb(o,Yb[c[++u%f]]))[0],h=s[1],(Math.abs(p-l)>Ib||Math.abs(v-h)>Ib)&&(c.splice(u,0,Yb.push(_b(a,d,Math.abs(p-t)<Ib&&r-v>Ib?[t,Math.abs(l-t)<Ib?h:r]:Math.abs(v-r)<Ib&&e-p>Ib?[Math.abs(h-r)<Ib?l:e,r]:Math.abs(p-e)<Ib&&v-n>Ib?[e,Math.abs(l-e)<Ib?h:n]:Math.abs(v-n)<Ib&&p-t>Ib?[Math.abs(h-n)<Ib?l:t,n]:null))-1),++f);f&&(y=!1)}if(y){var _,b,m,x=1/0;for(i=0,y=null;i<g;++i)(o=Bb[i])&&(m=(_=(a=o.site)[0]-t)*_+(b=a[1]-n)*b)<x&&(x=m,y=o);if(y){var w=[t,n],M=[t,r],N=[e,r],T=[e,n];y.halfedges.push(Yb.push(_b(a=y.site,w,M))-1,Yb.push(_b(a,M,N))-1,Yb.push(_b(a,N,T))-1,Yb.push(_b(a,T,w))-1)}}for(i=0;i<g;++i)(o=Bb[i])&&(o.halfedges.length||delete Bb[i])}(a,u,c,f)}this.edges=Yb,this.cells=Bb,Ob=Fb=Yb=Bb=null}function Gb(t){return function(){return t}}function $b(t,n,e){this.target=t,this.type=n,this.transform=e}function Wb(t,n,e){this.k=t,this.x=n,this.y=e}Vb.prototype={constructor:Vb,polygons:function(){var t=this.edges;return this.cells.map(function(n){var e=n.halfedges.map(function(e){return Mb(n,t[e])});return e.data=n.site.data,e})},triangles:function(){var t=[],n=this.edges;return this.cells.forEach(function(e,r){if(o=(i=e.halfedges).length)for(var i,o,a,u=e.site,c=-1,f=n[i[o-1]],s=f.left===u?f.right:f.left;++c<o;)a=s,s=(f=n[i[c]]).left===u?f.right:f.left,a&&s&&r<a.index&&r<s.index&&jb(u,a,s)<0&&t.push([u.data,a.data,s.data])}),t},links:function(){return this.edges.filter(function(t){return t.right}).map(function(t){return{source:t.left.data,target:t.right.data}})},find:function(t,n,e){for(var r,i,o=this,a=o._found||0,u=o.cells.length;!(i=o.cells[a]);)if(++a>=u)return null;var c=t-i.site[0],f=n-i.site[1],s=c*c+f*f;do{i=o.cells[r=a],a=null,i.halfedges.forEach(function(e){var r=o.edges[e],u=r.left;if(u!==i.site&&u||(u=r.right)){var c=t-u[0],f=n-u[1],l=c*c+f*f;l<s&&(s=l,a=u.index)}})}while(null!==a);return o._found=r,null==e||s<=e*e?i.site:null}},Wb.prototype={constructor:Wb,scale:function(t){return 1===t?this:new Wb(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new Wb(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var Zb=new Wb(1,0,0);function Qb(t){for(;!t.__zoom;)if(!(t=t.parentNode))return Zb;return t.__zoom}function Kb(){t.event.stopImmediatePropagation()}function Jb(){t.event.preventDefault(),t.event.stopImmediatePropagation()}function tm(){return!t.event.ctrlKey&&!t.event.button}function nm(){var t=this;return t instanceof SVGElement?(t=t.ownerSVGElement||t).hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]:[[0,0],[t.clientWidth,t.clientHeight]]}function em(){return this.__zoom||Zb}function rm(){return-t.event.deltaY*(1===t.event.deltaMode?.05:t.event.deltaMode?1:.002)}function im(){return navigator.maxTouchPoints||"ontouchstart"in this}function om(t,n,e){var r=t.invertX(n[0][0])-e[0][0],i=t.invertX(n[1][0])-e[1][0],o=t.invertY(n[0][1])-e[0][1],a=t.invertY(n[1][1])-e[1][1];return t.translate(i>r?(r+i)/2:Math.min(0,r)||Math.max(0,i),a>o?(o+a)/2:Math.min(0,o)||Math.max(0,a))}Qb.prototype=Wb.prototype,t.FormatSpecifier=Ba,t.active=function(t,n){var e,r,i=t.__transition;if(i)for(r in n=null==n?null:n+"",i)if((e=i[r]).state>xr&&e.name===n)return new Ur([[t]],yi,n,+r);return null},t.arc=function(){var t=Ry,n=Dy,e=my(0),r=null,i=qy,o=Ly,a=Uy,u=null;function c(){var c,f,s=+t.apply(this,arguments),l=+n.apply(this,arguments),h=i.apply(this,arguments)-Cy,d=o.apply(this,arguments)-Cy,p=xy(d-h),v=d>h;if(u||(u=c=no()),l<s&&(f=l,l=s,s=f),l>ky)if(p>Py-ky)u.moveTo(l*My(h),l*Ay(h)),u.arc(0,0,l,h,d,!v),s>ky&&(u.moveTo(s*My(d),s*Ay(d)),u.arc(0,0,s,d,h,v));else{var g,y,_=h,b=d,m=h,x=d,w=p,M=p,N=a.apply(this,arguments)/2,T=N>ky&&(r?+r.apply(this,arguments):Sy(s*s+l*l)),A=Ty(xy(l-s)/2,+e.apply(this,arguments)),S=A,k=A;if(T>ky){var E=zy(T/s*Ay(N)),C=zy(T/l*Ay(N));(w-=2*E)>ky?(m+=E*=v?1:-1,x-=E):(w=0,m=x=(h+d)/2),(M-=2*C)>ky?(_+=C*=v?1:-1,b-=C):(M=0,_=b=(h+d)/2)}var P=l*My(_),z=l*Ay(_),R=s*My(x),D=s*Ay(x);if(A>ky){var q,L=l*My(b),U=l*Ay(b),O=s*My(m),B=s*Ay(m);if(p<Ey&&(q=function(t,n,e,r,i,o,a,u){var c=e-t,f=r-n,s=a-i,l=u-o,h=l*c-s*f;if(!(h*h<ky))return[t+(h=(s*(n-o)-l*(t-i))/h)*c,n+h*f]}(P,z,O,B,L,U,R,D))){var F=P-q[0],Y=z-q[1],I=L-q[0],H=U-q[1],j=1/Ay(function(t){return t>1?0:t<-1?Ey:Math.acos(t)}((F*I+Y*H)/(Sy(F*F+Y*Y)*Sy(I*I+H*H)))/2),X=Sy(q[0]*q[0]+q[1]*q[1]);S=Ty(A,(s-X)/(j-1)),k=Ty(A,(l-X)/(j+1))}}M>ky?k>ky?(g=Oy(O,B,P,z,l,k,v),y=Oy(L,U,R,D,l,k,v),u.moveTo(g.cx+g.x01,g.cy+g.y01),k<A?u.arc(g.cx,g.cy,k,wy(g.y01,g.x01),wy(y.y01,y.x01),!v):(u.arc(g.cx,g.cy,k,wy(g.y01,g.x01),wy(g.y11,g.x11),!v),u.arc(0,0,l,wy(g.cy+g.y11,g.cx+g.x11),wy(y.cy+y.y11,y.cx+y.x11),!v),u.arc(y.cx,y.cy,k,wy(y.y11,y.x11),wy(y.y01,y.x01),!v))):(u.moveTo(P,z),u.arc(0,0,l,_,b,!v)):u.moveTo(P,z),s>ky&&w>ky?S>ky?(g=Oy(R,D,L,U,s,-S,v),y=Oy(P,z,O,B,s,-S,v),u.lineTo(g.cx+g.x01,g.cy+g.y01),S<A?u.arc(g.cx,g.cy,S,wy(g.y01,g.x01),wy(y.y01,y.x01),!v):(u.arc(g.cx,g.cy,S,wy(g.y01,g.x01),wy(g.y11,g.x11),!v),u.arc(0,0,s,wy(g.cy+g.y11,g.cx+g.x11),wy(y.cy+y.y11,y.cx+y.x11),v),u.arc(y.cx,y.cy,S,wy(y.y11,y.x11),wy(y.y01,y.x01),!v))):u.arc(0,0,s,x,m,v):u.lineTo(R,D)}else u.moveTo(0,0);if(u.closePath(),c)return u=null,c+""||null}return c.centroid=function(){var e=(+t.apply(this,arguments)+ +n.apply(this,arguments))/2,r=(+i.apply(this,arguments)+ +o.apply(this,arguments))/2-Ey/2;return[My(r)*e,Ay(r)*e]},c.innerRadius=function(n){return arguments.length?(t="function"==typeof n?n:my(+n),c):t},c.outerRadius=function(t){return arguments.length?(n="function"==typeof t?t:my(+t),c):n},c.cornerRadius=function(t){return arguments.length?(e="function"==typeof t?t:my(+t),c):e},c.padRadius=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:my(+t),c):r},c.startAngle=function(t){return arguments.length?(i="function"==typeof t?t:my(+t),c):i},c.endAngle=function(t){return arguments.length?(o="function"==typeof t?t:my(+t),c):o},c.padAngle=function(t){return arguments.length?(a="function"==typeof t?t:my(+t),c):a},c.context=function(t){return arguments.length?(u=null==t?null:t,c):u},c},t.area=jy,t.areaRadial=Ky,t.ascending=n,t.autoType=function(t){for(var n in t){var e,r,i=t[n].trim();if(i)if("true"===i)i=!0;else if("false"===i)i=!1;else if("NaN"===i)i=NaN;else if(isNaN(e=+i)){if(!(r=i.match(/^([-+]\d{2})?\d{4}(-\d{2}(-\d{2})?)?(T\d{2}:\d{2}(:\d{2}(\.\d{3})?)?(Z|[-+]\d{2}:\d{2})?)?$/)))continue;ra&&r[4]&&!r[7]&&(i=i.replace(/-/g,"/").replace(/T/," ")),i=new Date(i)}else i=e;else i=null;t[n]=i}return t},t.axisBottom=function(t){return F(D,t)},t.axisLeft=function(t){return F(q,t)},t.axisRight=function(t){return F(R,t)},t.axisTop=function(t){return F(z,t)},t.bisect=i,t.bisectLeft=o,t.bisectRight=i,t.bisector=e,t.blob=function(t,n){return fetch(t,n).then(ia)},t.brush=function(){return Yi(Ci)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.brushX=function(){return Yi(ki)},t.brushY=function(){return Yi(Ei)},t.buffer=function(t,n){return fetch(t,n).then(oa)},t.chord=function(){var t=0,n=null,e=null,r=null;function i(i){var o,a,u,c,f,s,l=i.length,h=[],d=g(l),p=[],v=[],y=v.groups=new Array(l),_=new Array(l*l);for(o=0,f=-1;++f<l;){for(a=0,s=-1;++s<l;)a+=i[f][s];h.push(a),p.push(g(l)),o+=a}for(n&&d.sort(function(t,e){return n(h[t],h[e])}),e&&p.forEach(function(t,n){t.sort(function(t,r){return e(i[n][t],i[n][r])})}),c=(o=Gi(0,Vi-t*l)/o)?t:Vi/l,a=0,f=-1;++f<l;){for(u=a,s=-1;++s<l;){var b=d[f],m=p[b][s],x=i[b][m],w=a,M=a+=x*o;_[m*l+b]={index:b,subindex:m,startAngle:w,endAngle:M,value:x}}y[b]={index:b,startAngle:u,endAngle:a,value:h[b]},a+=c}for(f=-1;++f<l;)for(s=f-1;++s<l;){var N=_[s*l+f],T=_[f*l+s];(N.value||T.value)&&v.push(N.value<T.value?{source:T,target:N}:{source:N,target:T})}return r?v.sort(r):v}return i.padAngle=function(n){return arguments.length?(t=Gi(0,n),i):t},i.sortGroups=function(t){return arguments.length?(n=t,i):n},i.sortSubgroups=function(t){return arguments.length?(e=t,i):e},i.sortChords=function(t){return arguments.length?(null==t?r=null:(r=$i(t))._=t,i):r&&r._},i},t.clientPoint=Ot,t.cluster=function(){var t=Nl,n=1,e=1,r=!1;function i(i){var o,a=0;i.eachAfter(function(n){var e=n.children;e?(n.x=function(t){return t.reduce(Tl,0)/t.length}(e),n.y=function(t){return 1+t.reduce(Al,0)}(e)):(n.x=o?a+=t(n,o):0,n.y=0,o=n)});var u=function(t){for(var n;n=t.children;)t=n[0];return t}(i),c=function(t){for(var n;n=t.children;)t=n[n.length-1];return t}(i),f=u.x-t(u,c)/2,s=c.x+t(c,u)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*n,t.y=(i.y-t.y)*e}:function(t){t.x=(t.x-f)/(s-f)*n,t.y=(1-(i.y?t.y/i.y:1))*e})}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.color=pn,t.contourDensity=function(){var t=ko,n=Eo,e=Co,r=960,i=500,o=20,a=2,u=3*o,c=r+2*u>>a,f=i+2*u>>a,s=bo(20);function l(r){var i=new Float32Array(c*f),l=new Float32Array(c*f);r.forEach(function(r,o,s){var l=+t(r,o,s)+u>>a,h=+n(r,o,s)+u>>a,d=+e(r,o,s);l>=0&&l<c&&h>=0&&h<f&&(i[l+h*c]+=d)}),Ao({width:c,height:f,data:i},{width:c,height:f,data:l},o>>a),So({width:c,height:f,data:l},{width:c,height:f,data:i},o>>a),Ao({width:c,height:f,data:i},{width:c,height:f,data:l},o>>a),So({width:c,height:f,data:l},{width:c,height:f,data:i},o>>a),Ao({width:c,height:f,data:i},{width:c,height:f,data:l},o>>a),So({width:c,height:f,data:l},{width:c,height:f,data:i},o>>a);var d=s(i);if(!Array.isArray(d)){var p=T(i);d=w(0,p,d),(d=g(0,Math.floor(p/d)*d,d)).shift()}return To().thresholds(d).size([c,f])(i).map(h)}function h(t){return t.value*=Math.pow(2,-2*a),t.coordinates.forEach(d),t}function d(t){t.forEach(p)}function p(t){t.forEach(v)}function v(t){t[0]=t[0]*Math.pow(2,a)-u,t[1]=t[1]*Math.pow(2,a)-u}function y(){return c=r+2*(u=3*o)>>a,f=i+2*u>>a,l}return l.x=function(n){return arguments.length?(t="function"==typeof n?n:bo(+n),l):t},l.y=function(t){return arguments.length?(n="function"==typeof t?t:bo(+t),l):n},l.weight=function(t){return arguments.length?(e="function"==typeof t?t:bo(+t),l):e},l.size=function(t){if(!arguments.length)return[r,i];var n=Math.ceil(t[0]),e=Math.ceil(t[1]);if(!(n>=0||n>=0))throw new Error("invalid size");return r=n,i=e,y()},l.cellSize=function(t){if(!arguments.length)return 1<<a;if(!((t=+t)>=1))throw new Error("invalid cell size");return a=Math.floor(Math.log(t)/Math.LN2),y()},l.thresholds=function(t){return arguments.length?(s="function"==typeof t?t:Array.isArray(t)?bo(yo.call(t)):bo(t),l):s},l.bandwidth=function(t){if(!arguments.length)return Math.sqrt(o*(o+1));if(!((t=+t)>=0))throw new Error("invalid bandwidth");return o=Math.round((Math.sqrt(4*t*t+1)-1)/2),y()},l},t.contours=To,t.create=function(t){return Rt(Z(t).call(document.documentElement))},t.creator=Z,t.cross=function(t,n,e){var r,i,o,u,c=t.length,f=n.length,s=new Array(c*f);for(null==e&&(e=a),r=o=0;r<c;++r)for(u=t[r],i=0;i<f;++i,++o)s[o]=e(u,n[i]);return s},t.csv=fa,t.csvFormat=jo,t.csvFormatBody=Xo,t.csvFormatRow=Go,t.csvFormatRows=Vo,t.csvFormatValue=$o,t.csvParse=Io,t.csvParseRows=Ho,t.cubehelix=ee,t.curveBasis=function(t){return new A_(t)},t.curveBasisClosed=function(t){return new S_(t)},t.curveBasisOpen=function(t){return new k_(t)},t.curveBundle=C_,t.curveCardinal=R_,t.curveCardinalClosed=q_,t.curveCardinalOpen=U_,t.curveCatmullRom=F_,t.curveCatmullRomClosed=I_,t.curveCatmullRomOpen=j_,t.curveLinear=Fy,t.curveLinearClosed=function(t){return new X_(t)},t.curveMonotoneX=function(t){return new Z_(t)},t.curveMonotoneY=function(t){return new Q_(t)},t.curveNatural=function(t){return new J_(t)},t.curveStep=function(t){return new nb(t,.5)},t.curveStepAfter=function(t){return new nb(t,1)},t.curveStepBefore=function(t){return new nb(t,0)},t.customEvent=kt,t.descending=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},t.deviation=f,t.dispatch=I,t.drag=function(){var n,e,r,i,o=Gt,a=$t,u=Wt,c=Zt,f={},s=I("start","drag","end"),l=0,h=0;function d(t){t.on("mousedown.drag",p).filter(c).on("touchstart.drag",y).on("touchmove.drag",_).on("touchend.drag touchcancel.drag",b).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function p(){if(!i&&o.apply(this,arguments)){var u=m("mouse",a.apply(this,arguments),Bt,this,arguments);u&&(Rt(t.event.view).on("mousemove.drag",v,!0).on("mouseup.drag",g,!0),Ht(t.event.view),Yt(),r=!1,n=t.event.clientX,e=t.event.clientY,u("start"))}}function v(){if(It(),!r){var i=t.event.clientX-n,o=t.event.clientY-e;r=i*i+o*o>h}f.mouse("drag")}function g(){Rt(t.event.view).on("mousemove.drag mouseup.drag",null),jt(t.event.view,r),It(),f.mouse("end")}function y(){if(o.apply(this,arguments)){var n,e,r=t.event.changedTouches,i=a.apply(this,arguments),u=r.length;for(n=0;n<u;++n)(e=m(r[n].identifier,i,Ft,this,arguments))&&(Yt(),e("start"))}}function _(){var n,e,r=t.event.changedTouches,i=r.length;for(n=0;n<i;++n)(e=f[r[n].identifier])&&(It(),e("drag"))}function b(){var n,e,r=t.event.changedTouches,o=r.length;for(i&&clearTimeout(i),i=setTimeout(function(){i=null},500),n=0;n<o;++n)(e=f[r[n].identifier])&&(Yt(),e("end"))}function m(n,e,r,i,o){var a,c,h,p=r(e,n),v=s.copy();if(kt(new Vt(d,"beforestart",a,n,l,p[0],p[1],0,0,v),function(){return null!=(t.event.subject=a=u.apply(i,o))&&(c=a.x-p[0]||0,h=a.y-p[1]||0,!0)}))return function t(u){var s,g=p;switch(u){case"start":f[n]=t,s=l++;break;case"end":delete f[n],--l;case"drag":p=r(e,n),s=l}kt(new Vt(d,u,a,n,s,p[0]+c,p[1]+h,p[0]-g[0],p[1]-g[1],v),v.apply,v,[u,i,o])}}return d.filter=function(t){return arguments.length?(o="function"==typeof t?t:Xt(!!t),d):o},d.container=function(t){return arguments.length?(a="function"==typeof t?t:Xt(t),d):a},d.subject=function(t){return arguments.length?(u="function"==typeof t?t:Xt(t),d):u},d.touchable=function(t){return arguments.length?(c="function"==typeof t?t:Xt(!!t),d):c},d.on=function(){var t=s.on.apply(s,arguments);return t===s?d:t},d.clickDistance=function(t){return arguments.length?(h=(t=+t)*t,d):Math.sqrt(h)},d},t.dragDisable=Ht,t.dragEnable=jt,t.dsv=function(t,n,e,r){3===arguments.length&&"function"==typeof e&&(r=e,e=void 0);var i=Fo(t);return ua(n,e).then(function(t){return i.parse(t,r)})},t.dsvFormat=Fo,t.easeBack=si,t.easeBackIn=ci,t.easeBackInOut=si,t.easeBackOut=fi,t.easeBounce=ui,t.easeBounceIn=function(t){return 1-ui(1-t)},t.easeBounceInOut=function(t){return((t*=2)<=1?1-ui(1-t):ui(t-1)+1)/2},t.easeBounceOut=ui,t.easeCircle=Zr,t.easeCircleIn=function(t){return 1-Math.sqrt(1-t*t)},t.easeCircleInOut=Zr,t.easeCircleOut=function(t){return Math.sqrt(1- --t*t)},t.easeCubic=Ir,t.easeCubicIn=function(t){return t*t*t},t.easeCubicInOut=Ir,t.easeCubicOut=function(t){return--t*t*t+1},t.easeElastic=di,t.easeElasticIn=hi,t.easeElasticInOut=pi,t.easeElasticOut=di,t.easeExp=Wr,t.easeExpIn=function(t){return Math.pow(2,10*t-10)},t.easeExpInOut=Wr,t.easeExpOut=function(t){return 1-Math.pow(2,-10*t)},t.easeLinear=function(t){return+t},t.easePoly=Xr,t.easePolyIn=Hr,t.easePolyInOut=Xr,t.easePolyOut=jr,t.easeQuad=Yr,t.easeQuadIn=function(t){return t*t},t.easeQuadInOut=Yr,t.easeQuadOut=function(t){return t*(2-t)},t.easeSin=$r,t.easeSinIn=function(t){return 1-Math.cos(t*Gr)},t.easeSinInOut=$r,t.easeSinOut=function(t){return Math.sin(t*Gr)},t.entries=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},t.extent=s,t.forceCenter=function(t,n){var e;function r(){var r,i,o=e.length,a=0,u=0;for(r=0;r<o;++r)a+=(i=e[r]).x,u+=i.y;for(a=a/o-t,u=u/o-n,r=0;r<o;++r)(i=e[r]).x-=a,i.y-=u}return null==t&&(t=0),null==n&&(n=0),r.initialize=function(t){e=t},r.x=function(n){return arguments.length?(t=+n,r):t},r.y=function(t){return arguments.length?(n=+t,r):n},r},t.forceCollide=function(t){var n,e,r=1,i=1;function o(){for(var t,o,u,c,f,s,l,h=n.length,d=0;d<i;++d)for(o=wa(n,Aa,Sa).visitAfter(a),t=0;t<h;++t)u=n[t],s=e[u.index],l=s*s,c=u.x+u.vx,f=u.y+u.vy,o.visit(p);function p(t,n,e,i,o){var a=t.data,h=t.r,d=s+h;if(!a)return n>c+d||i<c-d||e>f+d||o<f-d;if(a.index>u.index){var p=c-a.x-a.vx,v=f-a.y-a.vy,g=p*p+v*v;g<d*d&&(0===p&&(g+=(p=ya())*p),0===v&&(g+=(v=ya())*v),g=(d-(g=Math.sqrt(g)))/g*r,u.vx+=(p*=g)*(d=(h*=h)/(l+h)),u.vy+=(v*=g)*d,a.vx-=p*(d=1-d),a.vy-=v*d)}}}function a(t){if(t.data)return t.r=e[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function u(){if(n){var r,i,o=n.length;for(e=new Array(o),r=0;r<o;++r)i=n[r],e[i.index]=+t(i,r,n)}}return"function"!=typeof t&&(t=ga(null==t?1:+t)),o.initialize=function(t){n=t,u()},o.iterations=function(t){return arguments.length?(i=+t,o):i},o.strength=function(t){return arguments.length?(r=+t,o):r},o.radius=function(n){return arguments.length?(t="function"==typeof n?n:ga(+n),u(),o):t},o},t.forceLink=function(t){var n,e,r,i,o,a=ka,u=function(t){return 1/Math.min(i[t.source.index],i[t.target.index])},c=ga(30),f=1;function s(r){for(var i=0,a=t.length;i<f;++i)for(var u,c,s,l,h,d,p,v=0;v<a;++v)c=(u=t[v]).source,l=(s=u.target).x+s.vx-c.x-c.vx||ya(),h=s.y+s.vy-c.y-c.vy||ya(),l*=d=((d=Math.sqrt(l*l+h*h))-e[v])/d*r*n[v],h*=d,s.vx-=l*(p=o[v]),s.vy-=h*p,c.vx+=l*(p=1-p),c.vy+=h*p}function l(){if(r){var u,c,f=r.length,s=t.length,l=co(r,a);for(u=0,i=new Array(f);u<s;++u)(c=t[u]).index=u,"object"!=typeof c.source&&(c.source=Ea(l,c.source)),"object"!=typeof c.target&&(c.target=Ea(l,c.target)),i[c.source.index]=(i[c.source.index]||0)+1,i[c.target.index]=(i[c.target.index]||0)+1;for(u=0,o=new Array(s);u<s;++u)c=t[u],o[u]=i[c.source.index]/(i[c.source.index]+i[c.target.index]);n=new Array(s),h(),e=new Array(s),d()}}function h(){if(r)for(var e=0,i=t.length;e<i;++e)n[e]=+u(t[e],e,t)}function d(){if(r)for(var n=0,i=t.length;n<i;++n)e[n]=+c(t[n],n,t)}return null==t&&(t=[]),s.initialize=function(t){r=t,l()},s.links=function(n){return arguments.length?(t=n,l(),s):t},s.id=function(t){return arguments.length?(a=t,s):a},s.iterations=function(t){return arguments.length?(f=+t,s):f},s.strength=function(t){return arguments.length?(u="function"==typeof t?t:ga(+t),h(),s):u},s.distance=function(t){return arguments.length?(c="function"==typeof t?t:ga(+t),d(),s):c},s},t.forceManyBody=function(){var t,n,e,r,i=ga(-30),o=1,a=1/0,u=.81;function c(r){var i,o=t.length,a=wa(t,Ca,Pa).visitAfter(s);for(e=r,i=0;i<o;++i)n=t[i],a.visit(l)}function f(){if(t){var n,e,o=t.length;for(r=new Array(o),n=0;n<o;++n)e=t[n],r[e.index]=+i(e,n,t)}}function s(t){var n,e,i,o,a,u=0,c=0;if(t.length){for(i=o=a=0;a<4;++a)(n=t[a])&&(e=Math.abs(n.value))&&(u+=n.value,c+=e,i+=e*n.x,o+=e*n.y);t.x=i/c,t.y=o/c}else{(n=t).x=n.data.x,n.y=n.data.y;do{u+=r[n.data.index]}while(n=n.next)}t.value=u}function l(t,i,c,f){if(!t.value)return!0;var s=t.x-n.x,l=t.y-n.y,h=f-i,d=s*s+l*l;if(h*h/u<d)return d<a&&(0===s&&(d+=(s=ya())*s),0===l&&(d+=(l=ya())*l),d<o&&(d=Math.sqrt(o*d)),n.vx+=s*t.value*e/d,n.vy+=l*t.value*e/d),!0;if(!(t.length||d>=a)){(t.data!==n||t.next)&&(0===s&&(d+=(s=ya())*s),0===l&&(d+=(l=ya())*l),d<o&&(d=Math.sqrt(o*d)));do{t.data!==n&&(h=r[t.data.index]*e/d,n.vx+=s*h,n.vy+=l*h)}while(t=t.next)}}return c.initialize=function(n){t=n,f()},c.strength=function(t){return arguments.length?(i="function"==typeof t?t:ga(+t),f(),c):i},c.distanceMin=function(t){return arguments.length?(o=t*t,c):Math.sqrt(o)},c.distanceMax=function(t){return arguments.length?(a=t*t,c):Math.sqrt(a)},c.theta=function(t){return arguments.length?(u=t*t,c):Math.sqrt(u)},c},t.forceRadial=function(t,n,e){var r,i,o,a=ga(.1);function u(t){for(var a=0,u=r.length;a<u;++a){var c=r[a],f=c.x-n||1e-6,s=c.y-e||1e-6,l=Math.sqrt(f*f+s*s),h=(o[a]-l)*i[a]*t/l;c.vx+=f*h,c.vy+=s*h}}function c(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)o[n]=+t(r[n],n,r),i[n]=isNaN(o[n])?0:+a(r[n],n,r)}}return"function"!=typeof t&&(t=ga(+t)),null==n&&(n=0),null==e&&(e=0),u.initialize=function(t){r=t,c()},u.strength=function(t){return arguments.length?(a="function"==typeof t?t:ga(+t),c(),u):a},u.radius=function(n){return arguments.length?(t="function"==typeof n?n:ga(+n),c(),u):t},u.x=function(t){return arguments.length?(n=+t,u):n},u.y=function(t){return arguments.length?(e=+t,u):e},u},t.forceSimulation=function(t){var n,e=1,r=.001,i=1-Math.pow(r,1/300),o=0,a=.6,u=co(),c=hr(s),f=I("tick","end");function s(){l(),f.call("tick",n),e<r&&(c.stop(),f.call("end",n))}function l(r){var c,f,s=t.length;void 0===r&&(r=1);for(var l=0;l<r;++l)for(e+=(o-e)*i,u.each(function(t){t(e)}),c=0;c<s;++c)null==(f=t[c]).fx?f.x+=f.vx*=a:(f.x=f.fx,f.vx=0),null==f.fy?f.y+=f.vy*=a:(f.y=f.fy,f.vy=0);return n}function h(){for(var n,e=0,r=t.length;e<r;++e){if((n=t[e]).index=e,null!=n.fx&&(n.x=n.fx),null!=n.fy&&(n.y=n.fy),isNaN(n.x)||isNaN(n.y)){var i=za*Math.sqrt(e),o=e*Ra;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function d(n){return n.initialize&&n.initialize(t),n}return null==t&&(t=[]),h(),n={tick:l,restart:function(){return c.restart(s),n},stop:function(){return c.stop(),n},nodes:function(e){return arguments.length?(t=e,h(),u.each(d),n):t},alpha:function(t){return arguments.length?(e=+t,n):e},alphaMin:function(t){return arguments.length?(r=+t,n):r},alphaDecay:function(t){return arguments.length?(i=+t,n):+i},alphaTarget:function(t){return arguments.length?(o=+t,n):o},velocityDecay:function(t){return arguments.length?(a=1-t,n):1-a},force:function(t,e){return arguments.length>1?(null==e?u.remove(t):u.set(t,d(e)),n):u.get(t)},find:function(n,e,r){var i,o,a,u,c,f=0,s=t.length;for(null==r?r=1/0:r*=r,f=0;f<s;++f)(a=(i=n-(u=t[f]).x)*i+(o=e-u.y)*o)<r&&(c=u,r=a);return c},on:function(t,e){return arguments.length>1?(f.on(t,e),n):f.on(t)}}},t.forceX=function(t){var n,e,r,i=ga(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vx+=(r[o]-i.x)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=ga(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:ga(+t),a(),o):i},o.x=function(n){return arguments.length?(t="function"==typeof n?n:ga(+n),a(),o):t},o},t.forceY=function(t){var n,e,r,i=ga(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vy+=(r[o]-i.y)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=ga(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:ga(+t),a(),o):i},o.y=function(n){return arguments.length?(t="function"==typeof n?n:ga(+n),a(),o):t},o},t.formatDefaultLocale=Ga,t.formatLocale=Va,t.formatSpecifier=Oa,t.geoAlbers=el,t.geoAlbersUsa=function(){var t,n,e,r,i,o,a=el(),u=nl().rotate([154,0]).center([-2,58.5]).parallels([55,65]),c=nl().rotate([157,0]).center([-3,19.9]).parallels([8,18]),f={point:function(t,n){o=[t,n]}};function s(t){var n=t[0],a=t[1];return o=null,e.point(n,a),o||(r.point(n,a),o)||(i.point(n,a),o)}function l(){return t=n=null,s}return s.invert=function(t){var n=a.scale(),e=a.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?u:i>=.166&&i<.234&&r>=-.214&&r<-.115?c:a).invert(t)},s.stream=function(e){return t&&n===e?t:(r=[a.stream(n=e),u.stream(e),c.stream(e)],i=r.length,t={point:function(t,n){for(var e=-1;++e<i;)r[e].point(t,n)},sphere:function(){for(var t=-1;++t<i;)r[t].sphere()},lineStart:function(){for(var t=-1;++t<i;)r[t].lineStart()},lineEnd:function(){for(var t=-1;++t<i;)r[t].lineEnd()},polygonStart:function(){for(var t=-1;++t<i;)r[t].polygonStart()},polygonEnd:function(){for(var t=-1;++t<i;)r[t].polygonEnd()}});var r,i},s.precision=function(t){return arguments.length?(a.precision(t),u.precision(t),c.precision(t),l()):a.precision()},s.scale=function(t){return arguments.length?(a.scale(t),u.scale(.35*t),c.scale(t),s.translate(a.translate())):a.scale()},s.translate=function(t){if(!arguments.length)return a.translate();var n=a.scale(),o=+t[0],s=+t[1];return e=a.translate(t).clipExtent([[o-.455*n,s-.238*n],[o+.455*n,s+.238*n]]).stream(f),r=u.translate([o-.307*n,s+.201*n]).clipExtent([[o-.425*n+nu,s+.12*n+nu],[o-.214*n-nu,s+.234*n-nu]]).stream(f),i=c.translate([o-.205*n,s+.212*n]).clipExtent([[o-.214*n+nu,s+.166*n+nu],[o-.115*n-nu,s+.234*n-nu]]).stream(f),l()},s.fitExtent=function(t,n){return Is(s,t,n)},s.fitSize=function(t,n){return Hs(s,t,n)},s.fitWidth=function(t,n){return js(s,t,n)},s.fitHeight=function(t,n){return Xs(s,t,n)},s.scale(1070)},t.geoArea=function(t){return Uu.reset(),Cu(t,Ou),2*Uu},t.geoAzimuthalEqualArea=function(){return Qs(ol).scale(124.75).clipAngle(179.999)},t.geoAzimuthalEqualAreaRaw=ol,t.geoAzimuthalEquidistant=function(){return Qs(al).scale(79.4188).clipAngle(179.999)},t.geoAzimuthalEquidistantRaw=al,t.geoBounds=function(t){var n,e,r,i,o,a,u;if(Ju=Ku=-(Zu=Qu=1/0),ic=[],Cu(t,Mc),e=ic.length){for(ic.sort(zc),n=1,o=[r=ic[0]];n<e;++n)Rc(r,(i=ic[n])[0])||Rc(r,i[1])?(Pc(r[0],i[1])>Pc(r[0],r[1])&&(r[1]=i[1]),Pc(i[0],r[1])>Pc(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(a=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(u=Pc(r[1],i[0]))>a&&(a=u,Zu=i[0],Ku=r[1])}return ic=oc=null,Zu===1/0||Qu===1/0?[[NaN,NaN],[NaN,NaN]]:[[Zu,Qu],[Ku,Ju]]},t.geoCentroid=function(t){ac=uc=cc=fc=sc=lc=hc=dc=pc=vc=gc=0,Cu(t,Dc);var n=pc,e=vc,r=gc,i=n*n+e*e+r*r;return i<eu&&(n=lc,e=hc,r=dc,uc<nu&&(n=cc,e=fc,r=sc),(i=n*n+e*e+r*r)<eu)?[NaN,NaN]:[lu(e,n)*uu,wu(r/bu(i))*uu]},t.geoCircle=function(){var t,n,e=Xc([0,0]),r=Xc(90),i=Xc(6),o={point:function(e,r){t.push(e=n(e,r)),e[0]*=uu,e[1]*=uu}};function a(){var a=e.apply(this,arguments),u=r.apply(this,arguments)*cu,c=i.apply(this,arguments)*cu;return t=[],n=$c(-a[0]*cu,-a[1]*cu,0).invert,Jc(o,u,c,1),a={type:"Polygon",coordinates:[t]},t=n=null,a}return a.center=function(t){return arguments.length?(e="function"==typeof t?t:Xc([+t[0],+t[1]]),a):e},a.radius=function(t){return arguments.length?(r="function"==typeof t?t:Xc(+t),a):r},a.precision=function(t){return arguments.length?(i="function"==typeof t?t:Xc(+t),a):i},a},t.geoClipAntimeridian=df,t.geoClipCircle=pf,t.geoClipExtent=function(){var t,n,e,r=0,i=0,o=960,a=500;return e={stream:function(e){return t&&n===e?t:t=yf(r,i,o,a)(n=e)},extent:function(u){return arguments.length?(r=+u[0][0],i=+u[0][1],o=+u[1][0],a=+u[1][1],t=n=null,e):[[r,i],[o,a]]}}},t.geoClipRectangle=yf,t.geoConicConformal=function(){return Js(sl).scale(109.5).parallels([30,30])},t.geoConicConformalRaw=sl,t.geoConicEqualArea=nl,t.geoConicEqualAreaRaw=tl,t.geoConicEquidistant=function(){return Js(hl).scale(131.154).center([0,13.9389])},t.geoConicEquidistantRaw=hl,t.geoContains=function(t,n){return(t&&Cf.hasOwnProperty(t.type)?Cf[t.type]:zf)(t,n)},t.geoDistance=Ef,t.geoEqualEarth=function(){return Qs(_l).scale(177.158)},t.geoEqualEarthRaw=_l,t.geoEquirectangular=function(){return Qs(ll).scale(152.63)},t.geoEquirectangularRaw=ll,t.geoGnomonic=function(){return Qs(bl).scale(144.049).clipAngle(60)},t.geoGnomonicRaw=bl,t.geoGraticule=Ff,t.geoGraticule10=function(){return Ff()()},t.geoIdentity=function(){var t,n,e,r,i,o,a,u=1,c=0,f=0,s=1,l=1,h=0,d=null,p=1,v=1,g=Bs({point:function(t,n){var e=b([t,n]);this.stream.point(e[0],e[1])}}),y=Yf;function _(){return p=u*s,v=u*l,o=a=null,b}function b(e){var r=e[0]*p,i=e[1]*v;if(h){var o=i*t-r*n;r=r*t+i*n,i=o}return[r+c,i+f]}return b.invert=function(e){var r=e[0]-c,i=e[1]-f;if(h){var o=i*t+r*n;r=r*t-i*n,i=o}return[r/p,i/v]},b.stream=function(t){return o&&a===t?o:o=g(y(a=t))},b.postclip=function(t){return arguments.length?(y=t,d=e=r=i=null,_()):y},b.clipExtent=function(t){return arguments.length?(y=null==t?(d=e=r=i=null,Yf):yf(d=+t[0][0],e=+t[0][1],r=+t[1][0],i=+t[1][1]),_()):null==d?null:[[d,e],[r,i]]},b.scale=function(t){return arguments.length?(u=+t,_()):u},b.translate=function(t){return arguments.length?(c=+t[0],f=+t[1],_()):[c,f]},b.angle=function(e){return arguments.length?(n=yu(h=e%360*cu),t=hu(h),_()):h*uu},b.reflectX=function(t){return arguments.length?(s=t?-1:1,_()):s<0},b.reflectY=function(t){return arguments.length?(l=t?-1:1,_()):l<0},b.fitExtent=function(t,n){return Is(b,t,n)},b.fitSize=function(t,n){return Hs(b,t,n)},b.fitWidth=function(t,n){return js(b,t,n)},b.fitHeight=function(t,n){return Xs(b,t,n)},b},t.geoInterpolate=function(t,n){var e=t[0]*cu,r=t[1]*cu,i=n[0]*cu,o=n[1]*cu,a=hu(r),u=yu(r),c=hu(o),f=yu(o),s=a*hu(e),l=a*yu(e),h=c*hu(i),d=c*yu(i),p=2*wu(bu(Mu(o-r)+a*c*Mu(i-e))),v=yu(p),g=p?function(t){var n=yu(t*=p)/v,e=yu(p-t)/v,r=e*s+n*h,i=e*l+n*d,o=e*u+n*f;return[lu(i,r)*uu,lu(o,bu(r*r+i*i))*uu]}:function(){return[e*uu,r*uu]};return g.distance=p,g},t.geoLength=Af,t.geoMercator=function(){return cl(ul).scale(961/au)},t.geoMercatorRaw=ul,t.geoNaturalEarth1=function(){return Qs(ml).scale(175.295)},t.geoNaturalEarth1Raw=ml,t.geoOrthographic=function(){return Qs(xl).scale(249.5).clipAngle(90+nu)},t.geoOrthographicRaw=xl,t.geoPath=function(t,n){var e,r,i=4.5;function o(t){return t&&("function"==typeof i&&r.pointRadius(+i.apply(this,arguments)),Cu(t,e(r))),r.result()}return o.area=function(t){return Cu(t,e($f)),$f.result()},o.measure=function(t){return Cu(t,e(Ds)),Ds.result()},o.bounds=function(t){return Cu(t,e(rs)),rs.result()},o.centroid=function(t){return Cu(t,e(ys)),ys.result()},o.projection=function(n){return arguments.length?(e=null==n?(t=null,Yf):(t=n).stream,o):t},o.context=function(t){return arguments.length?(r=null==t?(n=null,new Us):new Ss(n=t),"function"!=typeof i&&r.pointRadius(i),o):n},o.pointRadius=function(t){return arguments.length?(i="function"==typeof t?t:(r.pointRadius(+t),+t),o):i},o.projection(t).context(n)},t.geoProjection=Qs,t.geoProjectionMutator=Ks,t.geoRotation=Kc,t.geoStereographic=function(){return Qs(wl).scale(250).clipAngle(142)},t.geoStereographicRaw=wl,t.geoStream=Cu,t.geoTransform=function(t){return{stream:Bs(t)}},t.geoTransverseMercator=function(){var t=cl(Ml),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):[(t=n())[1],-t[0]]},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):[(t=e())[0],t[1],t[2]-90]},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=Ml,t.gray=function(t,n){return new Bn(t,0,0,null==n?1:n)},t.hcl=Xn,t.hierarchy=kl,t.histogram=function(){var t=v,n=s,e=M;function r(r){var o,a,u=r.length,c=new Array(u);for(o=0;o<u;++o)c[o]=t(r[o],o,r);var f=n(c),s=f[0],l=f[1],h=e(c,s,l);Array.isArray(h)||(h=w(s,l,h),h=g(Math.ceil(s/h)*h,l,h));for(var d=h.length;h[0]<=s;)h.shift(),--d;for(;h[d-1]>l;)h.pop(),--d;var p,v=new Array(d+1);for(o=0;o<=d;++o)(p=v[o]=[]).x0=o>0?h[o-1]:s,p.x1=o<d?h[o]:l;for(o=0;o<u;++o)s<=(a=c[o])&&a<=l&&v[i(h,a,0,d)].push(r[o]);return v}return r.value=function(n){return arguments.length?(t="function"==typeof n?n:p(n),r):t},r.domain=function(t){return arguments.length?(n="function"==typeof t?t:p([t[0],t[1]]),r):n},r.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?p(h.call(t)):p(t),r):e},r},t.hsl=Tn,t.html=pa,t.image=function(t,n){return new Promise(function(e,r){var i=new Image;for(var o in n)i[o]=n[o];i.onerror=r,i.onload=function(){e(i)},i.src=t})},t.interpolate=Te,t.interpolateArray=function(t,n){return(ye(n)?ge:_e)(t,n)},t.interpolateBasis=oe,t.interpolateBasisClosed=ae,t.interpolateBlues=Qg,t.interpolateBrBG=fg,t.interpolateBuGn=Sg,t.interpolateBuPu=Eg,t.interpolateCividis=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(-4.54-t*(35.34-t*(2381.73-t*(6402.7-t*(7024.72-2710.57*t)))))))+", "+Math.max(0,Math.min(255,Math.round(32.49+t*(170.73+t*(52.82-t*(131.46-t*(176.58-67.37*t)))))))+", "+Math.max(0,Math.min(255,Math.round(81.24+t*(442.36-t*(2482.43-t*(6167.24-t*(6614.94-2475.67*t)))))))+")"},t.interpolateCool=sy,t.interpolateCubehelix=Ze,t.interpolateCubehelixDefault=cy,t.interpolateCubehelixLong=Qe,t.interpolateDate=be,t.interpolateDiscrete=function(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}},t.interpolateGnBu=Pg,t.interpolateGreens=Jg,t.interpolateGreys=ny,t.interpolateHcl=Ge,t.interpolateHclLong=$e,t.interpolateHsl=je,t.interpolateHslLong=Xe,t.interpolateHue=function(t,n){var e=fe(+t,+n);return function(t){var n=e(t);return n-360*Math.floor(n/360)}},t.interpolateInferno=_y,t.interpolateLab=function(t,n){var e=le((t=On(t)).l,(n=On(n)).l),r=le(t.a,n.a),i=le(t.b,n.b),o=le(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateMagma=yy,t.interpolateNumber=me,t.interpolateNumberArray=ge,t.interpolateObject=xe,t.interpolateOrRd=Rg,t.interpolateOranges=uy,t.interpolatePRGn=lg,t.interpolatePiYG=dg,t.interpolatePlasma=by,t.interpolatePuBu=Ug,t.interpolatePuBuGn=qg,t.interpolatePuOr=vg,t.interpolatePuRd=Bg,t.interpolatePurples=ry,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return ly.h=360*t-100,ly.s=1.5-1.5*n,ly.l=.8-.9*n,ly+""},t.interpolateRdBu=yg,t.interpolateRdGy=bg,t.interpolateRdPu=Yg,t.interpolateRdYlBu=xg,t.interpolateRdYlGn=Mg,t.interpolateReds=oy,t.interpolateRgb=he,t.interpolateRgbBasis=pe,t.interpolateRgbBasisClosed=ve,t.interpolateRound=Ae,t.interpolateSinebow=function(t){var n;return t=(.5-t)*Math.PI,hy.r=255*(n=Math.sin(t))*n,hy.g=255*(n=Math.sin(t+dy))*n,hy.b=255*(n=Math.sin(t+py))*n,hy+""},t.interpolateSpectral=Tg,t.interpolateString=Ne,t.interpolateTransformCss=qe,t.interpolateTransformSvg=Le,t.interpolateTurbo=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(34.61+t*(1172.33-t*(10793.56-t*(33300.12-t*(38394.49-14825.05*t)))))))+", "+Math.max(0,Math.min(255,Math.round(23.31+t*(557.33+t*(1225.33-t*(3574.96-t*(1073.77+707.56*t)))))))+", "+Math.max(0,Math.min(255,Math.round(27.2+t*(3211.1-t*(15327.97-t*(27814-t*(22569.18-6838.66*t)))))))+")"},t.interpolateViridis=gy,t.interpolateWarm=fy,t.interpolateYlGn=Xg,t.interpolateYlGnBu=Hg,t.interpolateYlOrBr=Gg,t.interpolateYlOrRd=Wg,t.interpolateZoom=Ie,t.interrupt=Pr,t.interval=function(t,n,e){var r=new lr,i=n;return null==n?(r.restart(t,n,e),r):(n=+n,e=null==e?fr():+e,r.restart(function o(a){a+=i,r.restart(o,i+=n,e),t(a)},n,e),r)},t.isoFormat=Rv,t.isoParse=Dv,t.json=function(t,n){return fetch(t,n).then(la)},t.keys=function(t){var n=[];for(var e in t)n.push(e);return n},t.lab=On,t.lch=function(t,n,e,r){return 1===arguments.length?jn(t):new Vn(e,n,t,null==r?1:r)},t.line=Hy,t.lineRadial=Qy,t.linkHorizontal=function(){return r_(i_)},t.linkRadial=function(){var t=r_(a_);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.linkVertical=function(){return r_(o_)},t.local=qt,t.map=co,t.matcher=nt,t.max=T,t.mean=function(t,n){var e,r=t.length,i=r,o=-1,a=0;if(null==n)for(;++o<r;)isNaN(e=u(t[o]))?--i:a+=e;else for(;++o<r;)isNaN(e=u(n(t[o],o,t)))?--i:a+=e;if(i)return a/i},t.median=function(t,e){var r,i=t.length,o=-1,a=[];if(null==e)for(;++o<i;)isNaN(r=u(t[o]))||a.push(r);else for(;++o<i;)isNaN(r=u(e(t[o],o,t)))||a.push(r);return N(a.sort(n),.5)},t.merge=A,t.min=S,t.mouse=Bt,t.namespace=W,t.namespaces=$,t.nest=function(){var t,n,e,r=[],i=[];function o(e,i,a,u){if(i>=r.length)return null!=t&&e.sort(t),null!=n?n(e):e;for(var c,f,s,l=-1,h=e.length,d=r[i++],p=co(),v=a();++l<h;)(s=p.get(c=d(f=e[l])+""))?s.push(f):p.set(c,[f]);return p.each(function(t,n){u(v,n,o(t,i,a,u))}),v}return e={object:function(t){return o(t,0,fo,so)},map:function(t){return o(t,0,lo,ho)},entries:function(t){return function t(e,o){if(++o>r.length)return e;var a,u=i[o-1];return null!=n&&o>=r.length?a=e.entries():(a=[],e.each(function(n,e){a.push({key:e,values:t(n,o)})})),null!=u?a.sort(function(t,n){return u(t.key,n.key)}):a}(o(t,0,lo,ho),0)},key:function(t){return r.push(t),e},sortKeys:function(t){return i[r.length-1]=t,e},sortValues:function(n){return t=n,e},rollup:function(t){return n=t,e}}},t.now=fr,t.pack=function(){var t=null,n=1,e=1,r=Wl;function i(i){return i.x=n/2,i.y=e/2,t?i.eachBefore(Kl(t)).eachAfter(Jl(r,.5)).eachBefore(th(1)):i.eachBefore(Kl(Ql)).eachAfter(Jl(Wl,1)).eachAfter(Jl(r,i.r/Math.min(n,e))).eachBefore(th(Math.min(n,e)/(2*i.r))),i}return i.radius=function(n){return arguments.length?(t=Gl(n),i):t},i.size=function(t){return arguments.length?(n=+t[0],e=+t[1],i):[n,e]},i.padding=function(t){return arguments.length?(r="function"==typeof t?t:Zl(+t),i):r},i},t.packEnclose=Dl,t.packSiblings=function(t){return Vl(t),t},t.pairs=function(t,n){null==n&&(n=a);for(var e=0,r=t.length-1,i=t[0],o=new Array(r<0?0:r);e<r;)o[e]=n(i,i=t[++e]);return o},t.partition=function(){var t=1,n=1,e=0,r=!1;function i(i){var o=i.height+1;return i.x0=i.y0=e,i.x1=t,i.y1=n/o,i.eachBefore(function(t,n){return function(r){r.children&&eh(r,r.x0,t*(r.depth+1)/n,r.x1,t*(r.depth+2)/n);var i=r.x0,o=r.y0,a=r.x1-e,u=r.y1-e;a<i&&(i=a=(i+a)/2),u<o&&(o=u=(o+u)/2),r.x0=i,r.y0=o,r.x1=a,r.y1=u}}(n,o)),r&&i.eachBefore(nh),i}return i.round=function(t){return arguments.length?(r=!!t,i):r},i.size=function(e){return arguments.length?(t=+e[0],n=+e[1],i):[t,n]},i.padding=function(t){return arguments.length?(e=+t,i):e},i},t.path=no,t.permute=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},t.pie=function(){var t=Vy,n=Xy,e=null,r=my(0),i=my(Py),o=my(0);function a(a){var u,c,f,s,l,h=a.length,d=0,p=new Array(h),v=new Array(h),g=+r.apply(this,arguments),y=Math.min(Py,Math.max(-Py,i.apply(this,arguments)-g)),_=Math.min(Math.abs(y)/h,o.apply(this,arguments)),b=_*(y<0?-1:1);for(u=0;u<h;++u)(l=v[p[u]=u]=+t(a[u],u,a))>0&&(d+=l);for(null!=n?p.sort(function(t,e){return n(v[t],v[e])}):null!=e&&p.sort(function(t,n){return e(a[t],a[n])}),u=0,f=d?(y-h*b)/d:0;u<h;++u,g=s)c=p[u],s=g+((l=v[c])>0?l*f:0)+b,v[c]={data:a[c],index:u,value:l,startAngle:g,endAngle:s,padAngle:_};return v}return a.value=function(n){return arguments.length?(t="function"==typeof n?n:my(+n),a):t},a.sortValues=function(t){return arguments.length?(n=t,e=null,a):n},a.sort=function(t){return arguments.length?(e=t,n=null,a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:my(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:my(+t),a):i},a.padAngle=function(t){return arguments.length?(o="function"==typeof t?t:my(+t),a):o},a},t.piecewise=function(t,n){for(var e=0,r=n.length-1,i=n[0],o=new Array(r<0?0:r);e<r;)o[e]=t(i,i=n[++e]);return function(t){var n=Math.max(0,Math.min(r-1,Math.floor(t*=r)));return o[n](t-n)}},t.pointRadial=Jy,t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},t.polygonCentroid=function(t){for(var n,e,r=-1,i=t.length,o=0,a=0,u=t[i-1],c=0;++r<i;)n=u,u=t[r],c+=e=n[0]*u[1]-u[0]*n[1],o+=(n[0]+u[0])*e,a+=(n[1]+u[1])*e;return[o/(c*=3),a/c]},t.polygonContains=function(t,n){for(var e,r,i=t.length,o=t[i-1],a=n[0],u=n[1],c=o[0],f=o[1],s=!1,l=0;l<i;++l)e=(o=t[l])[0],(r=o[1])>u!=f>u&&a<(c-e)*(u-r)/(f-r)+e&&(s=!s),c=e,f=r;return s},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(mh),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=xh(r),a=xh(i),u=a[0]===o[0],c=a[a.length-1]===o[o.length-1],f=[];for(n=o.length-1;n>=0;--n)f.push(t[r[o[n]][2]]);for(n=+u;n<a.length-c;++n)f.push(t[r[a[n]][2]]);return f},t.polygonLength=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],a=o[0],u=o[1],c=0;++r<i;)n=a,e=u,n-=a=(o=t[r])[0],e-=u=o[1],c+=Math.sqrt(n*n+e*e);return c},t.precisionFixed=$a,t.precisionPrefix=Wa,t.precisionRound=Za,t.quadtree=wa,t.quantile=N,t.quantize=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));return e},t.radialArea=Ky,t.radialLine=Qy,t.randomBates=Sh,t.randomExponential=kh,t.randomIrwinHall=Ah,t.randomLogNormal=Th,t.randomNormal=Nh,t.randomUniform=Mh,t.range=g,t.rgb=_n,t.ribbon=function(){var t=eo,n=ro,e=io,r=oo,i=ao,o=null;function a(){var a,u=Wi.call(arguments),c=t.apply(this,u),f=n.apply(this,u),s=+e.apply(this,(u[0]=c,u)),l=r.apply(this,u)-Xi,h=i.apply(this,u)-Xi,d=s*Ii(l),p=s*Hi(l),v=+e.apply(this,(u[0]=f,u)),g=r.apply(this,u)-Xi,y=i.apply(this,u)-Xi;if(o||(o=a=no()),o.moveTo(d,p),o.arc(0,0,s,l,h),l===g&&h===y||(o.quadraticCurveTo(0,0,v*Ii(g),v*Hi(g)),o.arc(0,0,v,g,y)),o.quadraticCurveTo(0,0,d,p),o.closePath(),a)return o=null,a+""||null}return a.radius=function(t){return arguments.length?(e="function"==typeof t?t:Zi(+t),a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:Zi(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:Zi(+t),a):i},a.source=function(n){return arguments.length?(t=n,a):t},a.target=function(t){return arguments.length?(n=t,a):n},a.context=function(t){return arguments.length?(o=null==t?null:t,a):o},a},t.scaleBand=Lh,t.scaleDiverging=function t(){var n=$h($v()(Bh));return n.copy=function(){return Vv(n,t())},Ch.apply(n,arguments)},t.scaleDivergingLog=function t(){var n=ed($v()).domain([.1,1,10]);return n.copy=function(){return Vv(n,t()).base(n.base())},Ch.apply(n,arguments)},t.scaleDivergingPow=Wv,t.scaleDivergingSqrt=function(){return Wv.apply(null,arguments).exponent(.5)},t.scaleDivergingSymlog=function t(){var n=od($v());return n.copy=function(){return Vv(n,t()).constant(n.constant())},Ch.apply(n,arguments)},t.scaleIdentity=function t(n){var e;function r(t){return isNaN(t=+t)?e:t}return r.invert=r,r.domain=r.range=function(t){return arguments.length?(n=zh.call(t,Uh),r):n.slice()},r.unknown=function(t){return arguments.length?(e=t,r):e},r.copy=function(){return t(n).unknown(e)},n=arguments.length?zh.call(n,Uh):[0,1],$h(r)},t.scaleImplicit=Dh,t.scaleLinear=function t(){var n=Vh(Bh,Bh);return n.copy=function(){return jh(n,t())},Eh.apply(n,arguments),$h(n)},t.scaleLog=function t(){var n=ed(Xh()).domain([1,10]);return n.copy=function(){return jh(n,t()).base(n.base())},Eh.apply(n,arguments),n},t.scaleOrdinal=qh,t.scalePoint=function(){return function t(n){var e=n.copy;return n.padding=n.paddingOuter,delete n.paddingInner,delete n.paddingOuter,n.copy=function(){return t(e())},n}(Lh.apply(null,arguments).paddingInner(1))},t.scalePow=sd,t.scaleQuantile=function t(){var e,r=[],o=[],a=[];function u(){var t=0,n=Math.max(1,o.length);for(a=new Array(n-1);++t<n;)a[t-1]=N(r,t/n);return c}function c(t){return isNaN(t=+t)?e:o[i(a,t)]}return c.invertExtent=function(t){var n=o.indexOf(t);return n<0?[NaN,NaN]:[n>0?a[n-1]:r[0],n<a.length?a[n]:r[r.length-1]]},c.domain=function(t){if(!arguments.length)return r.slice();r=[];for(var e,i=0,o=t.length;i<o;++i)null==(e=t[i])||isNaN(e=+e)||r.push(e);return r.sort(n),u()},c.range=function(t){return arguments.length?(o=Rh.call(t),u()):o.slice()},c.unknown=function(t){return arguments.length?(e=t,c):e},c.quantiles=function(){return a.slice()},c.copy=function(){return t().domain(r).range(o).unknown(e)},Eh.apply(c,arguments)},t.scaleQuantize=function t(){var n,e=0,r=1,o=1,a=[.5],u=[0,1];function c(t){return t<=t?u[i(a,t,0,o)]:n}function f(){var t=-1;for(a=new Array(o);++t<o;)a[t]=((t+1)*r-(t-o)*e)/(o+1);return c}return c.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],f()):[e,r]},c.range=function(t){return arguments.length?(o=(u=Rh.call(t)).length-1,f()):u.slice()},c.invertExtent=function(t){var n=u.indexOf(t);return n<0?[NaN,NaN]:n<1?[e,a[0]]:n>=o?[a[o-1],r]:[a[n-1],a[n]]},c.unknown=function(t){return arguments.length?(n=t,c):c},c.thresholds=function(){return a.slice()},c.copy=function(){return t().domain([e,r]).range(u).unknown(n)},Eh.apply($h(c),arguments)},t.scaleSequential=function t(){var n=$h(Xv()(Bh));return n.copy=function(){return Vv(n,t())},Ch.apply(n,arguments)},t.scaleSequentialLog=function t(){var n=ed(Xv()).domain([1,10]);return n.copy=function(){return Vv(n,t()).base(n.base())},Ch.apply(n,arguments)},t.scaleSequentialPow=Gv,t.scaleSequentialQuantile=function t(){var e=[],r=Bh;function o(t){if(!isNaN(t=+t))return r((i(e,t)-1)/(e.length-1))}return o.domain=function(t){if(!arguments.length)return e.slice();e=[];for(var r,i=0,a=t.length;i<a;++i)null==(r=t[i])||isNaN(r=+r)||e.push(r);return e.sort(n),o},o.interpolator=function(t){return arguments.length?(r=t,o):r},o.copy=function(){return t(r).domain(e)},Ch.apply(o,arguments)},t.scaleSequentialSqrt=function(){return Gv.apply(null,arguments).exponent(.5)},t.scaleSequentialSymlog=function t(){var n=od(Xv());return n.copy=function(){return Vv(n,t()).constant(n.constant())},Ch.apply(n,arguments)},t.scaleSqrt=function(){return sd.apply(null,arguments).exponent(.5)},t.scaleSymlog=function t(){var n=od(Xh());return n.copy=function(){return jh(n,t()).constant(n.constant())},Eh.apply(n,arguments)},t.scaleThreshold=function t(){var n,e=[.5],r=[0,1],o=1;function a(t){return t<=t?r[i(e,t,0,o)]:n}return a.domain=function(t){return arguments.length?(e=Rh.call(t),o=Math.min(e.length,r.length-1),a):e.slice()},a.range=function(t){return arguments.length?(r=Rh.call(t),o=Math.min(e.length,r.length-1),a):r.slice()},a.invertExtent=function(t){var n=r.indexOf(t);return[e[n-1],e[n]]},a.unknown=function(t){return arguments.length?(n=t,a):n},a.copy=function(){return t().domain(e).range(r).unknown(n)},Eh.apply(a,arguments)},t.scaleTime=function(){return Eh.apply(jv(Hd,Yd,Sd,Nd,wd,md,_d,pd,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)]),arguments)},t.scaleUtc=function(){return Eh.apply(jv(pp,hp,Kd,Wd,Gd,Xd,_d,pd,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)]),arguments)},t.scan=function(t,e){if(r=t.length){var r,i,o=0,a=0,u=t[a];for(null==e&&(e=n);++o<r;)(e(i=t[o],u)<0||0!==e(u,u))&&(u=i,a=o);return 0===e(u,u)?a:void 0}},t.schemeAccent=Kv,t.schemeBlues=Zg,t.schemeBrBG=cg,t.schemeBuGn=Ag,t.schemeBuPu=kg,t.schemeCategory10=Qv,t.schemeDark2=Jv,t.schemeGnBu=Cg,t.schemeGreens=Kg,t.schemeGreys=ty,t.schemeOrRd=zg,t.schemeOranges=ay,t.schemePRGn=sg,t.schemePaired=tg,t.schemePastel1=ng,t.schemePastel2=eg,t.schemePiYG=hg,t.schemePuBu=Lg,t.schemePuBuGn=Dg,t.schemePuOr=pg,t.schemePuRd=Og,t.schemePurples=ey,t.schemeRdBu=gg,t.schemeRdGy=_g,t.schemeRdPu=Fg,t.schemeRdYlBu=mg,t.schemeRdYlGn=wg,t.schemeReds=iy,t.schemeSet1=rg,t.schemeSet2=ig,t.schemeSet3=og,t.schemeSpectral=Ng,t.schemeTableau10=ag,t.schemeYlGn=jg,t.schemeYlGnBu=Ig,t.schemeYlOrBr=Vg,t.schemeYlOrRd=$g,t.select=Rt,t.selectAll=function(t){return"string"==typeof t?new Pt([document.querySelectorAll(t)],[document.documentElement]):new Pt([null==t?[]:t],Ct)},t.selection=zt,t.selector=K,t.selectorAll=tt,t.set=go,t.shuffle=function(t,n,e){for(var r,i,o=(null==e?t.length:e)-(n=null==n?0:+n);o;)i=Math.random()*o--|0,r=t[o+n],t[o+n]=t[i+n],t[i+n]=r;return t},t.stack=function(){var t=my([]),n=rb,e=eb,r=ib;function i(i){var o,a,u=t.apply(this,arguments),c=i.length,f=u.length,s=new Array(f);for(o=0;o<f;++o){for(var l,h=u[o],d=s[o]=new Array(c),p=0;p<c;++p)d[p]=l=[0,+r(i[p],h,p,i)],l.data=i[p];d.key=h}for(o=0,a=n(s);o<f;++o)s[a[o]].index=o;return e(s,a),s}return i.keys=function(n){return arguments.length?(t="function"==typeof n?n:my(t_.call(n)),i):t},i.value=function(t){return arguments.length?(r="function"==typeof t?t:my(+t),i):r},i.order=function(t){return arguments.length?(n=null==t?rb:"function"==typeof t?t:my(t_.call(t)),i):n},i.offset=function(t){return arguments.length?(e=null==t?eb:t,i):e},i},t.stackOffsetDiverging=function(t,n){if((u=t.length)>0)for(var e,r,i,o,a,u,c=0,f=t[n[0]].length;c<f;++c)for(o=a=0,e=0;e<u;++e)(i=(r=t[n[e]][c])[1]-r[0])>0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=a,r[0]=a+=i):(r[0]=0,r[1]=i)},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,a=t[0].length;o<a;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}eb(t,n)}},t.stackOffsetNone=eb,t.stackOffsetSilhouette=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var a=0,u=0;a<e;++a)u+=t[a][r][1]||0;i[r][1]+=i[r][0]=-u/2}eb(t,n)}},t.stackOffsetWiggle=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,a=1;a<r;++a){for(var u=0,c=0,f=0;u<i;++u){for(var s=t[n[u]],l=s[a][1]||0,h=(l-(s[a-1][1]||0))/2,d=0;d<u;++d){var p=t[n[d]];h+=(p[a][1]||0)-(p[a-1][1]||0)}c+=l,f+=h*l}e[a-1][1]+=e[a-1][0]=o,c&&(o-=f/c)}e[a-1][1]+=e[a-1][0]=o,eb(t,n)}},t.stackOrderAppearance=ob,t.stackOrderAscending=ub,t.stackOrderDescending=function(t){return ub(t).reverse()},t.stackOrderInsideOut=function(t){var n,e,r=t.length,i=t.map(cb),o=ob(t),a=0,u=0,c=[],f=[];for(n=0;n<r;++n)e=o[n],a<u?(a+=i[e],c.push(e)):(u+=i[e],f.push(e));return f.reverse().concat(c)},t.stackOrderNone=rb,t.stackOrderReverse=function(t){return rb(t).reverse()},t.stratify=function(){var t=ah,n=uh;function e(e){var r,i,o,a,u,c,f,s=e.length,l=new Array(s),h={};for(i=0;i<s;++i)r=e[i],u=l[i]=new zl(r),null!=(c=t(r,i,e))&&(c+="")&&(h[f=rh+(u.id=c)]=f in h?oh:u);for(i=0;i<s;++i)if(u=l[i],null!=(c=n(e[i],i,e))&&(c+="")){if(!(a=h[rh+c]))throw new Error("missing: "+c);if(a===oh)throw new Error("ambiguous: "+c);a.children?a.children.push(u):a.children=[u],u.parent=a}else{if(o)throw new Error("multiple roots");o=u}if(!o)throw new Error("no root");if(o.parent=ih,o.eachBefore(function(t){t.depth=t.parent.depth+1,--s}).eachBefore(Pl),o.parent=null,s>0)throw new Error("cycle");return o}return e.id=function(n){return arguments.length?(t=$l(n),e):t},e.parentId=function(t){return arguments.length?(n=$l(t),e):n},e},t.style=ft,t.sum=function(t,n){var e,r=t.length,i=-1,o=0;if(null==n)for(;++i<r;)(e=+t[i])&&(o+=e);else for(;++i<r;)(e=+n(t[i],i,t))&&(o+=e);return o},t.svg=va,t.symbol=function(){var t=my(u_),n=my(64),e=null;function r(){var r;if(e||(e=r=no()),t.apply(this,arguments).draw(e,+n.apply(this,arguments)),r)return e=null,r+""||null}return r.type=function(n){return arguments.length?(t="function"==typeof n?n:my(n),r):t},r.size=function(t){return arguments.length?(n="function"==typeof t?t:my(+t),r):n},r.context=function(t){return arguments.length?(e=null==t?null:t,r):e},r},t.symbolCircle=u_,t.symbolCross=c_,t.symbolDiamond=l_,t.symbolSquare=g_,t.symbolStar=v_,t.symbolTriangle=__,t.symbolWye=w_,t.symbols=M_,t.text=ua,t.thresholdFreedmanDiaconis=function(t,e,r){return t=d.call(t,u).sort(n),Math.ceil((r-e)/(2*(N(t,.75)-N(t,.25))*Math.pow(t.length,-1/3)))},t.thresholdScott=function(t,n,e){return Math.ceil((e-n)/(3.5*f(t)*Math.pow(t.length,-1/3)))},t.thresholdSturges=M,t.tickFormat=Gh,t.tickIncrement=x,t.tickStep=w,t.ticks=m,t.timeDay=Nd,t.timeDays=Td,t.timeFormatDefaultLocale=zv,t.timeFormatLocale=bp,t.timeFriday=zd,t.timeFridays=Bd,t.timeHour=wd,t.timeHours=Md,t.timeInterval=dd,t.timeMillisecond=pd,t.timeMilliseconds=vd,t.timeMinute=md,t.timeMinutes=xd,t.timeMonday=kd,t.timeMondays=qd,t.timeMonth=Yd,t.timeMonths=Id,t.timeSaturday=Rd,t.timeSaturdays=Fd,t.timeSecond=_d,t.timeSeconds=bd,t.timeSunday=Sd,t.timeSundays=Dd,t.timeThursday=Pd,t.timeThursdays=Od,t.timeTuesday=Ed,t.timeTuesdays=Ld,t.timeWednesday=Cd,t.timeWednesdays=Ud,t.timeWeek=Sd,t.timeWeeks=Dd,t.timeYear=Hd,t.timeYears=jd,t.timeout=yr,t.timer=hr,t.timerFlush=dr,t.touch=Ft,t.touches=function(t,n){null==n&&(n=Ut().touches);for(var e=0,r=n?n.length:0,i=new Array(r);e<r;++e)i[e]=Ot(t,n[e]);return i},t.transition=Or,t.transpose=k,t.tree=function(){var t=ch,n=1,e=1,r=null;function i(i){var c=function(t){for(var n,e,r,i,o,a=new dh(t,0),u=[a];n=u.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)u.push(e=n.children[i]=new dh(r[i],i)),e.parent=n;return(a.parent=new dh(null,0)).children=[a],a}(i);if(c.eachAfter(o),c.parent.m=-c.z,c.eachBefore(a),r)i.eachBefore(u);else{var f=i,s=i,l=i;i.eachBefore(function(t){t.x<f.x&&(f=t),t.x>s.x&&(s=t),t.depth>l.depth&&(l=t)});var h=f===s?1:t(f,s)/2,d=h-f.x,p=n/(s.x+h+d),v=e/(l.depth||1);i.eachBefore(function(t){t.x=(t.x+d)*p,t.y=t.depth*v})}return i}function o(n){var e=n.children,r=n.parent.children,i=n.i?r[n.i-1]:null;if(e){!function(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}(n);var o=(e[0].z+e[e.length-1].z)/2;i?(n.z=i.z+t(n._,i._),n.m=n.z-o):n.z=o}else i&&(n.z=i.z+t(n._,i._));n.parent.A=function(n,e,r){if(e){for(var i,o=n,a=n,u=e,c=o.parent.children[0],f=o.m,s=a.m,l=u.m,h=c.m;u=sh(u),o=fh(o),u&&o;)c=fh(c),(a=sh(a)).a=n,(i=u.z+l-o.z-f+t(u._,o._))>0&&(lh(hh(u,n,r),n,i),f+=i,s+=i),l+=u.m,f+=o.m,h+=c.m,s+=a.m;u&&!sh(a)&&(a.t=u,a.m+=l-s),o&&!fh(c)&&(c.t=o,c.m+=f-h,r=n)}return r}(n,i,n.parent.A||r[0])}function a(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function u(t){t.x*=n,t.y=t.depth*e}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.treemap=function(){var t=yh,n=!1,e=1,r=1,i=[0],o=Wl,a=Wl,u=Wl,c=Wl,f=Wl;function s(t){return t.x0=t.y0=0,t.x1=e,t.y1=r,t.eachBefore(l),i=[0],n&&t.eachBefore(nh),t}function l(n){var e=i[n.depth],r=n.x0+e,s=n.y0+e,l=n.x1-e,h=n.y1-e;l<r&&(r=l=(r+l)/2),h<s&&(s=h=(s+h)/2),n.x0=r,n.y0=s,n.x1=l,n.y1=h,n.children&&(e=i[n.depth+1]=o(n)/2,r+=f(n)-e,s+=a(n)-e,(l-=u(n)-e)<r&&(r=l=(r+l)/2),(h-=c(n)-e)<s&&(s=h=(s+h)/2),t(n,r,s,l,h))}return s.round=function(t){return arguments.length?(n=!!t,s):n},s.size=function(t){return arguments.length?(e=+t[0],r=+t[1],s):[e,r]},s.tile=function(n){return arguments.length?(t=$l(n),s):t},s.padding=function(t){return arguments.length?s.paddingInner(t).paddingOuter(t):s.paddingInner()},s.paddingInner=function(t){return arguments.length?(o="function"==typeof t?t:Zl(+t),s):o},s.paddingOuter=function(t){return arguments.length?s.paddingTop(t).paddingRight(t).paddingBottom(t).paddingLeft(t):s.paddingTop()},s.paddingTop=function(t){return arguments.length?(a="function"==typeof t?t:Zl(+t),s):a},s.paddingRight=function(t){return arguments.length?(u="function"==typeof t?t:Zl(+t),s):u},s.paddingBottom=function(t){return arguments.length?(c="function"==typeof t?t:Zl(+t),s):c},s.paddingLeft=function(t){return arguments.length?(f="function"==typeof t?t:Zl(+t),s):f},s},t.treemapBinary=function(t,n,e,r,i){var o,a,u=t.children,c=u.length,f=new Array(c+1);for(f[0]=a=o=0;o<c;++o)f[o+1]=a+=u[o].value;!function t(n,e,r,i,o,a,c){if(n>=e-1){var s=u[n];return s.x0=i,s.y0=o,s.x1=a,void(s.y1=c)}for(var l=f[n],h=r/2+l,d=n+1,p=e-1;d<p;){var v=d+p>>>1;f[v]<h?d=v+1:p=v}h-f[d-1]<f[d]-h&&n+1<d&&--d;var g=f[d]-l,y=r-g;if(a-i>c-o){var _=(i*y+a*g)/r;t(n,d,g,i,o,_,c),t(d,e,y,_,o,a,c)}else{var b=(o*y+c*g)/r;t(n,d,g,i,o,a,b),t(d,e,y,i,b,a,c)}}(0,c,t.value,n,e,r,i)},t.treemapDice=eh,t.treemapResquarify=_h,t.treemapSlice=ph,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?ph:eh)(t,n,e,r,i)},t.treemapSquarify=yh,t.tsv=sa,t.tsvFormat=Ko,t.tsvFormatBody=Jo,t.tsvFormatRow=na,t.tsvFormatRows=ta,t.tsvFormatValue=ea,t.tsvParse=Zo,t.tsvParseRows=Qo,t.utcDay=Wd,t.utcDays=Zd,t.utcFriday=rp,t.utcFridays=sp,t.utcHour=Gd,t.utcHours=$d,t.utcMillisecond=pd,t.utcMilliseconds=vd,t.utcMinute=Xd,t.utcMinutes=Vd,t.utcMonday=Jd,t.utcMondays=ap,t.utcMonth=hp,t.utcMonths=dp,t.utcSaturday=ip,t.utcSaturdays=lp,t.utcSecond=_d,t.utcSeconds=bd,t.utcSunday=Kd,t.utcSundays=op,t.utcThursday=ep,t.utcThursdays=fp,t.utcTuesday=tp,t.utcTuesdays=up,t.utcWednesday=np,t.utcWednesdays=cp,t.utcWeek=Kd,t.utcWeeks=op,t.utcYear=pp,t.utcYears=vp,t.values=function(t){var n=[];for(var e in t)n.push(t[e]);return n},t.variance=c,t.version="5.16.0",t.voronoi=function(){var t=sb,n=lb,e=null;function r(r){return new Vb(r.map(function(e,i){var o=[Math.round(t(e,i,r)/Ib)*Ib,Math.round(n(e,i,r)/Ib)*Ib];return o.index=i,o.data=e,o}),e)}return r.polygons=function(t){return r(t).polygons()},r.links=function(t){return r(t).links()},r.triangles=function(t){return r(t).triangles()},r.x=function(n){return arguments.length?(t="function"==typeof n?n:fb(+n),r):t},r.y=function(t){return arguments.length?(n="function"==typeof t?t:fb(+t),r):n},r.extent=function(t){return arguments.length?(e=null==t?null:[[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]],r):e&&[[e[0][0],e[0][1]],[e[1][0],e[1][1]]]},r.size=function(t){return arguments.length?(e=null==t?null:[[0,0],[+t[0],+t[1]]],r):e&&[e[1][0]-e[0][0],e[1][1]-e[0][1]]},r},t.window=ct,t.xml=da,t.zip=function(){return k(arguments)},t.zoom=function(){var n,e,r=tm,i=nm,o=om,a=rm,u=im,c=[0,1/0],f=[[-1/0,-1/0],[1/0,1/0]],s=250,l=Ie,h=I("start","zoom","end"),d=500,p=150,v=0;function g(t){t.property("__zoom",em).on("wheel.zoom",M).on("mousedown.zoom",N).on("dblclick.zoom",T).filter(u).on("touchstart.zoom",A).on("touchmove.zoom",S).on("touchend.zoom touchcancel.zoom",k).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function y(t,n){return(n=Math.max(c[0],Math.min(c[1],n)))===t.k?t:new Wb(n,t.x,t.y)}function _(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new Wb(t.k,r,i)}function b(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function m(t,n,e){t.on("start.zoom",function(){x(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){x(this,arguments).end()}).tween("zoom",function(){var t=this,r=arguments,o=x(t,r),a=i.apply(t,r),u=null==e?b(a):"function"==typeof e?e.apply(t,r):e,c=Math.max(a[1][0]-a[0][0],a[1][1]-a[0][1]),f=t.__zoom,s="function"==typeof n?n.apply(t,r):n,h=l(f.invert(u).concat(c/f.k),s.invert(u).concat(c/s.k));return function(t){if(1===t)t=s;else{var n=h(t),e=c/n[2];t=new Wb(e,u[0]-n[0]*e,u[1]-n[1]*e)}o.zoom(null,t)}})}function x(t,n,e){return!e&&t.__zooming||new w(t,n)}function w(t,n){this.that=t,this.args=n,this.active=0,this.extent=i.apply(t,n),this.taps=0}function M(){if(r.apply(this,arguments)){var t=x(this,arguments),n=this.__zoom,e=Math.max(c[0],Math.min(c[1],n.k*Math.pow(2,a.apply(this,arguments)))),i=Bt(this);if(t.wheel)t.mouse[0][0]===i[0]&&t.mouse[0][1]===i[1]||(t.mouse[1]=n.invert(t.mouse[0]=i)),clearTimeout(t.wheel);else{if(n.k===e)return;t.mouse=[i,n.invert(i)],Pr(this),t.start()}Jb(),t.wheel=setTimeout(function(){t.wheel=null,t.end()},p),t.zoom("mouse",o(_(y(n,e),t.mouse[0],t.mouse[1]),t.extent,f))}}function N(){if(!e&&r.apply(this,arguments)){var n=x(this,arguments,!0),i=Rt(t.event.view).on("mousemove.zoom",function(){if(Jb(),!n.moved){var e=t.event.clientX-u,r=t.event.clientY-c;n.moved=e*e+r*r>v}n.zoom("mouse",o(_(n.that.__zoom,n.mouse[0]=Bt(n.that),n.mouse[1]),n.extent,f))},!0).on("mouseup.zoom",function(){i.on("mousemove.zoom mouseup.zoom",null),jt(t.event.view,n.moved),Jb(),n.end()},!0),a=Bt(this),u=t.event.clientX,c=t.event.clientY;Ht(t.event.view),Kb(),n.mouse=[a,this.__zoom.invert(a)],Pr(this),n.start()}}function T(){if(r.apply(this,arguments)){var n=this.__zoom,e=Bt(this),a=n.invert(e),u=n.k*(t.event.shiftKey?.5:2),c=o(_(y(n,u),e,a),i.apply(this,arguments),f);Jb(),s>0?Rt(this).transition().duration(s).call(m,c,e):Rt(this).call(g.transform,c)}}function A(){if(r.apply(this,arguments)){var e,i,o,a,u=t.event.touches,c=u.length,f=x(this,arguments,t.event.changedTouches.length===c);for(Kb(),i=0;i<c;++i)a=[a=Ft(this,u,(o=u[i]).identifier),this.__zoom.invert(a),o.identifier],f.touch0?f.touch1||f.touch0[2]===a[2]||(f.touch1=a,f.taps=0):(f.touch0=a,e=!0,f.taps=1+!!n);n&&(n=clearTimeout(n)),e&&(f.taps<2&&(n=setTimeout(function(){n=null},d)),Pr(this),f.start())}}function S(){if(this.__zooming){var e,r,i,a,u=x(this,arguments),c=t.event.changedTouches,s=c.length;for(Jb(),n&&(n=clearTimeout(n)),u.taps=0,e=0;e<s;++e)i=Ft(this,c,(r=c[e]).identifier),u.touch0&&u.touch0[2]===r.identifier?u.touch0[0]=i:u.touch1&&u.touch1[2]===r.identifier&&(u.touch1[0]=i);if(r=u.that.__zoom,u.touch1){var l=u.touch0[0],h=u.touch0[1],d=u.touch1[0],p=u.touch1[1],v=(v=d[0]-l[0])*v+(v=d[1]-l[1])*v,g=(g=p[0]-h[0])*g+(g=p[1]-h[1])*g;r=y(r,Math.sqrt(v/g)),i=[(l[0]+d[0])/2,(l[1]+d[1])/2],a=[(h[0]+p[0])/2,(h[1]+p[1])/2]}else{if(!u.touch0)return;i=u.touch0[0],a=u.touch0[1]}u.zoom("touch",o(_(r,i,a),u.extent,f))}}function k(){if(this.__zooming){var n,r,i=x(this,arguments),o=t.event.changedTouches,a=o.length;for(Kb(),e&&clearTimeout(e),e=setTimeout(function(){e=null},d),n=0;n<a;++n)r=o[n],i.touch0&&i.touch0[2]===r.identifier?delete i.touch0:i.touch1&&i.touch1[2]===r.identifier&&delete i.touch1;if(i.touch1&&!i.touch0&&(i.touch0=i.touch1,delete i.touch1),i.touch0)i.touch0[1]=this.__zoom.invert(i.touch0[0]);else if(i.end(),2===i.taps){var u=Rt(this).on("dblclick.zoom");u&&u.apply(this,arguments)}}}return g.transform=function(t,n,e){var r=t.selection?t.selection():t;r.property("__zoom",em),t!==r?m(t,n,e):r.interrupt().each(function(){x(this,arguments).start().zoom(null,"function"==typeof n?n.apply(this,arguments):n).end()})},g.scaleBy=function(t,n,e){g.scaleTo(t,function(){var t=this.__zoom.k,e="function"==typeof n?n.apply(this,arguments):n;return t*e},e)},g.scaleTo=function(t,n,e){g.transform(t,function(){var t=i.apply(this,arguments),r=this.__zoom,a=null==e?b(t):"function"==typeof e?e.apply(this,arguments):e,u=r.invert(a),c="function"==typeof n?n.apply(this,arguments):n;return o(_(y(r,c),a,u),t,f)},e)},g.translateBy=function(t,n,e){g.transform(t,function(){return o(this.__zoom.translate("function"==typeof n?n.apply(this,arguments):n,"function"==typeof e?e.apply(this,arguments):e),i.apply(this,arguments),f)})},g.translateTo=function(t,n,e,r){g.transform(t,function(){var t=i.apply(this,arguments),a=this.__zoom,u=null==r?b(t):"function"==typeof r?r.apply(this,arguments):r;return o(Zb.translate(u[0],u[1]).scale(a.k).translate("function"==typeof n?-n.apply(this,arguments):-n,"function"==typeof e?-e.apply(this,arguments):-e),t,f)},r)},w.prototype={start:function(){return 1==++this.active&&(this.that.__zooming=this,this.emit("start")),this},zoom:function(t,n){return this.mouse&&"mouse"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&"touch"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&"touch"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit("zoom"),this},end:function(){return 0==--this.active&&(delete this.that.__zooming,this.emit("end")),this},emit:function(t){kt(new $b(g,t,this.that.__zoom),h.apply,h,[t,this.that,this.args])}},g.wheelDelta=function(t){return arguments.length?(a="function"==typeof t?t:Gb(+t),g):a},g.filter=function(t){return arguments.length?(r="function"==typeof t?t:Gb(!!t),g):r},g.touchable=function(t){return arguments.length?(u="function"==typeof t?t:Gb(!!t),g):u},g.extent=function(t){return arguments.length?(i="function"==typeof t?t:Gb([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),g):i},g.scaleExtent=function(t){return arguments.length?(c[0]=+t[0],c[1]=+t[1],g):[c[0],c[1]]},g.translateExtent=function(t){return arguments.length?(f[0][0]=+t[0][0],f[1][0]=+t[1][0],f[0][1]=+t[0][1],f[1][1]=+t[1][1],g):[[f[0][0],f[0][1]],[f[1][0],f[1][1]]]},g.constrain=function(t){return arguments.length?(o=t,g):o},g.duration=function(t){return arguments.length?(s=+t,g):s},g.interpolate=function(t){return arguments.length?(l=t,g):l},g.on=function(){var t=h.on.apply(h,arguments);return t===h?g:t},g.clickDistance=function(t){return arguments.length?(v=(t=+t)*t,g):Math.sqrt(v)},g},t.zoomIdentity=Zb,t.zoomTransform=Qb,Object.defineProperty(t,"__esModule",{value:!0})});
+// https://d3js.org v7.8.4 Copyright 2010-2023 Mike Bostock
+!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{})}(this,(function(t){"use strict";function n(t,n){return null==t||null==n?NaN:t<n?-1:t>n?1:t>=n?0:NaN}function e(t,n){return null==t||null==n?NaN:n<t?-1:n>t?1:n>=t?0:NaN}function r(t){let r,o,a;function u(t,n,e=0,i=t.length){if(e<i){if(0!==r(n,n))return i;do{const r=e+i>>>1;o(t[r],n)<0?e=r+1:i=r}while(e<i)}return e}return 2!==t.length?(r=n,o=(e,r)=>n(t(e),r),a=(n,e)=>t(n)-e):(r=t===n||t===e?t:i,o=t,a=t),{left:u,center:function(t,n,e=0,r=t.length){const i=u(t,n,e,r-1);return i>e&&a(t[i-1],n)>-a(t[i],n)?i-1:i},right:function(t,n,e=0,i=t.length){if(e<i){if(0!==r(n,n))return i;do{const r=e+i>>>1;o(t[r],n)<=0?e=r+1:i=r}while(e<i)}return e}}}function i(){return 0}function o(t){return null===t?NaN:+t}function*a(t,n){if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(yield n);else{let e=-1;for(let r of t)null!=(r=n(r,++e,t))&&(r=+r)>=r&&(yield r)}}const u=r(n),c=u.right,f=u.left,s=r(o).center;var l=c;const h=p(v),d=p((function(t){const n=v(t);return(t,e,r,i,o)=>{n(t,e,(r<<=2)+0,(i<<=2)+0,o<<=2),n(t,e,r+1,i+1,o),n(t,e,r+2,i+2,o),n(t,e,r+3,i+3,o)}}));function p(t){return function(n,e,r=e){if(!((e=+e)>=0))throw new RangeError("invalid rx");if(!((r=+r)>=0))throw new RangeError("invalid ry");let{data:i,width:o,height:a}=n;if(!((o=Math.floor(o))>=0))throw new RangeError("invalid width");if(!((a=Math.floor(void 0!==a?a:i.length/o))>=0))throw new RangeError("invalid height");if(!o||!a||!e&&!r)return n;const u=e&&t(e),c=r&&t(r),f=i.slice();return u&&c?(g(u,f,i,o,a),g(u,i,f,o,a),g(u,f,i,o,a),y(c,i,f,o,a),y(c,f,i,o,a),y(c,i,f,o,a)):u?(g(u,i,f,o,a),g(u,f,i,o,a),g(u,i,f,o,a)):c&&(y(c,i,f,o,a),y(c,f,i,o,a),y(c,i,f,o,a)),n}}function g(t,n,e,r,i){for(let o=0,a=r*i;o<a;)t(n,e,o,o+=r,1)}function y(t,n,e,r,i){for(let o=0,a=r*i;o<r;++o)t(n,e,o,o+a,r)}function v(t){const n=Math.floor(t);if(n===t)return function(t){const n=2*t+1;return(e,r,i,o,a)=>{if(!((o-=a)>=i))return;let u=t*r[i];const c=a*t;for(let t=i,n=i+c;t<n;t+=a)u+=r[Math.min(o,t)];for(let t=i,f=o;t<=f;t+=a)u+=r[Math.min(o,t+c)],e[t]=u/n,u-=r[Math.max(i,t-c)]}}(t);const e=t-n,r=2*t+1;return(t,i,o,a,u)=>{if(!((a-=u)>=o))return;let c=n*i[o];const f=u*n,s=f+u;for(let t=o,n=o+f;t<n;t+=u)c+=i[Math.min(a,t)];for(let n=o,l=a;n<=l;n+=u)c+=i[Math.min(a,n+f)],t[n]=(c+e*(i[Math.max(o,n-s)]+i[Math.min(a,n+s)]))/r,c-=i[Math.max(o,n-f)]}}function _(t,n){let e=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&++e;else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(i=+i)>=i&&++e}return e}function b(t){return 0|t.length}function m(t){return!(t>0)}function x(t){return"object"!=typeof t||"length"in t?t:Array.from(t)}function w(t,n){let e,r=0,i=0,o=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(e=n-i,i+=e/++r,o+=e*(n-i));else{let a=-1;for(let u of t)null!=(u=n(u,++a,t))&&(u=+u)>=u&&(e=u-i,i+=e/++r,o+=e*(u-i))}if(r>1)return o/(r-1)}function M(t,n){const e=w(t,n);return e?Math.sqrt(e):e}function T(t,n){let e,r;if(void 0===n)for(const n of t)null!=n&&(void 0===e?n>=n&&(e=r=n):(e>n&&(e=n),r<n&&(r=n)));else{let i=-1;for(let o of t)null!=(o=n(o,++i,t))&&(void 0===e?o>=o&&(e=r=o):(e>o&&(e=o),r<o&&(r=o)))}return[e,r]}class A{constructor(){this._partials=new Float64Array(32),this._n=0}add(t){const n=this._partials;let e=0;for(let r=0;r<this._n&&r<32;r++){const i=n[r],o=t+i,a=Math.abs(t)<Math.abs(i)?t-(o-i):i-(o-t);a&&(n[e++]=a),t=o}return n[e]=t,this._n=e+1,this}valueOf(){const t=this._partials;let n,e,r,i=this._n,o=0;if(i>0){for(o=t[--i];i>0&&(n=o,e=t[--i],o=n+e,r=e-(o-n),!r););i>0&&(r<0&&t[i-1]<0||r>0&&t[i-1]>0)&&(e=2*r,n=o+e,e==n-o&&(o=n))}return o}}class InternMap extends Map{constructor(t,n=k){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),null!=t)for(const[n,e]of t)this.set(n,e)}get(t){return super.get(S(this,t))}has(t){return super.has(S(this,t))}set(t,n){return super.set(E(this,t),n)}delete(t){return super.delete(N(this,t))}}class InternSet extends Set{constructor(t,n=k){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),null!=t)for(const n of t)this.add(n)}has(t){return super.has(S(this,t))}add(t){return super.add(E(this,t))}delete(t){return super.delete(N(this,t))}}function S({_intern:t,_key:n},e){const r=n(e);return t.has(r)?t.get(r):e}function E({_intern:t,_key:n},e){const r=n(e);return t.has(r)?t.get(r):(t.set(r,e),e)}function N({_intern:t,_key:n},e){const r=n(e);return t.has(r)&&(e=t.get(r),t.delete(r)),e}function k(t){return null!==t&&"object"==typeof t?t.valueOf():t}function C(t){return t}function P(t,...n){return q(t,C,C,n)}function z(t,...n){return q(t,Array.from,C,n)}function $(t,n){for(let e=1,r=n.length;e<r;++e)t=t.flatMap((t=>t.pop().map((([n,e])=>[...t,n,e]))));return t}function D(t,n,...e){return q(t,C,n,e)}function R(t,n,...e){return q(t,Array.from,n,e)}function F(t){if(1!==t.length)throw new Error("duplicate key");return t[0]}function q(t,n,e,r){return function t(i,o){if(o>=r.length)return e(i);const a=new InternMap,u=r[o++];let c=-1;for(const t of i){const n=u(t,++c,i),e=a.get(n);e?e.push(t):a.set(n,[t])}for(const[n,e]of a)a.set(n,t(e,o));return n(a)}(t,0)}function U(t,n){return Array.from(n,(n=>t[n]))}function I(t,...n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");t=Array.from(t);let[e]=n;if(e&&2!==e.length||n.length>1){const r=Uint32Array.from(t,((t,n)=>n));return n.length>1?(n=n.map((n=>t.map(n))),r.sort(((t,e)=>{for(const r of n){const n=B(r[t],r[e]);if(n)return n}}))):(e=t.map(e),r.sort(((t,n)=>B(e[t],e[n])))),U(t,r)}return t.sort(O(e))}function O(t=n){if(t===n)return B;if("function"!=typeof t)throw new TypeError("compare is not a function");return(n,e)=>{const r=t(n,e);return r||0===r?r:(0===t(e,e))-(0===t(n,n))}}function B(t,n){return(null==t||!(t>=t))-(null==n||!(n>=n))||(t<n?-1:t>n?1:0)}var Y=Array.prototype.slice;function L(t){return()=>t}const j=Math.sqrt(50),H=Math.sqrt(10),X=Math.sqrt(2);function G(t,n,e){const r=(n-t)/Math.max(0,e),i=Math.floor(Math.log10(r)),o=r/Math.pow(10,i),a=o>=j?10:o>=H?5:o>=X?2:1;let u,c,f;return i<0?(f=Math.pow(10,-i)/a,u=Math.round(t*f),c=Math.round(n*f),u/f<t&&++u,c/f>n&&--c,f=-f):(f=Math.pow(10,i)*a,u=Math.round(t/f),c=Math.round(n/f),u*f<t&&++u,c*f>n&&--c),c<u&&.5<=e&&e<2?G(t,n,2*e):[u,c,f]}function V(t,n,e){if(!((e=+e)>0))return[];if((t=+t)===(n=+n))return[t];const r=n<t,[i,o,a]=r?G(n,t,e):G(t,n,e);if(!(o>=i))return[];const u=o-i+1,c=new Array(u);if(r)if(a<0)for(let t=0;t<u;++t)c[t]=(o-t)/-a;else for(let t=0;t<u;++t)c[t]=(o-t)*a;else if(a<0)for(let t=0;t<u;++t)c[t]=(i+t)/-a;else for(let t=0;t<u;++t)c[t]=(i+t)*a;return c}function W(t,n,e){return G(t=+t,n=+n,e=+e)[2]}function Z(t,n,e){e=+e;const r=(n=+n)<(t=+t),i=r?W(n,t,e):W(t,n,e);return(r?-1:1)*(i<0?1/-i:i)}function K(t,n,e){let r;for(;;){const i=W(t,n,e);if(i===r||0===i||!isFinite(i))return[t,n];i>0?(t=Math.floor(t/i)*i,n=Math.ceil(n/i)*i):i<0&&(t=Math.ceil(t*i)/i,n=Math.floor(n*i)/i),r=i}}function Q(t){return Math.max(1,Math.ceil(Math.log(_(t))/Math.LN2)+1)}function J(){var t=C,n=T,e=Q;function r(r){Array.isArray(r)||(r=Array.from(r));var i,o,a,u=r.length,c=new Array(u);for(i=0;i<u;++i)c[i]=t(r[i],i,r);var f=n(c),s=f[0],h=f[1],d=e(c,s,h);if(!Array.isArray(d)){const t=h,e=+d;if(n===T&&([s,h]=K(s,h,e)),(d=V(s,h,e))[0]<=s&&(a=W(s,h,e)),d[d.length-1]>=h)if(t>=h&&n===T){const t=W(s,h,e);isFinite(t)&&(t>0?h=(Math.floor(h/t)+1)*t:t<0&&(h=(Math.ceil(h*-t)+1)/-t))}else d.pop()}for(var p=d.length,g=0,y=p;d[g]<=s;)++g;for(;d[y-1]>h;)--y;(g||y<p)&&(d=d.slice(g,y),p=y-g);var v,_=new Array(p+1);for(i=0;i<=p;++i)(v=_[i]=[]).x0=i>0?d[i-1]:s,v.x1=i<p?d[i]:h;if(isFinite(a)){if(a>0)for(i=0;i<u;++i)null!=(o=c[i])&&s<=o&&o<=h&&_[Math.min(p,Math.floor((o-s)/a))].push(r[i]);else if(a<0)for(i=0;i<u;++i)if(null!=(o=c[i])&&s<=o&&o<=h){const t=Math.floor((s-o)*a);_[Math.min(p,t+(d[t]<=o))].push(r[i])}}else for(i=0;i<u;++i)null!=(o=c[i])&&s<=o&&o<=h&&_[l(d,o,0,p)].push(r[i]);return _}return r.value=function(n){return arguments.length?(t="function"==typeof n?n:L(n),r):t},r.domain=function(t){return arguments.length?(n="function"==typeof t?t:L([t[0],t[1]]),r):n},r.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:L(Array.isArray(t)?Y.call(t):t),r):e},r}function tt(t,n){let e;if(void 0===n)for(const n of t)null!=n&&(e<n||void 0===e&&n>=n)&&(e=n);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(e<i||void 0===e&&i>=i)&&(e=i)}return e}function nt(t,n){let e,r=-1,i=-1;if(void 0===n)for(const n of t)++i,null!=n&&(e<n||void 0===e&&n>=n)&&(e=n,r=i);else for(let o of t)null!=(o=n(o,++i,t))&&(e<o||void 0===e&&o>=o)&&(e=o,r=i);return r}function et(t,n){let e;if(void 0===n)for(const n of t)null!=n&&(e>n||void 0===e&&n>=n)&&(e=n);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(e>i||void 0===e&&i>=i)&&(e=i)}return e}function rt(t,n){let e,r=-1,i=-1;if(void 0===n)for(const n of t)++i,null!=n&&(e>n||void 0===e&&n>=n)&&(e=n,r=i);else for(let o of t)null!=(o=n(o,++i,t))&&(e>o||void 0===e&&o>=o)&&(e=o,r=i);return r}function it(t,n,e=0,r=1/0,i){if(n=Math.floor(n),e=Math.floor(Math.max(0,e)),r=Math.floor(Math.min(t.length-1,r)),!(e<=n&&n<=r))return t;for(i=void 0===i?B:O(i);r>e;){if(r-e>600){const o=r-e+1,a=n-e+1,u=Math.log(o),c=.5*Math.exp(2*u/3),f=.5*Math.sqrt(u*c*(o-c)/o)*(a-o/2<0?-1:1);it(t,n,Math.max(e,Math.floor(n-a*c/o+f)),Math.min(r,Math.floor(n+(o-a)*c/o+f)),i)}const o=t[n];let a=e,u=r;for(ot(t,e,n),i(t[r],o)>0&&ot(t,e,r);a<u;){for(ot(t,a,u),++a,--u;i(t[a],o)<0;)++a;for(;i(t[u],o)>0;)--u}0===i(t[e],o)?ot(t,e,u):(++u,ot(t,u,r)),u<=n&&(e=u+1),n<=u&&(r=u-1)}return t}function ot(t,n,e){const r=t[n];t[n]=t[e],t[e]=r}function at(t,e=n){let r,i=!1;if(1===e.length){let o;for(const a of t){const t=e(a);(i?n(t,o)>0:0===n(t,t))&&(r=a,o=t,i=!0)}}else for(const n of t)(i?e(n,r)>0:0===e(n,n))&&(r=n,i=!0);return r}function ut(t,n,e){if((r=(t=Float64Array.from(a(t,e))).length)&&!isNaN(n=+n)){if(n<=0||r<2)return et(t);if(n>=1)return tt(t);var r,i=(r-1)*n,o=Math.floor(i),u=tt(it(t,o).subarray(0,o+1));return u+(et(t.subarray(o+1))-u)*(i-o)}}function ct(t,n,e=o){if((r=t.length)&&!isNaN(n=+n)){if(n<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,a=Math.floor(i),u=+e(t[a],a,t);return u+(+e(t[a+1],a+1,t)-u)*(i-a)}}function ft(t,n,e){if((r=(t=Float64Array.from(a(t,e))).length)&&!isNaN(n=+n)){if(n<=0||r<2)return rt(t);if(n>=1)return nt(t);var r,i=Math.floor((r-1)*n),o=it(Uint32Array.from(t,((t,n)=>n)),i,0,r-1,((n,e)=>B(t[n],t[e])));return at(o.subarray(0,i+1),(n=>t[n]))}}function st(t){return Array.from(function*(t){for(const n of t)yield*n}(t))}function lt(t,n){return[t,n]}function ht(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o}function dt(t,e=n){if(1===e.length)return rt(t,e);let r,i=-1,o=-1;for(const n of t)++o,(i<0?0===e(n,n):e(n,r)<0)&&(r=n,i=o);return i}var pt=gt(Math.random);function gt(t){return function(n,e=0,r=n.length){let i=r-(e=+e);for(;i;){const r=t()*i--|0,o=n[i+e];n[i+e]=n[r+e],n[r+e]=o}return n}}function yt(t){if(!(i=t.length))return[];for(var n=-1,e=et(t,vt),r=new Array(e);++n<e;)for(var i,o=-1,a=r[n]=new Array(i);++o<i;)a[o]=t[o][n];return r}function vt(t){return t.length}function _t(t){return t instanceof InternSet?t:new InternSet(t)}function bt(t,n){const e=t[Symbol.iterator](),r=new Set;for(const t of n){const n=mt(t);if(r.has(n))continue;let i,o;for(;({value:i,done:o}=e.next());){if(o)return!1;const t=mt(i);if(r.add(t),Object.is(n,t))break}}return!0}function mt(t){return null!==t&&"object"==typeof t?t.valueOf():t}function xt(t){return t}var wt=1,Mt=2,Tt=3,At=4,St=1e-6;function Et(t){return"translate("+t+",0)"}function Nt(t){return"translate(0,"+t+")"}function kt(t){return n=>+t(n)}function Ct(t,n){return n=Math.max(0,t.bandwidth()-2*n)/2,t.round()&&(n=Math.round(n)),e=>+t(e)+n}function Pt(){return!this.__axis}function zt(t,n){var e=[],r=null,i=null,o=6,a=6,u=3,c="undefined"!=typeof window&&window.devicePixelRatio>1?0:.5,f=t===wt||t===At?-1:1,s=t===At||t===Mt?"x":"y",l=t===wt||t===Tt?Et:Nt;function h(h){var d=null==r?n.ticks?n.ticks.apply(n,e):n.domain():r,p=null==i?n.tickFormat?n.tickFormat.apply(n,e):xt:i,g=Math.max(o,0)+u,y=n.range(),v=+y[0]+c,_=+y[y.length-1]+c,b=(n.bandwidth?Ct:kt)(n.copy(),c),m=h.selection?h.selection():h,x=m.selectAll(".domain").data([null]),w=m.selectAll(".tick").data(d,n).order(),M=w.exit(),T=w.enter().append("g").attr("class","tick"),A=w.select("line"),S=w.select("text");x=x.merge(x.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),w=w.merge(T),A=A.merge(T.append("line").attr("stroke","currentColor").attr(s+"2",f*o)),S=S.merge(T.append("text").attr("fill","currentColor").attr(s,f*g).attr("dy",t===wt?"0em":t===Tt?"0.71em":"0.32em")),h!==m&&(x=x.transition(h),w=w.transition(h),A=A.transition(h),S=S.transition(h),M=M.transition(h).attr("opacity",St).attr("transform",(function(t){return isFinite(t=b(t))?l(t+c):this.getAttribute("transform")})),T.attr("opacity",St).attr("transform",(function(t){var n=this.parentNode.__axis;return l((n&&isFinite(n=n(t))?n:b(t))+c)}))),M.remove(),x.attr("d",t===At||t===Mt?a?"M"+f*a+","+v+"H"+c+"V"+_+"H"+f*a:"M"+c+","+v+"V"+_:a?"M"+v+","+f*a+"V"+c+"H"+_+"V"+f*a:"M"+v+","+c+"H"+_),w.attr("opacity",1).attr("transform",(function(t){return l(b(t)+c)})),A.attr(s+"2",f*o),S.attr(s,f*g).text(p),m.filter(Pt).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===Mt?"start":t===At?"end":"middle"),m.each((function(){this.__axis=b}))}return h.scale=function(t){return arguments.length?(n=t,h):n},h.ticks=function(){return e=Array.from(arguments),h},h.tickArguments=function(t){return arguments.length?(e=null==t?[]:Array.from(t),h):e.slice()},h.tickValues=function(t){return arguments.length?(r=null==t?null:Array.from(t),h):r&&r.slice()},h.tickFormat=function(t){return arguments.length?(i=t,h):i},h.tickSize=function(t){return arguments.length?(o=a=+t,h):o},h.tickSizeInner=function(t){return arguments.length?(o=+t,h):o},h.tickSizeOuter=function(t){return arguments.length?(a=+t,h):a},h.tickPadding=function(t){return arguments.length?(u=+t,h):u},h.offset=function(t){return arguments.length?(c=+t,h):c},h}var $t={value:()=>{}};function Dt(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+"")||t in r||/[\s.]/.test(t))throw new Error("illegal type: "+t);r[t]=[]}return new Rt(r)}function Rt(t){this._=t}function Ft(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function qt(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=$t,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}Rt.prototype=Dt.prototype={constructor:Rt,on:function(t,n){var e,r,i=this._,o=(r=i,(t+"").trim().split(/^|\s+/).map((function(t){var n="",e=t.indexOf(".");if(e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),t&&!r.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}}))),a=-1,u=o.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++a<u;)if(e=(t=o[a]).type)i[e]=qt(i[e],t.name,n);else if(null==n)for(e in i)i[e]=qt(i[e],t.name,null);return this}for(;++a<u;)if((e=(t=o[a]).type)&&(e=Ft(i[e],t.name)))return e},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new Rt(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=0,e=(r=this._[t]).length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var Ut="http://www.w3.org/1999/xhtml",It={svg:"http://www.w3.org/2000/svg",xhtml:Ut,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function Ot(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),It.hasOwnProperty(n)?{space:It[n],local:t}:t}function Bt(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===Ut&&n.documentElement.namespaceURI===Ut?n.createElement(t):n.createElementNS(e,t)}}function Yt(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function Lt(t){var n=Ot(t);return(n.local?Yt:Bt)(n)}function jt(){}function Ht(t){return null==t?jt:function(){return this.querySelector(t)}}function Xt(t){return null==t?[]:Array.isArray(t)?t:Array.from(t)}function Gt(){return[]}function Vt(t){return null==t?Gt:function(){return this.querySelectorAll(t)}}function Wt(t){return function(){return this.matches(t)}}function Zt(t){return function(n){return n.matches(t)}}var Kt=Array.prototype.find;function Qt(){return this.firstElementChild}var Jt=Array.prototype.filter;function tn(){return Array.from(this.children)}function nn(t){return new Array(t.length)}function en(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function rn(t,n,e,r,i,o){for(var a,u=0,c=n.length,f=o.length;u<f;++u)(a=n[u])?(a.__data__=o[u],r[u]=a):e[u]=new en(t,o[u]);for(;u<c;++u)(a=n[u])&&(i[u]=a)}function on(t,n,e,r,i,o,a){var u,c,f,s=new Map,l=n.length,h=o.length,d=new Array(l);for(u=0;u<l;++u)(c=n[u])&&(d[u]=f=a.call(c,c.__data__,u,n)+"",s.has(f)?i[u]=c:s.set(f,c));for(u=0;u<h;++u)f=a.call(t,o[u],u,o)+"",(c=s.get(f))?(r[u]=c,c.__data__=o[u],s.delete(f)):e[u]=new en(t,o[u]);for(u=0;u<l;++u)(c=n[u])&&s.get(d[u])===c&&(i[u]=c)}function an(t){return t.__data__}function un(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}function cn(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function fn(t){return function(){this.removeAttribute(t)}}function sn(t){return function(){this.removeAttributeNS(t.space,t.local)}}function ln(t,n){return function(){this.setAttribute(t,n)}}function hn(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function dn(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function pn(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function gn(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function yn(t){return function(){this.style.removeProperty(t)}}function vn(t,n,e){return function(){this.style.setProperty(t,n,e)}}function _n(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function bn(t,n){return t.style.getPropertyValue(n)||gn(t).getComputedStyle(t,null).getPropertyValue(n)}function mn(t){return function(){delete this[t]}}function xn(t,n){return function(){this[t]=n}}function wn(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function Mn(t){return t.trim().split(/^|\s+/)}function Tn(t){return t.classList||new An(t)}function An(t){this._node=t,this._names=Mn(t.getAttribute("class")||"")}function Sn(t,n){for(var e=Tn(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function En(t,n){for(var e=Tn(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function Nn(t){return function(){Sn(this,t)}}function kn(t){return function(){En(this,t)}}function Cn(t,n){return function(){(n.apply(this,arguments)?Sn:En)(this,t)}}function Pn(){this.textContent=""}function zn(t){return function(){this.textContent=t}}function $n(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}}function Dn(){this.innerHTML=""}function Rn(t){return function(){this.innerHTML=t}}function Fn(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}}function qn(){this.nextSibling&&this.parentNode.appendChild(this)}function Un(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function In(){return null}function On(){var t=this.parentNode;t&&t.removeChild(this)}function Bn(){var t=this.cloneNode(!1),n=this.parentNode;return n?n.insertBefore(t,this.nextSibling):t}function Yn(){var t=this.cloneNode(!0),n=this.parentNode;return n?n.insertBefore(t,this.nextSibling):t}function Ln(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.options);++i?n.length=i:delete this.__on}}}function jn(t,n,e){return function(){var r,i=this.__on,o=function(t){return function(n){t.call(this,n,this.__data__)}}(n);if(i)for(var a=0,u=i.length;a<u;++a)if((r=i[a]).type===t.type&&r.name===t.name)return this.removeEventListener(r.type,r.listener,r.options),this.addEventListener(r.type,r.listener=o,r.options=e),void(r.value=n);this.addEventListener(t.type,o,e),r={type:t.type,name:t.name,value:n,listener:o,options:e},i?i.push(r):this.__on=[r]}}function Hn(t,n,e){var r=gn(t),i=r.CustomEvent;"function"==typeof i?i=new i(n,e):(i=r.document.createEvent("Event"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}function Xn(t,n){return function(){return Hn(this,t,n)}}function Gn(t,n){return function(){return Hn(this,t,n.apply(this,arguments))}}en.prototype={constructor:en,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}},An.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Vn=[null];function Wn(t,n){this._groups=t,this._parents=n}function Zn(){return new Wn([[document.documentElement]],Vn)}function Kn(t){return"string"==typeof t?new Wn([[document.querySelector(t)]],[document.documentElement]):new Wn([[t]],Vn)}Wn.prototype=Zn.prototype={constructor:Wn,select:function(t){"function"!=typeof t&&(t=Ht(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a,u=n[i],c=u.length,f=r[i]=new Array(c),s=0;s<c;++s)(o=u[s])&&(a=t.call(o,o.__data__,s,u))&&("__data__"in o&&(a.__data__=o.__data__),f[s]=a);return new Wn(r,this._parents)},selectAll:function(t){t="function"==typeof t?function(t){return function(){return Xt(t.apply(this,arguments))}}(t):Vt(t);for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var a,u=n[o],c=u.length,f=0;f<c;++f)(a=u[f])&&(r.push(t.call(a,a.__data__,f,u)),i.push(a));return new Wn(r,i)},selectChild:function(t){return this.select(null==t?Qt:function(t){return function(){return Kt.call(this.children,t)}}("function"==typeof t?t:Zt(t)))},selectChildren:function(t){return this.selectAll(null==t?tn:function(t){return function(){return Jt.call(this.children,t)}}("function"==typeof t?t:Zt(t)))},filter:function(t){"function"!=typeof t&&(t=Wt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,c=r[i]=[],f=0;f<u;++f)(o=a[f])&&t.call(o,o.__data__,f,a)&&c.push(o);return new Wn(r,this._parents)},data:function(t,n){if(!arguments.length)return Array.from(this,an);var e=n?on:rn,r=this._parents,i=this._groups;"function"!=typeof t&&(t=function(t){return function(){return t}}(t));for(var o=i.length,a=new Array(o),u=new Array(o),c=new Array(o),f=0;f<o;++f){var s=r[f],l=i[f],h=l.length,d=un(t.call(s,s&&s.__data__,f,r)),p=d.length,g=u[f]=new Array(p),y=a[f]=new Array(p);e(s,l,g,y,c[f]=new Array(h),d,n);for(var v,_,b=0,m=0;b<p;++b)if(v=g[b]){for(b>=m&&(m=b+1);!(_=y[m])&&++m<p;);v._next=_||null}}return(a=new Wn(a,r))._enter=u,a._exit=c,a},enter:function(){return new Wn(this._enter||this._groups.map(nn),this._parents)},exit:function(){return new Wn(this._exit||this._groups.map(nn),this._parents)},join:function(t,n,e){var r=this.enter(),i=this,o=this.exit();return"function"==typeof t?(r=t(r))&&(r=r.selection()):r=r.append(t+""),null!=n&&(i=n(i))&&(i=i.selection()),null==e?o.remove():e(o),r&&i?r.merge(i).order():i},merge:function(t){for(var n=t.selection?t.selection():t,e=this._groups,r=n._groups,i=e.length,o=r.length,a=Math.min(i,o),u=new Array(i),c=0;c<a;++c)for(var f,s=e[c],l=r[c],h=s.length,d=u[c]=new Array(h),p=0;p<h;++p)(f=s[p]||l[p])&&(d[p]=f);for(;c<i;++c)u[c]=e[c];return new Wn(u,this._parents)},selection:function(){return this},order:function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,a=i[o];--o>=0;)(r=i[o])&&(a&&4^r.compareDocumentPosition(a)&&a.parentNode.insertBefore(r,a),a=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=cn);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o<r;++o){for(var a,u=e[o],c=u.length,f=i[o]=new Array(c),s=0;s<c;++s)(a=u[s])&&(f[s]=a);f.sort(n)}return new Wn(i,this._parents).order()},call:function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},nodes:function(){return Array.from(this)},node:function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var a=r[i];if(a)return a}return null},size:function(){let t=0;for(const n of this)++t;return t},empty:function(){return!this.node()},each:function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],a=0,u=o.length;a<u;++a)(i=o[a])&&t.call(i,i.__data__,a,o);return this},attr:function(t,n){var e=Ot(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?sn:fn:"function"==typeof n?e.local?pn:dn:e.local?hn:ln)(e,n))},style:function(t,n,e){return arguments.length>1?this.each((null==n?yn:"function"==typeof n?_n:vn)(t,n,null==e?"":e)):bn(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?mn:"function"==typeof n?wn:xn)(t,n)):this.node()[t]},classed:function(t,n){var e=Mn(t+"");if(arguments.length<2){for(var r=Tn(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each(("function"==typeof n?Cn:n?Nn:kn)(e,n))},text:function(t){return arguments.length?this.each(null==t?Pn:("function"==typeof t?$n:zn)(t)):this.node().textContent},html:function(t){return arguments.length?this.each(null==t?Dn:("function"==typeof t?Fn:Rn)(t)):this.node().innerHTML},raise:function(){return this.each(qn)},lower:function(){return this.each(Un)},append:function(t){var n="function"==typeof t?t:Lt(t);return this.select((function(){return this.appendChild(n.apply(this,arguments))}))},insert:function(t,n){var e="function"==typeof t?t:Lt(t),r=null==n?In:"function"==typeof n?n:Ht(n);return this.select((function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)}))},remove:function(){return this.each(On)},clone:function(t){return this.select(t?Yn:Bn)},datum:function(t){return arguments.length?this.property("__data__",t):this.node().__data__},on:function(t,n,e){var r,i,o=function(t){return t.trim().split(/^|\s+/).map((function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}}))}(t+""),a=o.length;if(!(arguments.length<2)){for(u=n?jn:Ln,r=0;r<a;++r)this.each(u(o[r],n,e));return this}var u=this.node().__on;if(u)for(var c,f=0,s=u.length;f<s;++f)for(r=0,c=u[f];r<a;++r)if((i=o[r]).type===c.type&&i.name===c.name)return c.value},dispatch:function(t,n){return this.each(("function"==typeof n?Gn:Xn)(t,n))},[Symbol.iterator]:function*(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r,i=t[n],o=0,a=i.length;o<a;++o)(r=i[o])&&(yield r)}};var Qn=0;function Jn(){return new te}function te(){this._="@"+(++Qn).toString(36)}function ne(t){let n;for(;n=t.sourceEvent;)t=n;return t}function ee(t,n){if(t=ne(t),void 0===n&&(n=t.currentTarget),n){var e=n.ownerSVGElement||n;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=t.clientX,r.y=t.clientY,[(r=r.matrixTransform(n.getScreenCTM().inverse())).x,r.y]}if(n.getBoundingClientRect){var i=n.getBoundingClientRect();return[t.clientX-i.left-n.clientLeft,t.clientY-i.top-n.clientTop]}}return[t.pageX,t.pageY]}te.prototype=Jn.prototype={constructor:te,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}};const re={passive:!1},ie={capture:!0,passive:!1};function oe(t){t.stopImmediatePropagation()}function ae(t){t.preventDefault(),t.stopImmediatePropagation()}function ue(t){var n=t.document.documentElement,e=Kn(t).on("dragstart.drag",ae,ie);"onselectstart"in n?e.on("selectstart.drag",ae,ie):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect="none")}function ce(t,n){var e=t.document.documentElement,r=Kn(t).on("dragstart.drag",null);n&&(r.on("click.drag",ae,ie),setTimeout((function(){r.on("click.drag",null)}),0)),"onselectstart"in e?r.on("selectstart.drag",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}var fe=t=>()=>t;function se(t,{sourceEvent:n,subject:e,target:r,identifier:i,active:o,x:a,y:u,dx:c,dy:f,dispatch:s}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},subject:{value:e,enumerable:!0,configurable:!0},target:{value:r,enumerable:!0,configurable:!0},identifier:{value:i,enumerable:!0,configurable:!0},active:{value:o,enumerable:!0,configurable:!0},x:{value:a,enumerable:!0,configurable:!0},y:{value:u,enumerable:!0,configurable:!0},dx:{value:c,enumerable:!0,configurable:!0},dy:{value:f,enumerable:!0,configurable:!0},_:{value:s}})}function le(t){return!t.ctrlKey&&!t.button}function he(){return this.parentNode}function de(t,n){return null==n?{x:t.x,y:t.y}:n}function pe(){return navigator.maxTouchPoints||"ontouchstart"in this}function ge(t,n,e){t.prototype=n.prototype=e,e.constructor=t}function ye(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function ve(){}se.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var _e=.7,be=1/_e,me="\\s*([+-]?\\d+)\\s*",xe="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)\\s*",we="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)%\\s*",Me=/^#([0-9a-f]{3,8})$/,Te=new RegExp(`^rgb\\(${me},${me},${me}\\)$`),Ae=new RegExp(`^rgb\\(${we},${we},${we}\\)$`),Se=new RegExp(`^rgba\\(${me},${me},${me},${xe}\\)$`),Ee=new RegExp(`^rgba\\(${we},${we},${we},${xe}\\)$`),Ne=new RegExp(`^hsl\\(${xe},${we},${we}\\)$`),ke=new RegExp(`^hsla\\(${xe},${we},${we},${xe}\\)$`),Ce={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};function Pe(){return this.rgb().formatHex()}function ze(){return this.rgb().formatRgb()}function $e(t){var n,e;return t=(t+"").trim().toLowerCase(),(n=Me.exec(t))?(e=n[1].length,n=parseInt(n[1],16),6===e?De(n):3===e?new Ue(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):8===e?Re(n>>24&255,n>>16&255,n>>8&255,(255&n)/255):4===e?Re(n>>12&15|n>>8&240,n>>8&15|n>>4&240,n>>4&15|240&n,((15&n)<<4|15&n)/255):null):(n=Te.exec(t))?new Ue(n[1],n[2],n[3],1):(n=Ae.exec(t))?new Ue(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Se.exec(t))?Re(n[1],n[2],n[3],n[4]):(n=Ee.exec(t))?Re(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Ne.exec(t))?je(n[1],n[2]/100,n[3]/100,1):(n=ke.exec(t))?je(n[1],n[2]/100,n[3]/100,n[4]):Ce.hasOwnProperty(t)?De(Ce[t]):"transparent"===t?new Ue(NaN,NaN,NaN,0):null}function De(t){return new Ue(t>>16&255,t>>8&255,255&t,1)}function Re(t,n,e,r){return r<=0&&(t=n=e=NaN),new Ue(t,n,e,r)}function Fe(t){return t instanceof ve||(t=$e(t)),t?new Ue((t=t.rgb()).r,t.g,t.b,t.opacity):new Ue}function qe(t,n,e,r){return 1===arguments.length?Fe(t):new Ue(t,n,e,null==r?1:r)}function Ue(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Ie(){return`#${Le(this.r)}${Le(this.g)}${Le(this.b)}`}function Oe(){const t=Be(this.opacity);return`${1===t?"rgb(":"rgba("}${Ye(this.r)}, ${Ye(this.g)}, ${Ye(this.b)}${1===t?")":`, ${t})`}`}function Be(t){return isNaN(t)?1:Math.max(0,Math.min(1,t))}function Ye(t){return Math.max(0,Math.min(255,Math.round(t)||0))}function Le(t){return((t=Ye(t))<16?"0":"")+t.toString(16)}function je(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Ge(t,n,e,r)}function He(t){if(t instanceof Ge)return new Ge(t.h,t.s,t.l,t.opacity);if(t instanceof ve||(t=$e(t)),!t)return new Ge;if(t instanceof Ge)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),a=NaN,u=o-i,c=(o+i)/2;return u?(a=n===o?(e-r)/u+6*(e<r):e===o?(r-n)/u+2:(n-e)/u+4,u/=c<.5?o+i:2-o-i,a*=60):u=c>0&&c<1?0:a,new Ge(a,u,c,t.opacity)}function Xe(t,n,e,r){return 1===arguments.length?He(t):new Ge(t,n,e,null==r?1:r)}function Ge(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Ve(t){return(t=(t||0)%360)<0?t+360:t}function We(t){return Math.max(0,Math.min(1,t||0))}function Ze(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}ge(ve,$e,{copy(t){return Object.assign(new this.constructor,this,t)},displayable(){return this.rgb().displayable()},hex:Pe,formatHex:Pe,formatHex8:function(){return this.rgb().formatHex8()},formatHsl:function(){return He(this).formatHsl()},formatRgb:ze,toString:ze}),ge(Ue,qe,ye(ve,{brighter(t){return t=null==t?be:Math.pow(be,t),new Ue(this.r*t,this.g*t,this.b*t,this.opacity)},darker(t){return t=null==t?_e:Math.pow(_e,t),new Ue(this.r*t,this.g*t,this.b*t,this.opacity)},rgb(){return this},clamp(){return new Ue(Ye(this.r),Ye(this.g),Ye(this.b),Be(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Ie,formatHex:Ie,formatHex8:function(){return`#${Le(this.r)}${Le(this.g)}${Le(this.b)}${Le(255*(isNaN(this.opacity)?1:this.opacity))}`},formatRgb:Oe,toString:Oe})),ge(Ge,Xe,ye(ve,{brighter(t){return t=null==t?be:Math.pow(be,t),new Ge(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=null==t?_e:Math.pow(_e,t),new Ge(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new Ue(Ze(t>=240?t-240:t+120,i,r),Ze(t,i,r),Ze(t<120?t+240:t-120,i,r),this.opacity)},clamp(){return new Ge(Ve(this.h),We(this.s),We(this.l),Be(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){const t=Be(this.opacity);return`${1===t?"hsl(":"hsla("}${Ve(this.h)}, ${100*We(this.s)}%, ${100*We(this.l)}%${1===t?")":`, ${t})`}`}}));const Ke=Math.PI/180,Qe=180/Math.PI,Je=.96422,tr=1,nr=.82521,er=4/29,rr=6/29,ir=3*rr*rr,or=rr*rr*rr;function ar(t){if(t instanceof cr)return new cr(t.l,t.a,t.b,t.opacity);if(t instanceof gr)return yr(t);t instanceof Ue||(t=Fe(t));var n,e,r=hr(t.r),i=hr(t.g),o=hr(t.b),a=fr((.2225045*r+.7168786*i+.0606169*o)/tr);return r===i&&i===o?n=e=a:(n=fr((.4360747*r+.3850649*i+.1430804*o)/Je),e=fr((.0139322*r+.0971045*i+.7141733*o)/nr)),new cr(116*a-16,500*(n-a),200*(a-e),t.opacity)}function ur(t,n,e,r){return 1===arguments.length?ar(t):new cr(t,n,e,null==r?1:r)}function cr(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function fr(t){return t>or?Math.pow(t,1/3):t/ir+er}function sr(t){return t>rr?t*t*t:ir*(t-er)}function lr(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function hr(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function dr(t){if(t instanceof gr)return new gr(t.h,t.c,t.l,t.opacity);if(t instanceof cr||(t=ar(t)),0===t.a&&0===t.b)return new gr(NaN,0<t.l&&t.l<100?0:NaN,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*Qe;return new gr(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function pr(t,n,e,r){return 1===arguments.length?dr(t):new gr(t,n,e,null==r?1:r)}function gr(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}function yr(t){if(isNaN(t.h))return new cr(t.l,0,0,t.opacity);var n=t.h*Ke;return new cr(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}ge(cr,ur,ye(ve,{brighter(t){return new cr(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker(t){return new cr(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new Ue(lr(3.1338561*(n=Je*sr(n))-1.6168667*(t=tr*sr(t))-.4906146*(e=nr*sr(e))),lr(-.9787684*n+1.9161415*t+.033454*e),lr(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),ge(gr,pr,ye(ve,{brighter(t){return new gr(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker(t){return new gr(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb(){return yr(this).rgb()}}));var vr=-.14861,_r=1.78277,br=-.29227,mr=-.90649,xr=1.97294,wr=xr*mr,Mr=xr*_r,Tr=_r*br-mr*vr;function Ar(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof Sr)return new Sr(t.h,t.s,t.l,t.opacity);t instanceof Ue||(t=Fe(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(Tr*r+wr*n-Mr*e)/(Tr+wr-Mr),o=r-i,a=(xr*(e-i)-br*o)/mr,u=Math.sqrt(a*a+o*o)/(xr*i*(1-i)),c=u?Math.atan2(a,o)*Qe-120:NaN;return new Sr(c<0?c+360:c,u,i,t.opacity)}(t):new Sr(t,n,e,null==r?1:r)}function Sr(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Er(t,n,e,r,i){var o=t*t,a=o*t;return((1-3*t+3*o-a)*n+(4-6*o+3*a)*e+(1+3*t+3*o-3*a)*r+a*i)/6}function Nr(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],a=r>0?t[r-1]:2*i-o,u=r<n-1?t[r+2]:2*o-i;return Er((e-r/n)*n,a,i,o,u)}}function kr(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],a=t[(r+1)%n],u=t[(r+2)%n];return Er((e-r/n)*n,i,o,a,u)}}ge(Sr,Ar,ye(ve,{brighter(t){return t=null==t?be:Math.pow(be,t),new Sr(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=null==t?_e:Math.pow(_e,t),new Sr(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=isNaN(this.h)?0:(this.h+120)*Ke,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new Ue(255*(n+e*(vr*r+_r*i)),255*(n+e*(br*r+mr*i)),255*(n+e*(xr*r)),this.opacity)}}));var Cr=t=>()=>t;function Pr(t,n){return function(e){return t+e*n}}function zr(t,n){var e=n-t;return e?Pr(t,e>180||e<-180?e-360*Math.round(e/360):e):Cr(isNaN(t)?n:t)}function $r(t){return 1==(t=+t)?Dr:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):Cr(isNaN(n)?e:n)}}function Dr(t,n){var e=n-t;return e?Pr(t,e):Cr(isNaN(t)?n:t)}var Rr=function t(n){var e=$r(n);function r(t,n){var r=e((t=qe(t)).r,(n=qe(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),a=Dr(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=a(n),t+""}}return r.gamma=t,r}(1);function Fr(t){return function(n){var e,r,i=n.length,o=new Array(i),a=new Array(i),u=new Array(i);for(e=0;e<i;++e)r=qe(n[e]),o[e]=r.r||0,a[e]=r.g||0,u[e]=r.b||0;return o=t(o),a=t(a),u=t(u),r.opacity=1,function(t){return r.r=o(t),r.g=a(t),r.b=u(t),r+""}}}var qr=Fr(Nr),Ur=Fr(kr);function Ir(t,n){n||(n=[]);var e,r=t?Math.min(n.length,t.length):0,i=n.slice();return function(o){for(e=0;e<r;++e)i[e]=t[e]*(1-o)+n[e]*o;return i}}function Or(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)}function Br(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(i),a=new Array(r);for(e=0;e<i;++e)o[e]=Vr(t[e],n[e]);for(;e<r;++e)a[e]=n[e];return function(t){for(e=0;e<i;++e)a[e]=o[e](t);return a}}function Yr(t,n){var e=new Date;return t=+t,n=+n,function(r){return e.setTime(t*(1-r)+n*r),e}}function Lr(t,n){return t=+t,n=+n,function(e){return t*(1-e)+n*e}}function jr(t,n){var e,r={},i={};for(e in null!==t&&"object"==typeof t||(t={}),null!==n&&"object"==typeof n||(n={}),n)e in t?r[e]=Vr(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}}var Hr=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,Xr=new RegExp(Hr.source,"g");function Gr(t,n){var e,r,i,o=Hr.lastIndex=Xr.lastIndex=0,a=-1,u=[],c=[];for(t+="",n+="";(e=Hr.exec(t))&&(r=Xr.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(e=e[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,c.push({i:a,x:Lr(e,r)})),o=Xr.lastIndex;return o<n.length&&(i=n.slice(o),u[a]?u[a]+=i:u[++a]=i),u.length<2?c[0]?function(t){return function(n){return t(n)+""}}(c[0].x):function(t){return function(){return t}}(n):(n=c.length,function(t){for(var e,r=0;r<n;++r)u[(e=c[r]).i]=e.x(t);return u.join("")})}function Vr(t,n){var e,r=typeof n;return null==n||"boolean"===r?Cr(n):("number"===r?Lr:"string"===r?(e=$e(n))?(n=e,Rr):Gr:n instanceof $e?Rr:n instanceof Date?Yr:Or(n)?Ir:Array.isArray(n)?Br:"function"!=typeof n.valueOf&&"function"!=typeof n.toString||isNaN(n)?jr:Lr)(t,n)}function Wr(t,n){return t=+t,n=+n,function(e){return Math.round(t*(1-e)+n*e)}}var Zr,Kr=180/Math.PI,Qr={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function Jr(t,n,e,r,i,o){var a,u,c;return(a=Math.sqrt(t*t+n*n))&&(t/=a,n/=a),(c=t*e+n*r)&&(e-=t*c,r-=n*c),(u=Math.sqrt(e*e+r*r))&&(e/=u,r/=u,c/=u),t*r<n*e&&(t=-t,n=-n,c=-c,a=-a),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*Kr,skewX:Math.atan(c)*Kr,scaleX:a,scaleY:u}}function ti(t,n,e,r){function i(t){return t.length?t.pop()+" ":""}return function(o,a){var u=[],c=[];return o=t(o),a=t(a),function(t,r,i,o,a,u){if(t!==i||r!==o){var c=a.push("translate(",null,n,null,e);u.push({i:c-4,x:Lr(t,i)},{i:c-2,x:Lr(r,o)})}else(i||o)&&a.push("translate("+i+n+o+e)}(o.translateX,o.translateY,a.translateX,a.translateY,u,c),function(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:Lr(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,a.rotate,u,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:Lr(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,a.skewX,u,c),function(t,n,e,r,o,a){if(t!==e||n!==r){var u=o.push(i(o)+"scale(",null,",",null,")");a.push({i:u-4,x:Lr(t,e)},{i:u-2,x:Lr(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,a.scaleX,a.scaleY,u,c),o=a=null,function(t){for(var n,e=-1,r=c.length;++e<r;)u[(n=c[e]).i]=n.x(t);return u.join("")}}}var ni=ti((function(t){const n=new("function"==typeof DOMMatrix?DOMMatrix:WebKitCSSMatrix)(t+"");return n.isIdentity?Qr:Jr(n.a,n.b,n.c,n.d,n.e,n.f)}),"px, ","px)","deg)"),ei=ti((function(t){return null==t?Qr:(Zr||(Zr=document.createElementNS("http://www.w3.org/2000/svg","g")),Zr.setAttribute("transform",t),(t=Zr.transform.baseVal.consolidate())?Jr((t=t.matrix).a,t.b,t.c,t.d,t.e,t.f):Qr)}),", ",")",")");function ri(t){return((t=Math.exp(t))+1/t)/2}var ii=function t(n,e,r){function i(t,i){var o,a,u=t[0],c=t[1],f=t[2],s=i[0],l=i[1],h=i[2],d=s-u,p=l-c,g=d*d+p*p;if(g<1e-12)a=Math.log(h/f)/n,o=function(t){return[u+t*d,c+t*p,f*Math.exp(n*t*a)]};else{var y=Math.sqrt(g),v=(h*h-f*f+r*g)/(2*f*e*y),_=(h*h-f*f-r*g)/(2*h*e*y),b=Math.log(Math.sqrt(v*v+1)-v),m=Math.log(Math.sqrt(_*_+1)-_);a=(m-b)/n,o=function(t){var r=t*a,i=ri(b),o=f/(e*y)*(i*function(t){return((t=Math.exp(2*t))-1)/(t+1)}(n*r+b)-function(t){return((t=Math.exp(t))-1/t)/2}(b));return[u+o*d,c+o*p,f*i/ri(n*r+b)]}}return o.duration=1e3*a*n/Math.SQRT2,o}return i.rho=function(n){var e=Math.max(.001,+n),r=e*e;return t(e,r,r*r)},i}(Math.SQRT2,2,4);function oi(t){return function(n,e){var r=t((n=Xe(n)).h,(e=Xe(e)).h),i=Dr(n.s,e.s),o=Dr(n.l,e.l),a=Dr(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var ai=oi(zr),ui=oi(Dr);function ci(t){return function(n,e){var r=t((n=pr(n)).h,(e=pr(e)).h),i=Dr(n.c,e.c),o=Dr(n.l,e.l),a=Dr(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var fi=ci(zr),si=ci(Dr);function li(t){return function n(e){function r(n,r){var i=t((n=Ar(n)).h,(r=Ar(r)).h),o=Dr(n.s,r.s),a=Dr(n.l,r.l),u=Dr(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=a(Math.pow(t,e)),n.opacity=u(t),n+""}}return e=+e,r.gamma=n,r}(1)}var hi=li(zr),di=li(Dr);function pi(t,n){void 0===n&&(n=t,t=Vr);for(var e=0,r=n.length-1,i=n[0],o=new Array(r<0?0:r);e<r;)o[e]=t(i,i=n[++e]);return function(t){var n=Math.max(0,Math.min(r-1,Math.floor(t*=r)));return o[n](t-n)}}var gi,yi,vi=0,_i=0,bi=0,mi=1e3,xi=0,wi=0,Mi=0,Ti="object"==typeof performance&&performance.now?performance:Date,Ai="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function Si(){return wi||(Ai(Ei),wi=Ti.now()+Mi)}function Ei(){wi=0}function Ni(){this._call=this._time=this._next=null}function ki(t,n,e){var r=new Ni;return r.restart(t,n,e),r}function Ci(){Si(),++vi;for(var t,n=gi;n;)(t=wi-n._time)>=0&&n._call.call(void 0,t),n=n._next;--vi}function Pi(){wi=(xi=Ti.now())+Mi,vi=_i=0;try{Ci()}finally{vi=0,function(){var t,n,e=gi,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:gi=n);yi=t,$i(r)}(),wi=0}}function zi(){var t=Ti.now(),n=t-xi;n>mi&&(Mi-=n,xi=t)}function $i(t){vi||(_i&&(_i=clearTimeout(_i)),t-wi>24?(t<1/0&&(_i=setTimeout(Pi,t-Ti.now()-Mi)),bi&&(bi=clearInterval(bi))):(bi||(xi=Ti.now(),bi=setInterval(zi,mi)),vi=1,Ai(Pi)))}function Di(t,n,e){var r=new Ni;return n=null==n?0:+n,r.restart((e=>{r.stop(),t(e+n)}),n,e),r}Ni.prototype=ki.prototype={constructor:Ni,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?Si():+e)+(null==n?0:+n),this._next||yi===this||(yi?yi._next=this:gi=this,yi=this),this._call=t,this._time=e,$i()},stop:function(){this._call&&(this._call=null,this._time=1/0,$i())}};var Ri=Dt("start","end","cancel","interrupt"),Fi=[],qi=0,Ui=1,Ii=2,Oi=3,Bi=4,Yi=5,Li=6;function ji(t,n,e,r,i,o){var a=t.__transition;if(a){if(e in a)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(t){e.state=Ui,e.timer.restart(a,e.delay,e.time),e.delay<=t&&a(t-e.delay)}function a(o){var f,s,l,h;if(e.state!==Ui)return c();for(f in i)if((h=i[f]).name===e.name){if(h.state===Oi)return Di(a);h.state===Bi?(h.state=Li,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[f]):+f<n&&(h.state=Li,h.timer.stop(),h.on.call("cancel",t,t.__data__,h.index,h.group),delete i[f])}if(Di((function(){e.state===Oi&&(e.state=Bi,e.timer.restart(u,e.delay,e.time),u(o))})),e.state=Ii,e.on.call("start",t,t.__data__,e.index,e.group),e.state===Ii){for(e.state=Oi,r=new Array(l=e.tween.length),f=0,s=-1;f<l;++f)(h=e.tween[f].value.call(t,t.__data__,e.index,e.group))&&(r[++s]=h);r.length=s+1}}function u(n){for(var i=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(c),e.state=Yi,1),o=-1,a=r.length;++o<a;)r[o].call(t,i);e.state===Yi&&(e.on.call("end",t,t.__data__,e.index,e.group),c())}function c(){for(var r in e.state=Li,e.timer.stop(),delete i[n],i)return;delete t.__transition}i[n]=e,e.timer=ki(o,0,e.time)}(t,e,{name:n,index:r,group:i,on:Ri,tween:Fi,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:qi})}function Hi(t,n){var e=Gi(t,n);if(e.state>qi)throw new Error("too late; already scheduled");return e}function Xi(t,n){var e=Gi(t,n);if(e.state>Oi)throw new Error("too late; already running");return e}function Gi(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}function Vi(t,n){var e,r,i,o=t.__transition,a=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>Ii&&e.state<Yi,e.state=Li,e.timer.stop(),e.on.call(r?"interrupt":"cancel",t,t.__data__,e.index,e.group),delete o[i]):a=!1;a&&delete t.__transition}}function Wi(t,n){var e,r;return function(){var i=Xi(this,t),o=i.tween;if(o!==e)for(var a=0,u=(r=e=o).length;a<u;++a)if(r[a].name===n){(r=r.slice()).splice(a,1);break}i.tween=r}}function Zi(t,n,e){var r,i;if("function"!=typeof e)throw new Error;return function(){var o=Xi(this,t),a=o.tween;if(a!==r){i=(r=a).slice();for(var u={name:n,value:e},c=0,f=i.length;c<f;++c)if(i[c].name===n){i[c]=u;break}c===f&&i.push(u)}o.tween=i}}function Ki(t,n,e){var r=t._id;return t.each((function(){var t=Xi(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)})),function(t){return Gi(t,r).value[n]}}function Qi(t,n){var e;return("number"==typeof n?Lr:n instanceof $e?Rr:(e=$e(n))?(n=e,Rr):Gr)(t,n)}function Ji(t){return function(){this.removeAttribute(t)}}function to(t){return function(){this.removeAttributeNS(t.space,t.local)}}function no(t,n,e){var r,i,o=e+"";return function(){var a=this.getAttribute(t);return a===o?null:a===r?i:i=n(r=a,e)}}function eo(t,n,e){var r,i,o=e+"";return function(){var a=this.getAttributeNS(t.space,t.local);return a===o?null:a===r?i:i=n(r=a,e)}}function ro(t,n,e){var r,i,o;return function(){var a,u,c=e(this);if(null!=c)return(a=this.getAttribute(t))===(u=c+"")?null:a===r&&u===i?o:(i=u,o=n(r=a,c));this.removeAttribute(t)}}function io(t,n,e){var r,i,o;return function(){var a,u,c=e(this);if(null!=c)return(a=this.getAttributeNS(t.space,t.local))===(u=c+"")?null:a===r&&u===i?o:(i=u,o=n(r=a,c));this.removeAttributeNS(t.space,t.local)}}function oo(t,n){var e,r;function i(){var i=n.apply(this,arguments);return i!==r&&(e=(r=i)&&function(t,n){return function(e){this.setAttributeNS(t.space,t.local,n.call(this,e))}}(t,i)),e}return i._value=n,i}function ao(t,n){var e,r;function i(){var i=n.apply(this,arguments);return i!==r&&(e=(r=i)&&function(t,n){return function(e){this.setAttribute(t,n.call(this,e))}}(t,i)),e}return i._value=n,i}function uo(t,n){return function(){Hi(this,t).delay=+n.apply(this,arguments)}}function co(t,n){return n=+n,function(){Hi(this,t).delay=n}}function fo(t,n){return function(){Xi(this,t).duration=+n.apply(this,arguments)}}function so(t,n){return n=+n,function(){Xi(this,t).duration=n}}var lo=Zn.prototype.constructor;function ho(t){return function(){this.style.removeProperty(t)}}var po=0;function go(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function yo(t){return Zn().transition(t)}function vo(){return++po}var _o=Zn.prototype;go.prototype=yo.prototype={constructor:go,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=Ht(t));for(var r=this._groups,i=r.length,o=new Array(i),a=0;a<i;++a)for(var u,c,f=r[a],s=f.length,l=o[a]=new Array(s),h=0;h<s;++h)(u=f[h])&&(c=t.call(u,u.__data__,h,f))&&("__data__"in u&&(c.__data__=u.__data__),l[h]=c,ji(l[h],n,e,h,l,Gi(u,e)));return new go(o,this._parents,n,e)},selectAll:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=Vt(t));for(var r=this._groups,i=r.length,o=[],a=[],u=0;u<i;++u)for(var c,f=r[u],s=f.length,l=0;l<s;++l)if(c=f[l]){for(var h,d=t.call(c,c.__data__,l,f),p=Gi(c,e),g=0,y=d.length;g<y;++g)(h=d[g])&&ji(h,n,e,g,d,p);o.push(d),a.push(c)}return new go(o,a,n,e)},selectChild:_o.selectChild,selectChildren:_o.selectChildren,filter:function(t){"function"!=typeof t&&(t=Wt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,c=r[i]=[],f=0;f<u;++f)(o=a[f])&&t.call(o,o.__data__,f,a)&&c.push(o);return new go(r,this._parents,this._name,this._id)},merge:function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),a=new Array(r),u=0;u<o;++u)for(var c,f=n[u],s=e[u],l=f.length,h=a[u]=new Array(l),d=0;d<l;++d)(c=f[d]||s[d])&&(h[d]=c);for(;u<r;++u)a[u]=n[u];return new go(a,this._parents,this._name,this._id)},selection:function(){return new lo(this._groups,this._parents)},transition:function(){for(var t=this._name,n=this._id,e=vo(),r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],c=u.length,f=0;f<c;++f)if(a=u[f]){var s=Gi(a,n);ji(a,t,e,f,u,{time:s.time+s.delay+s.duration,delay:0,duration:s.duration,ease:s.ease})}return new go(r,this._parents,t,e)},call:_o.call,nodes:_o.nodes,node:_o.node,size:_o.size,empty:_o.empty,each:_o.each,on:function(t,n){var e=this._id;return arguments.length<2?Gi(this.node(),e).on.on(t):this.each(function(t,n,e){var r,i,o=function(t){return(t+"").trim().split(/^|\s+/).every((function(t){var n=t.indexOf(".");return n>=0&&(t=t.slice(0,n)),!t||"start"===t}))}(n)?Hi:Xi;return function(){var a=o(this,t),u=a.on;u!==r&&(i=(r=u).copy()).on(n,e),a.on=i}}(e,t,n))},attr:function(t,n){var e=Ot(t),r="transform"===e?ei:Qi;return this.attrTween(t,"function"==typeof n?(e.local?io:ro)(e,r,Ki(this,"attr."+t,n)):null==n?(e.local?to:Ji)(e):(e.local?eo:no)(e,r,n))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=Ot(t);return this.tween(e,(r.local?oo:ao)(r,n))},style:function(t,n,e){var r="transform"==(t+="")?ni:Qi;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=bn(this,t),a=(this.style.removeProperty(t),bn(this,t));return o===a?null:o===e&&a===r?i:i=n(e=o,r=a)}}(t,r)).on("end.style."+t,ho(t)):"function"==typeof n?this.styleTween(t,function(t,n,e){var r,i,o;return function(){var a=bn(this,t),u=e(this),c=u+"";return null==u&&(this.style.removeProperty(t),c=u=bn(this,t)),a===c?null:a===r&&c===i?o:(i=c,o=n(r=a,u))}}(t,r,Ki(this,"style."+t,n))).each(function(t,n){var e,r,i,o,a="style."+n,u="end."+a;return function(){var c=Xi(this,t),f=c.on,s=null==c.value[a]?o||(o=ho(n)):void 0;f===e&&i===s||(r=(e=f).copy()).on(u,i=s),c.on=r}}(this._id,t)):this.styleTween(t,function(t,n,e){var r,i,o=e+"";return function(){var a=bn(this,t);return a===o?null:a===r?i:i=n(r=a,e)}}(t,r,n),e).on("end.style."+t,null)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){var r,i;function o(){var o=n.apply(this,arguments);return o!==i&&(r=(i=o)&&function(t,n,e){return function(r){this.style.setProperty(t,n.call(this,r),e)}}(t,o,e)),r}return o._value=n,o}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(Ki(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},textTween:function(t){var n="text";if(arguments.length<1)return(n=this.tween(n))&&n._value;if(null==t)return this.tween(n,null);if("function"!=typeof t)throw new Error;return this.tween(n,function(t){var n,e;function r(){var r=t.apply(this,arguments);return r!==e&&(n=(e=r)&&function(t){return function(n){this.textContent=t.call(this,n)}}(r)),n}return r._value=t,r}(t))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=Gi(this.node(),e).tween,o=0,a=i.length;o<a;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?Wi:Zi)(e,t,n))},delay:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?uo:co)(n,t)):Gi(this.node(),n).delay},duration:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?fo:so)(n,t)):Gi(this.node(),n).duration},ease:function(t){var n=this._id;return arguments.length?this.each(function(t,n){if("function"!=typeof n)throw new Error;return function(){Xi(this,t).ease=n}}(n,t)):Gi(this.node(),n).ease},easeVarying:function(t){if("function"!=typeof t)throw new Error;return this.each(function(t,n){return function(){var e=n.apply(this,arguments);if("function"!=typeof e)throw new Error;Xi(this,t).ease=e}}(this._id,t))},end:function(){var t,n,e=this,r=e._id,i=e.size();return new Promise((function(o,a){var u={value:a},c={value:function(){0==--i&&o()}};e.each((function(){var e=Xi(this,r),i=e.on;i!==t&&((n=(t=i).copy())._.cancel.push(u),n._.interrupt.push(u),n._.end.push(c)),e.on=n})),0===i&&o()}))},[Symbol.iterator]:_o[Symbol.iterator]};function bo(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function mo(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}var xo=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(3),wo=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(3),Mo=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(3),To=Math.PI,Ao=To/2;function So(t){return(1-Math.cos(To*t))/2}function Eo(t){return 1.0009775171065494*(Math.pow(2,-10*t)-.0009765625)}function No(t){return((t*=2)<=1?Eo(1-t):2-Eo(t-1))/2}function ko(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}var Co=4/11,Po=6/11,zo=8/11,$o=3/4,Do=9/11,Ro=10/11,Fo=15/16,qo=21/22,Uo=63/64,Io=1/Co/Co;function Oo(t){return(t=+t)<Co?Io*t*t:t<zo?Io*(t-=Po)*t+$o:t<Ro?Io*(t-=Do)*t+Fo:Io*(t-=qo)*t+Uo}var Bo=1.70158,Yo=function t(n){function e(t){return(t=+t)*t*(n*(t-1)+t)}return n=+n,e.overshoot=t,e}(Bo),Lo=function t(n){function e(t){return--t*t*((t+1)*n+t)+1}return n=+n,e.overshoot=t,e}(Bo),jo=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(Bo),Ho=2*Math.PI,Xo=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=Ho);function i(t){return n*Eo(- --t)*Math.sin((r-t)/e)}return i.amplitude=function(n){return t(n,e*Ho)},i.period=function(e){return t(n,e)},i}(1,.3),Go=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=Ho);function i(t){return 1-n*Eo(t=+t)*Math.sin((t+r)/e)}return i.amplitude=function(n){return t(n,e*Ho)},i.period=function(e){return t(n,e)},i}(1,.3),Vo=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=Ho);function i(t){return((t=2*t-1)<0?n*Eo(-t)*Math.sin((r-t)/e):2-n*Eo(t)*Math.sin((r+t)/e))/2}return i.amplitude=function(n){return t(n,e*Ho)},i.period=function(e){return t(n,e)},i}(1,.3),Wo={time:null,delay:0,duration:250,ease:mo};function Zo(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))throw new Error(`transition ${n} not found`);return e}Zn.prototype.interrupt=function(t){return this.each((function(){Vi(this,t)}))},Zn.prototype.transition=function(t){var n,e;t instanceof go?(n=t._id,t=t._name):(n=vo(),(e=Wo).time=Si(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],c=u.length,f=0;f<c;++f)(a=u[f])&&ji(a,t,n,f,u,e||Zo(a,n));return new go(r,this._parents,t,n)};var Ko=[null];var Qo=t=>()=>t;function Jo(t,{sourceEvent:n,target:e,selection:r,mode:i,dispatch:o}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},target:{value:e,enumerable:!0,configurable:!0},selection:{value:r,enumerable:!0,configurable:!0},mode:{value:i,enumerable:!0,configurable:!0},_:{value:o}})}function ta(t){t.preventDefault(),t.stopImmediatePropagation()}var na={name:"drag"},ea={name:"space"},ra={name:"handle"},ia={name:"center"};const{abs:oa,max:aa,min:ua}=Math;function ca(t){return[+t[0],+t[1]]}function fa(t){return[ca(t[0]),ca(t[1])]}var sa={name:"x",handles:["w","e"].map(_a),input:function(t,n){return null==t?null:[[+t[0],n[0][1]],[+t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},la={name:"y",handles:["n","s"].map(_a),input:function(t,n){return null==t?null:[[n[0][0],+t[0]],[n[1][0],+t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},ha={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(_a),input:function(t){return null==t?null:fa(t)},output:function(t){return t}},da={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},pa={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},ga={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},ya={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},va={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function _a(t){return{type:t}}function ba(t){return!t.ctrlKey&&!t.button}function ma(){var t=this.ownerSVGElement||this;return t.hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function xa(){return navigator.maxTouchPoints||"ontouchstart"in this}function wa(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function Ma(t){var n,e=ma,r=ba,i=xa,o=!0,a=Dt("start","brush","end"),u=6;function c(n){var e=n.property("__brush",g).selectAll(".overlay").data([_a("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",da.overlay).merge(e).each((function(){var t=wa(this).extent;Kn(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])})),n.selectAll(".selection").data([_a("selection")]).enter().append("rect").attr("class","selection").attr("cursor",da.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var r=n.selectAll(".handle").data(t.handles,(function(t){return t.type}));r.exit().remove(),r.enter().append("rect").attr("class",(function(t){return"handle handle--"+t.type})).attr("cursor",(function(t){return da[t.type]})),n.each(f).attr("fill","none").attr("pointer-events","all").on("mousedown.brush",h).filter(i).on("touchstart.brush",h).on("touchmove.brush",d).on("touchend.brush touchcancel.brush",p).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function f(){var t=Kn(this),n=wa(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",(function(t){return"e"===t.type[t.type.length-1]?n[1][0]-u/2:n[0][0]-u/2})).attr("y",(function(t){return"s"===t.type[0]?n[1][1]-u/2:n[0][1]-u/2})).attr("width",(function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+u:u})).attr("height",(function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+u:u}))):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function s(t,n,e){var r=t.__brush.emitter;return!r||e&&r.clean?new l(t,n,e):r}function l(t,n,e){this.that=t,this.args=n,this.state=t.__brush,this.active=0,this.clean=e}function h(e){if((!n||e.touches)&&r.apply(this,arguments)){var i,a,u,c,l,h,d,p,g,y,v,_=this,b=e.target.__data__.type,m="selection"===(o&&e.metaKey?b="overlay":b)?na:o&&e.altKey?ia:ra,x=t===la?null:ya[b],w=t===sa?null:va[b],M=wa(_),T=M.extent,A=M.selection,S=T[0][0],E=T[0][1],N=T[1][0],k=T[1][1],C=0,P=0,z=x&&w&&o&&e.shiftKey,$=Array.from(e.touches||[e],(t=>{const n=t.identifier;return(t=ee(t,_)).point0=t.slice(),t.identifier=n,t}));Vi(_);var D=s(_,arguments,!0).beforestart();if("overlay"===b){A&&(g=!0);const n=[$[0],$[1]||$[0]];M.selection=A=[[i=t===la?S:ua(n[0][0],n[1][0]),u=t===sa?E:ua(n[0][1],n[1][1])],[l=t===la?N:aa(n[0][0],n[1][0]),d=t===sa?k:aa(n[0][1],n[1][1])]],$.length>1&&I(e)}else i=A[0][0],u=A[0][1],l=A[1][0],d=A[1][1];a=i,c=u,h=l,p=d;var R=Kn(_).attr("pointer-events","none"),F=R.selectAll(".overlay").attr("cursor",da[b]);if(e.touches)D.moved=U,D.ended=O;else{var q=Kn(e.view).on("mousemove.brush",U,!0).on("mouseup.brush",O,!0);o&&q.on("keydown.brush",(function(t){switch(t.keyCode){case 16:z=x&&w;break;case 18:m===ra&&(x&&(l=h-C*x,i=a+C*x),w&&(d=p-P*w,u=c+P*w),m=ia,I(t));break;case 32:m!==ra&&m!==ia||(x<0?l=h-C:x>0&&(i=a-C),w<0?d=p-P:w>0&&(u=c-P),m=ea,F.attr("cursor",da.selection),I(t));break;default:return}ta(t)}),!0).on("keyup.brush",(function(t){switch(t.keyCode){case 16:z&&(y=v=z=!1,I(t));break;case 18:m===ia&&(x<0?l=h:x>0&&(i=a),w<0?d=p:w>0&&(u=c),m=ra,I(t));break;case 32:m===ea&&(t.altKey?(x&&(l=h-C*x,i=a+C*x),w&&(d=p-P*w,u=c+P*w),m=ia):(x<0?l=h:x>0&&(i=a),w<0?d=p:w>0&&(u=c),m=ra),F.attr("cursor",da[b]),I(t));break;default:return}ta(t)}),!0),ue(e.view)}f.call(_),D.start(e,m.name)}function U(t){for(const n of t.changedTouches||[t])for(const t of $)t.identifier===n.identifier&&(t.cur=ee(n,_));if(z&&!y&&!v&&1===$.length){const t=$[0];oa(t.cur[0]-t[0])>oa(t.cur[1]-t[1])?v=!0:y=!0}for(const t of $)t.cur&&(t[0]=t.cur[0],t[1]=t.cur[1]);g=!0,ta(t),I(t)}function I(t){const n=$[0],e=n.point0;var r;switch(C=n[0]-e[0],P=n[1]-e[1],m){case ea:case na:x&&(C=aa(S-i,ua(N-l,C)),a=i+C,h=l+C),w&&(P=aa(E-u,ua(k-d,P)),c=u+P,p=d+P);break;case ra:$[1]?(x&&(a=aa(S,ua(N,$[0][0])),h=aa(S,ua(N,$[1][0])),x=1),w&&(c=aa(E,ua(k,$[0][1])),p=aa(E,ua(k,$[1][1])),w=1)):(x<0?(C=aa(S-i,ua(N-i,C)),a=i+C,h=l):x>0&&(C=aa(S-l,ua(N-l,C)),a=i,h=l+C),w<0?(P=aa(E-u,ua(k-u,P)),c=u+P,p=d):w>0&&(P=aa(E-d,ua(k-d,P)),c=u,p=d+P));break;case ia:x&&(a=aa(S,ua(N,i-C*x)),h=aa(S,ua(N,l+C*x))),w&&(c=aa(E,ua(k,u-P*w)),p=aa(E,ua(k,d+P*w)))}h<a&&(x*=-1,r=i,i=l,l=r,r=a,a=h,h=r,b in pa&&F.attr("cursor",da[b=pa[b]])),p<c&&(w*=-1,r=u,u=d,d=r,r=c,c=p,p=r,b in ga&&F.attr("cursor",da[b=ga[b]])),M.selection&&(A=M.selection),y&&(a=A[0][0],h=A[1][0]),v&&(c=A[0][1],p=A[1][1]),A[0][0]===a&&A[0][1]===c&&A[1][0]===h&&A[1][1]===p||(M.selection=[[a,c],[h,p]],f.call(_),D.brush(t,m.name))}function O(t){if(function(t){t.stopImmediatePropagation()}(t),t.touches){if(t.touches.length)return;n&&clearTimeout(n),n=setTimeout((function(){n=null}),500)}else ce(t.view,g),q.on("keydown.brush keyup.brush mousemove.brush mouseup.brush",null);R.attr("pointer-events","all"),F.attr("cursor",da.overlay),M.selection&&(A=M.selection),function(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}(A)&&(M.selection=null,f.call(_)),D.end(t,m.name)}}function d(t){s(this,arguments).moved(t)}function p(t){s(this,arguments).ended(t)}function g(){var n=this.__brush||{selection:null};return n.extent=fa(e.apply(this,arguments)),n.dim=t,n}return c.move=function(n,e,r){n.tween?n.on("start.brush",(function(t){s(this,arguments).beforestart().start(t)})).on("interrupt.brush end.brush",(function(t){s(this,arguments).end(t)})).tween("brush",(function(){var n=this,r=n.__brush,i=s(n,arguments),o=r.selection,a=t.input("function"==typeof e?e.apply(this,arguments):e,r.extent),u=Vr(o,a);function c(t){r.selection=1===t&&null===a?null:u(t),f.call(n),i.brush()}return null!==o&&null!==a?c:c(1)})):n.each((function(){var n=this,i=arguments,o=n.__brush,a=t.input("function"==typeof e?e.apply(n,i):e,o.extent),u=s(n,i).beforestart();Vi(n),o.selection=null===a?null:a,f.call(n),u.start(r).brush(r).end(r)}))},c.clear=function(t,n){c.move(t,null,n)},l.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(t,n){return this.starting?(this.starting=!1,this.emit("start",t,n)):this.emit("brush",t),this},brush:function(t,n){return this.emit("brush",t,n),this},end:function(t,n){return 0==--this.active&&(delete this.state.emitter,this.emit("end",t,n)),this},emit:function(n,e,r){var i=Kn(this.that).datum();a.call(n,this.that,new Jo(n,{sourceEvent:e,target:c,selection:t.output(this.state.selection),mode:r,dispatch:a}),i)}},c.extent=function(t){return arguments.length?(e="function"==typeof t?t:Qo(fa(t)),c):e},c.filter=function(t){return arguments.length?(r="function"==typeof t?t:Qo(!!t),c):r},c.touchable=function(t){return arguments.length?(i="function"==typeof t?t:Qo(!!t),c):i},c.handleSize=function(t){return arguments.length?(u=+t,c):u},c.keyModifiers=function(t){return arguments.length?(o=!!t,c):o},c.on=function(){var t=a.on.apply(a,arguments);return t===a?c:t},c}var Ta=Math.abs,Aa=Math.cos,Sa=Math.sin,Ea=Math.PI,Na=Ea/2,ka=2*Ea,Ca=Math.max,Pa=1e-12;function za(t,n){return Array.from({length:n-t},((n,e)=>t+e))}function $a(t,n){var e=0,r=null,i=null,o=null;function a(a){var u,c=a.length,f=new Array(c),s=za(0,c),l=new Array(c*c),h=new Array(c),d=0;a=Float64Array.from({length:c*c},n?(t,n)=>a[n%c][n/c|0]:(t,n)=>a[n/c|0][n%c]);for(let n=0;n<c;++n){let e=0;for(let r=0;r<c;++r)e+=a[n*c+r]+t*a[r*c+n];d+=f[n]=e}u=(d=Ca(0,ka-e*c)/d)?e:ka/c;{let n=0;r&&s.sort(((t,n)=>r(f[t],f[n])));for(const e of s){const r=n;if(t){const t=za(1+~c,c).filter((t=>t<0?a[~t*c+e]:a[e*c+t]));i&&t.sort(((t,n)=>i(t<0?-a[~t*c+e]:a[e*c+t],n<0?-a[~n*c+e]:a[e*c+n])));for(const r of t)if(r<0){(l[~r*c+e]||(l[~r*c+e]={source:null,target:null})).target={index:e,startAngle:n,endAngle:n+=a[~r*c+e]*d,value:a[~r*c+e]}}else{(l[e*c+r]||(l[e*c+r]={source:null,target:null})).source={index:e,startAngle:n,endAngle:n+=a[e*c+r]*d,value:a[e*c+r]}}h[e]={index:e,startAngle:r,endAngle:n,value:f[e]}}else{const t=za(0,c).filter((t=>a[e*c+t]||a[t*c+e]));i&&t.sort(((t,n)=>i(a[e*c+t],a[e*c+n])));for(const r of t){let t;if(e<r?(t=l[e*c+r]||(l[e*c+r]={source:null,target:null}),t.source={index:e,startAngle:n,endAngle:n+=a[e*c+r]*d,value:a[e*c+r]}):(t=l[r*c+e]||(l[r*c+e]={source:null,target:null}),t.target={index:e,startAngle:n,endAngle:n+=a[e*c+r]*d,value:a[e*c+r]},e===r&&(t.source=t.target)),t.source&&t.target&&t.source.value<t.target.value){const n=t.source;t.source=t.target,t.target=n}}h[e]={index:e,startAngle:r,endAngle:n,value:f[e]}}n+=u}}return(l=Object.values(l)).groups=h,o?l.sort(o):l}return a.padAngle=function(t){return arguments.length?(e=Ca(0,t),a):e},a.sortGroups=function(t){return arguments.length?(r=t,a):r},a.sortSubgroups=function(t){return arguments.length?(i=t,a):i},a.sortChords=function(t){return arguments.length?(null==t?o=null:(n=t,o=function(t,e){return n(t.source.value+t.target.value,e.source.value+e.target.value)})._=t,a):o&&o._;var n},a}const Da=Math.PI,Ra=2*Da,Fa=1e-6,qa=Ra-Fa;function Ua(t){this._+=t[0];for(let n=1,e=t.length;n<e;++n)this._+=arguments[n]+t[n]}let Ia=class{constructor(t){this._x0=this._y0=this._x1=this._y1=null,this._="",this._append=null==t?Ua:function(t){let n=Math.floor(t);if(!(n>=0))throw new Error(`invalid digits: ${t}`);if(n>15)return Ua;const e=10**n;return function(t){this._+=t[0];for(let n=1,r=t.length;n<r;++n)this._+=Math.round(arguments[n]*e)/e+t[n]}}(t)}moveTo(t,n){this._append`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}`}closePath(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._append`Z`)}lineTo(t,n){this._append`L${this._x1=+t},${this._y1=+n}`}quadraticCurveTo(t,n,e,r){this._append`Q${+t},${+n},${this._x1=+e},${this._y1=+r}`}bezierCurveTo(t,n,e,r,i,o){this._append`C${+t},${+n},${+e},${+r},${this._x1=+i},${this._y1=+o}`}arcTo(t,n,e,r,i){if(t=+t,n=+n,e=+e,r=+r,(i=+i)<0)throw new Error(`negative radius: ${i}`);let o=this._x1,a=this._y1,u=e-t,c=r-n,f=o-t,s=a-n,l=f*f+s*s;if(null===this._x1)this._append`M${this._x1=t},${this._y1=n}`;else if(l>Fa)if(Math.abs(s*u-c*f)>Fa&&i){let h=e-o,d=r-a,p=u*u+c*c,g=h*h+d*d,y=Math.sqrt(p),v=Math.sqrt(l),_=i*Math.tan((Da-Math.acos((p+l-g)/(2*y*v)))/2),b=_/v,m=_/y;Math.abs(b-1)>Fa&&this._append`L${t+b*f},${n+b*s}`,this._append`A${i},${i},0,0,${+(s*h>f*d)},${this._x1=t+m*u},${this._y1=n+m*c}`}else this._append`L${this._x1=t},${this._y1=n}`;else;}arc(t,n,e,r,i,o){if(t=+t,n=+n,o=!!o,(e=+e)<0)throw new Error(`negative radius: ${e}`);let a=e*Math.cos(r),u=e*Math.sin(r),c=t+a,f=n+u,s=1^o,l=o?r-i:i-r;null===this._x1?this._append`M${c},${f}`:(Math.abs(this._x1-c)>Fa||Math.abs(this._y1-f)>Fa)&&this._append`L${c},${f}`,e&&(l<0&&(l=l%Ra+Ra),l>qa?this._append`A${e},${e},0,1,${s},${t-a},${n-u}A${e},${e},0,1,${s},${this._x1=c},${this._y1=f}`:l>Fa&&this._append`A${e},${e},0,${+(l>=Da)},${s},${this._x1=t+e*Math.cos(i)},${this._y1=n+e*Math.sin(i)}`)}rect(t,n,e,r){this._append`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}h${e=+e}v${+r}h${-e}Z`}toString(){return this._}};function Oa(){return new Ia}Oa.prototype=Ia.prototype;var Ba=Array.prototype.slice;function Ya(t){return function(){return t}}function La(t){return t.source}function ja(t){return t.target}function Ha(t){return t.radius}function Xa(t){return t.startAngle}function Ga(t){return t.endAngle}function Va(){return 0}function Wa(){return 10}function Za(t){var n=La,e=ja,r=Ha,i=Ha,o=Xa,a=Ga,u=Va,c=null;function f(){var f,s=n.apply(this,arguments),l=e.apply(this,arguments),h=u.apply(this,arguments)/2,d=Ba.call(arguments),p=+r.apply(this,(d[0]=s,d)),g=o.apply(this,d)-Na,y=a.apply(this,d)-Na,v=+i.apply(this,(d[0]=l,d)),_=o.apply(this,d)-Na,b=a.apply(this,d)-Na;if(c||(c=f=Oa()),h>Pa&&(Ta(y-g)>2*h+Pa?y>g?(g+=h,y-=h):(g-=h,y+=h):g=y=(g+y)/2,Ta(b-_)>2*h+Pa?b>_?(_+=h,b-=h):(_-=h,b+=h):_=b=(_+b)/2),c.moveTo(p*Aa(g),p*Sa(g)),c.arc(0,0,p,g,y),g!==_||y!==b)if(t){var m=v-+t.apply(this,arguments),x=(_+b)/2;c.quadraticCurveTo(0,0,m*Aa(_),m*Sa(_)),c.lineTo(v*Aa(x),v*Sa(x)),c.lineTo(m*Aa(b),m*Sa(b))}else c.quadraticCurveTo(0,0,v*Aa(_),v*Sa(_)),c.arc(0,0,v,_,b);if(c.quadraticCurveTo(0,0,p*Aa(g),p*Sa(g)),c.closePath(),f)return c=null,f+""||null}return t&&(f.headRadius=function(n){return arguments.length?(t="function"==typeof n?n:Ya(+n),f):t}),f.radius=function(t){return arguments.length?(r=i="function"==typeof t?t:Ya(+t),f):r},f.sourceRadius=function(t){return arguments.length?(r="function"==typeof t?t:Ya(+t),f):r},f.targetRadius=function(t){return arguments.length?(i="function"==typeof t?t:Ya(+t),f):i},f.startAngle=function(t){return arguments.length?(o="function"==typeof t?t:Ya(+t),f):o},f.endAngle=function(t){return arguments.length?(a="function"==typeof t?t:Ya(+t),f):a},f.padAngle=function(t){return arguments.length?(u="function"==typeof t?t:Ya(+t),f):u},f.source=function(t){return arguments.length?(n=t,f):n},f.target=function(t){return arguments.length?(e=t,f):e},f.context=function(t){return arguments.length?(c=null==t?null:t,f):c},f}var Ka=Array.prototype.slice;function Qa(t,n){return t-n}var Ja=t=>()=>t;function tu(t,n){for(var e,r=-1,i=n.length;++r<i;)if(e=nu(t,n[r]))return e;return 0}function nu(t,n){for(var e=n[0],r=n[1],i=-1,o=0,a=t.length,u=a-1;o<a;u=o++){var c=t[o],f=c[0],s=c[1],l=t[u],h=l[0],d=l[1];if(eu(c,l,n))return 0;s>r!=d>r&&e<(h-f)*(r-s)/(d-s)+f&&(i=-i)}return i}function eu(t,n,e){var r,i,o,a;return function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])==(e[0]-t[0])*(n[1]-t[1])}(t,n,e)&&(i=t[r=+(t[0]===n[0])],o=e[r],a=n[r],i<=o&&o<=a||a<=o&&o<=i)}function ru(){}var iu=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]];function ou(){var t=1,n=1,e=Q,r=u;function i(t){var n=e(t);if(Array.isArray(n))n=n.slice().sort(Qa);else{const e=T(t,au);for(n=V(...K(e[0],e[1],n),n);n[n.length-1]>=e[1];)n.pop();for(;n[1]<e[0];)n.shift()}return n.map((n=>o(t,n)))}function o(e,i){const o=null==i?NaN:+i;if(isNaN(o))throw new Error(`invalid value: ${i}`);var u=[],c=[];return function(e,r,i){var o,u,c,f,s,l,h=new Array,d=new Array;o=u=-1,f=uu(e[0],r),iu[f<<1].forEach(p);for(;++o<t-1;)c=f,f=uu(e[o+1],r),iu[c|f<<1].forEach(p);iu[f<<0].forEach(p);for(;++u<n-1;){for(o=-1,f=uu(e[u*t+t],r),s=uu(e[u*t],r),iu[f<<1|s<<2].forEach(p);++o<t-1;)c=f,f=uu(e[u*t+t+o+1],r),l=s,s=uu(e[u*t+o+1],r),iu[c|f<<1|s<<2|l<<3].forEach(p);iu[f|s<<3].forEach(p)}o=-1,s=e[u*t]>=r,iu[s<<2].forEach(p);for(;++o<t-1;)l=s,s=uu(e[u*t+o+1],r),iu[s<<2|l<<3].forEach(p);function p(t){var n,e,r=[t[0][0]+o,t[0][1]+u],c=[t[1][0]+o,t[1][1]+u],f=a(r),s=a(c);(n=d[f])?(e=h[s])?(delete d[n.end],delete h[e.start],n===e?(n.ring.push(c),i(n.ring)):h[n.start]=d[e.end]={start:n.start,end:e.end,ring:n.ring.concat(e.ring)}):(delete d[n.end],n.ring.push(c),d[n.end=s]=n):(n=h[s])?(e=d[f])?(delete h[n.start],delete d[e.end],n===e?(n.ring.push(c),i(n.ring)):h[e.start]=d[n.end]={start:e.start,end:n.end,ring:e.ring.concat(n.ring)}):(delete h[n.start],n.ring.unshift(r),h[n.start=f]=n):h[f]=d[s]={start:f,end:s,ring:[r,c]}}iu[s<<3].forEach(p)}(e,o,(function(t){r(t,e,o),function(t){for(var n=0,e=t.length,r=t[e-1][1]*t[0][0]-t[e-1][0]*t[0][1];++n<e;)r+=t[n-1][1]*t[n][0]-t[n-1][0]*t[n][1];return r}(t)>0?u.push([t]):c.push(t)})),c.forEach((function(t){for(var n,e=0,r=u.length;e<r;++e)if(-1!==tu((n=u[e])[0],t))return void n.push(t)})),{type:"MultiPolygon",value:i,coordinates:u}}function a(n){return 2*n[0]+n[1]*(t+1)*4}function u(e,r,i){e.forEach((function(e){var o=e[0],a=e[1],u=0|o,c=0|a,f=cu(r[c*t+u]);o>0&&o<t&&u===o&&(e[0]=fu(o,cu(r[c*t+u-1]),f,i)),a>0&&a<n&&c===a&&(e[1]=fu(a,cu(r[(c-1)*t+u]),f,i))}))}return i.contour=o,i.size=function(e){if(!arguments.length)return[t,n];var r=Math.floor(e[0]),o=Math.floor(e[1]);if(!(r>=0&&o>=0))throw new Error("invalid size");return t=r,n=o,i},i.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?Ja(Ka.call(t)):Ja(t),i):e},i.smooth=function(t){return arguments.length?(r=t?u:ru,i):r===u},i}function au(t){return isFinite(t)?t:NaN}function uu(t,n){return null!=t&&+t>=n}function cu(t){return null==t||isNaN(t=+t)?-1/0:t}function fu(t,n,e,r){const i=r-n,o=e-n,a=isFinite(i)||isFinite(o)?i/o:Math.sign(i)/Math.sign(o);return isNaN(a)?t:t+a-.5}function su(t){return t[0]}function lu(t){return t[1]}function hu(){return 1}const du=134217729,pu=33306690738754706e-32;function gu(t,n,e,r,i){let o,a,u,c,f=n[0],s=r[0],l=0,h=0;s>f==s>-f?(o=f,f=n[++l]):(o=s,s=r[++h]);let d=0;if(l<t&&h<e)for(s>f==s>-f?(a=f+o,u=o-(a-f),f=n[++l]):(a=s+o,u=o-(a-s),s=r[++h]),o=a,0!==u&&(i[d++]=u);l<t&&h<e;)s>f==s>-f?(a=o+f,c=a-o,u=o-(a-c)+(f-c),f=n[++l]):(a=o+s,c=a-o,u=o-(a-c)+(s-c),s=r[++h]),o=a,0!==u&&(i[d++]=u);for(;l<t;)a=o+f,c=a-o,u=o-(a-c)+(f-c),f=n[++l],o=a,0!==u&&(i[d++]=u);for(;h<e;)a=o+s,c=a-o,u=o-(a-c)+(s-c),s=r[++h],o=a,0!==u&&(i[d++]=u);return 0===o&&0!==d||(i[d++]=o),d}function yu(t){return new Float64Array(t)}const vu=22204460492503146e-32,_u=11093356479670487e-47,bu=yu(4),mu=yu(8),xu=yu(12),wu=yu(16),Mu=yu(4);function Tu(t,n,e,r,i,o){const a=(n-o)*(e-i),u=(t-i)*(r-o),c=a-u;if(0===a||0===u||a>0!=u>0)return c;const f=Math.abs(a+u);return Math.abs(c)>=33306690738754716e-32*f?c:-function(t,n,e,r,i,o,a){let u,c,f,s,l,h,d,p,g,y,v,_,b,m,x,w,M,T;const A=t-i,S=e-i,E=n-o,N=r-o;m=A*N,h=du*A,d=h-(h-A),p=A-d,h=du*N,g=h-(h-N),y=N-g,x=p*y-(m-d*g-p*g-d*y),w=E*S,h=du*E,d=h-(h-E),p=E-d,h=du*S,g=h-(h-S),y=S-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,bu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,bu[1]=b-(v+l)+(l-w),T=_+v,l=T-_,bu[2]=_-(T-l)+(v-l),bu[3]=T;let k=function(t,n){let e=n[0];for(let r=1;r<t;r++)e+=n[r];return e}(4,bu),C=vu*a;if(k>=C||-k>=C)return k;if(l=t-A,u=t-(A+l)+(l-i),l=e-S,f=e-(S+l)+(l-i),l=n-E,c=n-(E+l)+(l-o),l=r-N,s=r-(N+l)+(l-o),0===u&&0===c&&0===f&&0===s)return k;if(C=_u*a+pu*Math.abs(k),k+=A*s+N*u-(E*f+S*c),k>=C||-k>=C)return k;m=u*N,h=du*u,d=h-(h-u),p=u-d,h=du*N,g=h-(h-N),y=N-g,x=p*y-(m-d*g-p*g-d*y),w=c*S,h=du*c,d=h-(h-c),p=c-d,h=du*S,g=h-(h-S),y=S-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,Mu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,Mu[1]=b-(v+l)+(l-w),T=_+v,l=T-_,Mu[2]=_-(T-l)+(v-l),Mu[3]=T;const P=gu(4,bu,4,Mu,mu);m=A*s,h=du*A,d=h-(h-A),p=A-d,h=du*s,g=h-(h-s),y=s-g,x=p*y-(m-d*g-p*g-d*y),w=E*f,h=du*E,d=h-(h-E),p=E-d,h=du*f,g=h-(h-f),y=f-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,Mu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,Mu[1]=b-(v+l)+(l-w),T=_+v,l=T-_,Mu[2]=_-(T-l)+(v-l),Mu[3]=T;const z=gu(P,mu,4,Mu,xu);m=u*s,h=du*u,d=h-(h-u),p=u-d,h=du*s,g=h-(h-s),y=s-g,x=p*y-(m-d*g-p*g-d*y),w=c*f,h=du*c,d=h-(h-c),p=c-d,h=du*f,g=h-(h-f),y=f-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,Mu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,Mu[1]=b-(v+l)+(l-w),T=_+v,l=T-_,Mu[2]=_-(T-l)+(v-l),Mu[3]=T;const $=gu(z,xu,4,Mu,wu);return wu[$-1]}(t,n,e,r,i,o,f)}const Au=Math.pow(2,-52),Su=new Uint32Array(512);class Eu{static from(t,n=$u,e=Du){const r=t.length,i=new Float64Array(2*r);for(let o=0;o<r;o++){const r=t[o];i[2*o]=n(r),i[2*o+1]=e(r)}return new Eu(i)}constructor(t){const n=t.length>>1;if(n>0&&"number"!=typeof t[0])throw new Error("Expected coords to contain numbers.");this.coords=t;const e=Math.max(2*n-5,0);this._triangles=new Uint32Array(3*e),this._halfedges=new Int32Array(3*e),this._hashSize=Math.ceil(Math.sqrt(n)),this._hullPrev=new Uint32Array(n),this._hullNext=new Uint32Array(n),this._hullTri=new Uint32Array(n),this._hullHash=new Int32Array(this._hashSize).fill(-1),this._ids=new Uint32Array(n),this._dists=new Float64Array(n),this.update()}update(){const{coords:t,_hullPrev:n,_hullNext:e,_hullTri:r,_hullHash:i}=this,o=t.length>>1;let a=1/0,u=1/0,c=-1/0,f=-1/0;for(let n=0;n<o;n++){const e=t[2*n],r=t[2*n+1];e<a&&(a=e),r<u&&(u=r),e>c&&(c=e),r>f&&(f=r),this._ids[n]=n}const s=(a+c)/2,l=(u+f)/2;let h,d,p,g=1/0;for(let n=0;n<o;n++){const e=Nu(s,l,t[2*n],t[2*n+1]);e<g&&(h=n,g=e)}const y=t[2*h],v=t[2*h+1];g=1/0;for(let n=0;n<o;n++){if(n===h)continue;const e=Nu(y,v,t[2*n],t[2*n+1]);e<g&&e>0&&(d=n,g=e)}let _=t[2*d],b=t[2*d+1],m=1/0;for(let n=0;n<o;n++){if(n===h||n===d)continue;const e=Cu(y,v,_,b,t[2*n],t[2*n+1]);e<m&&(p=n,m=e)}let x=t[2*p],w=t[2*p+1];if(m===1/0){for(let n=0;n<o;n++)this._dists[n]=t[2*n]-t[0]||t[2*n+1]-t[1];Pu(this._ids,this._dists,0,o-1);const n=new Uint32Array(o);let e=0;for(let t=0,r=-1/0;t<o;t++){const i=this._ids[t];this._dists[i]>r&&(n[e++]=i,r=this._dists[i])}return this.hull=n.subarray(0,e),this.triangles=new Uint32Array(0),void(this.halfedges=new Uint32Array(0))}if(Tu(y,v,_,b,x,w)<0){const t=d,n=_,e=b;d=p,_=x,b=w,p=t,x=n,w=e}const M=function(t,n,e,r,i,o){const a=e-t,u=r-n,c=i-t,f=o-n,s=a*a+u*u,l=c*c+f*f,h=.5/(a*f-u*c),d=t+(f*s-u*l)*h,p=n+(a*l-c*s)*h;return{x:d,y:p}}(y,v,_,b,x,w);this._cx=M.x,this._cy=M.y;for(let n=0;n<o;n++)this._dists[n]=Nu(t[2*n],t[2*n+1],M.x,M.y);Pu(this._ids,this._dists,0,o-1),this._hullStart=h;let T=3;e[h]=n[p]=d,e[d]=n[h]=p,e[p]=n[d]=h,r[h]=0,r[d]=1,r[p]=2,i.fill(-1),i[this._hashKey(y,v)]=h,i[this._hashKey(_,b)]=d,i[this._hashKey(x,w)]=p,this.trianglesLen=0,this._addTriangle(h,d,p,-1,-1,-1);for(let o,a,u=0;u<this._ids.length;u++){const c=this._ids[u],f=t[2*c],s=t[2*c+1];if(u>0&&Math.abs(f-o)<=Au&&Math.abs(s-a)<=Au)continue;if(o=f,a=s,c===h||c===d||c===p)continue;let l=0;for(let t=0,n=this._hashKey(f,s);t<this._hashSize&&(l=i[(n+t)%this._hashSize],-1===l||l===e[l]);t++);l=n[l];let g,y=l;for(;g=e[y],Tu(f,s,t[2*y],t[2*y+1],t[2*g],t[2*g+1])>=0;)if(y=g,y===l){y=-1;break}if(-1===y)continue;let v=this._addTriangle(y,c,e[y],-1,-1,r[y]);r[c]=this._legalize(v+2),r[y]=v,T++;let _=e[y];for(;g=e[_],Tu(f,s,t[2*_],t[2*_+1],t[2*g],t[2*g+1])<0;)v=this._addTriangle(_,c,g,r[c],-1,r[_]),r[c]=this._legalize(v+2),e[_]=_,T--,_=g;if(y===l)for(;g=n[y],Tu(f,s,t[2*g],t[2*g+1],t[2*y],t[2*y+1])<0;)v=this._addTriangle(g,c,y,-1,r[y],r[g]),this._legalize(v+2),r[g]=v,e[y]=y,T--,y=g;this._hullStart=n[c]=y,e[y]=n[_]=c,e[c]=_,i[this._hashKey(f,s)]=c,i[this._hashKey(t[2*y],t[2*y+1])]=y}this.hull=new Uint32Array(T);for(let t=0,n=this._hullStart;t<T;t++)this.hull[t]=n,n=e[n];this.triangles=this._triangles.subarray(0,this.trianglesLen),this.halfedges=this._halfedges.subarray(0,this.trianglesLen)}_hashKey(t,n){return Math.floor(function(t,n){const e=t/(Math.abs(t)+Math.abs(n));return(n>0?3-e:1+e)/4}(t-this._cx,n-this._cy)*this._hashSize)%this._hashSize}_legalize(t){const{_triangles:n,_halfedges:e,coords:r}=this;let i=0,o=0;for(;;){const a=e[t],u=t-t%3;if(o=u+(t+2)%3,-1===a){if(0===i)break;t=Su[--i];continue}const c=a-a%3,f=u+(t+1)%3,s=c+(a+2)%3,l=n[o],h=n[t],d=n[f],p=n[s];if(ku(r[2*l],r[2*l+1],r[2*h],r[2*h+1],r[2*d],r[2*d+1],r[2*p],r[2*p+1])){n[t]=p,n[a]=l;const r=e[s];if(-1===r){let n=this._hullStart;do{if(this._hullTri[n]===s){this._hullTri[n]=t;break}n=this._hullPrev[n]}while(n!==this._hullStart)}this._link(t,r),this._link(a,e[o]),this._link(o,s);const u=c+(a+1)%3;i<Su.length&&(Su[i++]=u)}else{if(0===i)break;t=Su[--i]}}return o}_link(t,n){this._halfedges[t]=n,-1!==n&&(this._halfedges[n]=t)}_addTriangle(t,n,e,r,i,o){const a=this.trianglesLen;return this._triangles[a]=t,this._triangles[a+1]=n,this._triangles[a+2]=e,this._link(a,r),this._link(a+1,i),this._link(a+2,o),this.trianglesLen+=3,a}}function Nu(t,n,e,r){const i=t-e,o=n-r;return i*i+o*o}function ku(t,n,e,r,i,o,a,u){const c=t-a,f=n-u,s=e-a,l=r-u,h=i-a,d=o-u,p=s*s+l*l,g=h*h+d*d;return c*(l*g-p*d)-f*(s*g-p*h)+(c*c+f*f)*(s*d-l*h)<0}function Cu(t,n,e,r,i,o){const a=e-t,u=r-n,c=i-t,f=o-n,s=a*a+u*u,l=c*c+f*f,h=.5/(a*f-u*c),d=(f*s-u*l)*h,p=(a*l-c*s)*h;return d*d+p*p}function Pu(t,n,e,r){if(r-e<=20)for(let i=e+1;i<=r;i++){const r=t[i],o=n[r];let a=i-1;for(;a>=e&&n[t[a]]>o;)t[a+1]=t[a--];t[a+1]=r}else{let i=e+1,o=r;zu(t,e+r>>1,i),n[t[e]]>n[t[r]]&&zu(t,e,r),n[t[i]]>n[t[r]]&&zu(t,i,r),n[t[e]]>n[t[i]]&&zu(t,e,i);const a=t[i],u=n[a];for(;;){do{i++}while(n[t[i]]<u);do{o--}while(n[t[o]]>u);if(o<i)break;zu(t,i,o)}t[e+1]=t[o],t[o]=a,r-i+1>=o-e?(Pu(t,n,i,r),Pu(t,n,e,o-1)):(Pu(t,n,e,o-1),Pu(t,n,i,r))}}function zu(t,n,e){const r=t[n];t[n]=t[e],t[e]=r}function $u(t){return t[0]}function Du(t){return t[1]}const Ru=1e-6;class Fu{constructor(){this._x0=this._y0=this._x1=this._y1=null,this._=""}moveTo(t,n){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}`}closePath(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")}lineTo(t,n){this._+=`L${this._x1=+t},${this._y1=+n}`}arc(t,n,e){const r=(t=+t)+(e=+e),i=n=+n;if(e<0)throw new Error("negative radius");null===this._x1?this._+=`M${r},${i}`:(Math.abs(this._x1-r)>Ru||Math.abs(this._y1-i)>Ru)&&(this._+="L"+r+","+i),e&&(this._+=`A${e},${e},0,1,1,${t-e},${n}A${e},${e},0,1,1,${this._x1=r},${this._y1=i}`)}rect(t,n,e,r){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}h${+e}v${+r}h${-e}Z`}value(){return this._||null}}class qu{constructor(){this._=[]}moveTo(t,n){this._.push([t,n])}closePath(){this._.push(this._[0].slice())}lineTo(t,n){this._.push([t,n])}value(){return this._.length?this._:null}}class Uu{constructor(t,[n,e,r,i]=[0,0,960,500]){if(!((r=+r)>=(n=+n)&&(i=+i)>=(e=+e)))throw new Error("invalid bounds");this.delaunay=t,this._circumcenters=new Float64Array(2*t.points.length),this.vectors=new Float64Array(2*t.points.length),this.xmax=r,this.xmin=n,this.ymax=i,this.ymin=e,this._init()}update(){return this.delaunay.update(),this._init(),this}_init(){const{delaunay:{points:t,hull:n,triangles:e},vectors:r}=this;let i,o;const a=this.circumcenters=this._circumcenters.subarray(0,e.length/3*2);for(let r,u,c=0,f=0,s=e.length;c<s;c+=3,f+=2){const s=2*e[c],l=2*e[c+1],h=2*e[c+2],d=t[s],p=t[s+1],g=t[l],y=t[l+1],v=t[h],_=t[h+1],b=g-d,m=y-p,x=v-d,w=_-p,M=2*(b*w-m*x);if(Math.abs(M)<1e-9){if(void 0===i){i=o=0;for(const e of n)i+=t[2*e],o+=t[2*e+1];i/=n.length,o/=n.length}const e=1e9*Math.sign((i-d)*w-(o-p)*x);r=(d+v)/2-e*w,u=(p+_)/2+e*x}else{const t=1/M,n=b*b+m*m,e=x*x+w*w;r=d+(w*n-m*e)*t,u=p+(b*e-x*n)*t}a[f]=r,a[f+1]=u}let u,c,f,s=n[n.length-1],l=4*s,h=t[2*s],d=t[2*s+1];r.fill(0);for(let e=0;e<n.length;++e)s=n[e],u=l,c=h,f=d,l=4*s,h=t[2*s],d=t[2*s+1],r[u+2]=r[l]=f-d,r[u+3]=r[l+1]=h-c}render(t){const n=null==t?t=new Fu:void 0,{delaunay:{halfedges:e,inedges:r,hull:i},circumcenters:o,vectors:a}=this;if(i.length<=1)return null;for(let n=0,r=e.length;n<r;++n){const r=e[n];if(r<n)continue;const i=2*Math.floor(n/3),a=2*Math.floor(r/3),u=o[i],c=o[i+1],f=o[a],s=o[a+1];this._renderSegment(u,c,f,s,t)}let u,c=i[i.length-1];for(let n=0;n<i.length;++n){u=c,c=i[n];const e=2*Math.floor(r[c]/3),f=o[e],s=o[e+1],l=4*u,h=this._project(f,s,a[l+2],a[l+3]);h&&this._renderSegment(f,s,h[0],h[1],t)}return n&&n.value()}renderBounds(t){const n=null==t?t=new Fu:void 0;return t.rect(this.xmin,this.ymin,this.xmax-this.xmin,this.ymax-this.ymin),n&&n.value()}renderCell(t,n){const e=null==n?n=new Fu:void 0,r=this._clip(t);if(null===r||!r.length)return;n.moveTo(r[0],r[1]);let i=r.length;for(;r[0]===r[i-2]&&r[1]===r[i-1]&&i>1;)i-=2;for(let t=2;t<i;t+=2)r[t]===r[t-2]&&r[t+1]===r[t-1]||n.lineTo(r[t],r[t+1]);return n.closePath(),e&&e.value()}*cellPolygons(){const{delaunay:{points:t}}=this;for(let n=0,e=t.length/2;n<e;++n){const t=this.cellPolygon(n);t&&(t.index=n,yield t)}}cellPolygon(t){const n=new qu;return this.renderCell(t,n),n.value()}_renderSegment(t,n,e,r,i){let o;const a=this._regioncode(t,n),u=this._regioncode(e,r);0===a&&0===u?(i.moveTo(t,n),i.lineTo(e,r)):(o=this._clipSegment(t,n,e,r,a,u))&&(i.moveTo(o[0],o[1]),i.lineTo(o[2],o[3]))}contains(t,n,e){return(n=+n)==n&&(e=+e)==e&&this.delaunay._step(t,n,e)===t}*neighbors(t){const n=this._clip(t);if(n)for(const e of this.delaunay.neighbors(t)){const t=this._clip(e);if(t)t:for(let r=0,i=n.length;r<i;r+=2)for(let o=0,a=t.length;o<a;o+=2)if(n[r]===t[o]&&n[r+1]===t[o+1]&&n[(r+2)%i]===t[(o+a-2)%a]&&n[(r+3)%i]===t[(o+a-1)%a]){yield e;break t}}}_cell(t){const{circumcenters:n,delaunay:{inedges:e,halfedges:r,triangles:i}}=this,o=e[t];if(-1===o)return null;const a=[];let u=o;do{const e=Math.floor(u/3);if(a.push(n[2*e],n[2*e+1]),u=u%3==2?u-2:u+1,i[u]!==t)break;u=r[u]}while(u!==o&&-1!==u);return a}_clip(t){if(0===t&&1===this.delaunay.hull.length)return[this.xmax,this.ymin,this.xmax,this.ymax,this.xmin,this.ymax,this.xmin,this.ymin];const n=this._cell(t);if(null===n)return null;const{vectors:e}=this,r=4*t;return this._simplify(e[r]||e[r+1]?this._clipInfinite(t,n,e[r],e[r+1],e[r+2],e[r+3]):this._clipFinite(t,n))}_clipFinite(t,n){const e=n.length;let r,i,o,a,u=null,c=n[e-2],f=n[e-1],s=this._regioncode(c,f),l=0;for(let h=0;h<e;h+=2)if(r=c,i=f,c=n[h],f=n[h+1],o=s,s=this._regioncode(c,f),0===o&&0===s)a=l,l=0,u?u.push(c,f):u=[c,f];else{let n,e,h,d,p;if(0===o){if(null===(n=this._clipSegment(r,i,c,f,o,s)))continue;[e,h,d,p]=n}else{if(null===(n=this._clipSegment(c,f,r,i,s,o)))continue;[d,p,e,h]=n,a=l,l=this._edgecode(e,h),a&&l&&this._edge(t,a,l,u,u.length),u?u.push(e,h):u=[e,h]}a=l,l=this._edgecode(d,p),a&&l&&this._edge(t,a,l,u,u.length),u?u.push(d,p):u=[d,p]}if(u)a=l,l=this._edgecode(u[0],u[1]),a&&l&&this._edge(t,a,l,u,u.length);else if(this.contains(t,(this.xmin+this.xmax)/2,(this.ymin+this.ymax)/2))return[this.xmax,this.ymin,this.xmax,this.ymax,this.xmin,this.ymax,this.xmin,this.ymin];return u}_clipSegment(t,n,e,r,i,o){const a=i<o;for(a&&([t,n,e,r,i,o]=[e,r,t,n,o,i]);;){if(0===i&&0===o)return a?[e,r,t,n]:[t,n,e,r];if(i&o)return null;let u,c,f=i||o;8&f?(u=t+(e-t)*(this.ymax-n)/(r-n),c=this.ymax):4&f?(u=t+(e-t)*(this.ymin-n)/(r-n),c=this.ymin):2&f?(c=n+(r-n)*(this.xmax-t)/(e-t),u=this.xmax):(c=n+(r-n)*(this.xmin-t)/(e-t),u=this.xmin),i?(t=u,n=c,i=this._regioncode(t,n)):(e=u,r=c,o=this._regioncode(e,r))}}_clipInfinite(t,n,e,r,i,o){let a,u=Array.from(n);if((a=this._project(u[0],u[1],e,r))&&u.unshift(a[0],a[1]),(a=this._project(u[u.length-2],u[u.length-1],i,o))&&u.push(a[0],a[1]),u=this._clipFinite(t,u))for(let n,e=0,r=u.length,i=this._edgecode(u[r-2],u[r-1]);e<r;e+=2)n=i,i=this._edgecode(u[e],u[e+1]),n&&i&&(e=this._edge(t,n,i,u,e),r=u.length);else this.contains(t,(this.xmin+this.xmax)/2,(this.ymin+this.ymax)/2)&&(u=[this.xmin,this.ymin,this.xmax,this.ymin,this.xmax,this.ymax,this.xmin,this.ymax]);return u}_edge(t,n,e,r,i){for(;n!==e;){let e,o;switch(n){case 5:n=4;continue;case 4:n=6,e=this.xmax,o=this.ymin;break;case 6:n=2;continue;case 2:n=10,e=this.xmax,o=this.ymax;break;case 10:n=8;continue;case 8:n=9,e=this.xmin,o=this.ymax;break;case 9:n=1;continue;case 1:n=5,e=this.xmin,o=this.ymin}r[i]===e&&r[i+1]===o||!this.contains(t,e,o)||(r.splice(i,0,e,o),i+=2)}return i}_project(t,n,e,r){let i,o,a,u=1/0;if(r<0){if(n<=this.ymin)return null;(i=(this.ymin-n)/r)<u&&(a=this.ymin,o=t+(u=i)*e)}else if(r>0){if(n>=this.ymax)return null;(i=(this.ymax-n)/r)<u&&(a=this.ymax,o=t+(u=i)*e)}if(e>0){if(t>=this.xmax)return null;(i=(this.xmax-t)/e)<u&&(o=this.xmax,a=n+(u=i)*r)}else if(e<0){if(t<=this.xmin)return null;(i=(this.xmin-t)/e)<u&&(o=this.xmin,a=n+(u=i)*r)}return[o,a]}_edgecode(t,n){return(t===this.xmin?1:t===this.xmax?2:0)|(n===this.ymin?4:n===this.ymax?8:0)}_regioncode(t,n){return(t<this.xmin?1:t>this.xmax?2:0)|(n<this.ymin?4:n>this.ymax?8:0)}_simplify(t){if(t&&t.length>4){for(let n=0;n<t.length;n+=2){const e=(n+2)%t.length,r=(n+4)%t.length;(t[n]===t[e]&&t[e]===t[r]||t[n+1]===t[e+1]&&t[e+1]===t[r+1])&&(t.splice(e,2),n-=2)}t.length||(t=null)}return t}}const Iu=2*Math.PI,Ou=Math.pow;function Bu(t){return t[0]}function Yu(t){return t[1]}function Lu(t,n,e){return[t+Math.sin(t+n)*e,n+Math.cos(t-n)*e]}class ju{static from(t,n=Bu,e=Yu,r){return new ju("length"in t?function(t,n,e,r){const i=t.length,o=new Float64Array(2*i);for(let a=0;a<i;++a){const i=t[a];o[2*a]=n.call(r,i,a,t),o[2*a+1]=e.call(r,i,a,t)}return o}(t,n,e,r):Float64Array.from(function*(t,n,e,r){let i=0;for(const o of t)yield n.call(r,o,i,t),yield e.call(r,o,i,t),++i}(t,n,e,r)))}constructor(t){this._delaunator=new Eu(t),this.inedges=new Int32Array(t.length/2),this._hullIndex=new Int32Array(t.length/2),this.points=this._delaunator.coords,this._init()}update(){return this._delaunator.update(),this._init(),this}_init(){const t=this._delaunator,n=this.points;if(t.hull&&t.hull.length>2&&function(t){const{triangles:n,coords:e}=t;for(let t=0;t<n.length;t+=3){const r=2*n[t],i=2*n[t+1],o=2*n[t+2];if((e[o]-e[r])*(e[i+1]-e[r+1])-(e[i]-e[r])*(e[o+1]-e[r+1])>1e-10)return!1}return!0}(t)){this.collinear=Int32Array.from({length:n.length/2},((t,n)=>n)).sort(((t,e)=>n[2*t]-n[2*e]||n[2*t+1]-n[2*e+1]));const t=this.collinear[0],e=this.collinear[this.collinear.length-1],r=[n[2*t],n[2*t+1],n[2*e],n[2*e+1]],i=1e-8*Math.hypot(r[3]-r[1],r[2]-r[0]);for(let t=0,e=n.length/2;t<e;++t){const e=Lu(n[2*t],n[2*t+1],i);n[2*t]=e[0],n[2*t+1]=e[1]}this._delaunator=new Eu(n)}else delete this.collinear;const e=this.halfedges=this._delaunator.halfedges,r=this.hull=this._delaunator.hull,i=this.triangles=this._delaunator.triangles,o=this.inedges.fill(-1),a=this._hullIndex.fill(-1);for(let t=0,n=e.length;t<n;++t){const n=i[t%3==2?t-2:t+1];-1!==e[t]&&-1!==o[n]||(o[n]=t)}for(let t=0,n=r.length;t<n;++t)a[r[t]]=t;r.length<=2&&r.length>0&&(this.triangles=new Int32Array(3).fill(-1),this.halfedges=new Int32Array(3).fill(-1),this.triangles[0]=r[0],o[r[0]]=1,2===r.length&&(o[r[1]]=0,this.triangles[1]=r[1],this.triangles[2]=r[1]))}voronoi(t){return new Uu(this,t)}*neighbors(t){const{inedges:n,hull:e,_hullIndex:r,halfedges:i,triangles:o,collinear:a}=this;if(a){const n=a.indexOf(t);return n>0&&(yield a[n-1]),void(n<a.length-1&&(yield a[n+1]))}const u=n[t];if(-1===u)return;let c=u,f=-1;do{if(yield f=o[c],c=c%3==2?c-2:c+1,o[c]!==t)return;if(c=i[c],-1===c){const n=e[(r[t]+1)%e.length];return void(n!==f&&(yield n))}}while(c!==u)}find(t,n,e=0){if((t=+t)!=t||(n=+n)!=n)return-1;const r=e;let i;for(;(i=this._step(e,t,n))>=0&&i!==e&&i!==r;)e=i;return i}_step(t,n,e){const{inedges:r,hull:i,_hullIndex:o,halfedges:a,triangles:u,points:c}=this;if(-1===r[t]||!c.length)return(t+1)%(c.length>>1);let f=t,s=Ou(n-c[2*t],2)+Ou(e-c[2*t+1],2);const l=r[t];let h=l;do{let r=u[h];const l=Ou(n-c[2*r],2)+Ou(e-c[2*r+1],2);if(l<s&&(s=l,f=r),h=h%3==2?h-2:h+1,u[h]!==t)break;if(h=a[h],-1===h){if(h=i[(o[t]+1)%i.length],h!==r&&Ou(n-c[2*h],2)+Ou(e-c[2*h+1],2)<s)return h;break}}while(h!==l);return f}render(t){const n=null==t?t=new Fu:void 0,{points:e,halfedges:r,triangles:i}=this;for(let n=0,o=r.length;n<o;++n){const o=r[n];if(o<n)continue;const a=2*i[n],u=2*i[o];t.moveTo(e[a],e[a+1]),t.lineTo(e[u],e[u+1])}return this.renderHull(t),n&&n.value()}renderPoints(t,n){void 0!==n||t&&"function"==typeof t.moveTo||(n=t,t=null),n=null==n?2:+n;const e=null==t?t=new Fu:void 0,{points:r}=this;for(let e=0,i=r.length;e<i;e+=2){const i=r[e],o=r[e+1];t.moveTo(i+n,o),t.arc(i,o,n,0,Iu)}return e&&e.value()}renderHull(t){const n=null==t?t=new Fu:void 0,{hull:e,points:r}=this,i=2*e[0],o=e.length;t.moveTo(r[i],r[i+1]);for(let n=1;n<o;++n){const i=2*e[n];t.lineTo(r[i],r[i+1])}return t.closePath(),n&&n.value()}hullPolygon(){const t=new qu;return this.renderHull(t),t.value()}renderTriangle(t,n){const e=null==n?n=new Fu:void 0,{points:r,triangles:i}=this,o=2*i[t*=3],a=2*i[t+1],u=2*i[t+2];return n.moveTo(r[o],r[o+1]),n.lineTo(r[a],r[a+1]),n.lineTo(r[u],r[u+1]),n.closePath(),e&&e.value()}*trianglePolygons(){const{triangles:t}=this;for(let n=0,e=t.length/3;n<e;++n)yield this.trianglePolygon(n)}trianglePolygon(t){const n=new qu;return this.renderTriangle(t,n),n.value()}}var Hu={},Xu={},Gu=34,Vu=10,Wu=13;function Zu(t){return new Function("d","return {"+t.map((function(t,n){return JSON.stringify(t)+": d["+n+'] || ""'})).join(",")+"}")}function Ku(t){var n=Object.create(null),e=[];return t.forEach((function(t){for(var r in t)r in n||e.push(n[r]=r)})),e}function Qu(t,n){var e=t+"",r=e.length;return r<n?new Array(n-r+1).join(0)+e:e}function Ju(t){var n,e=t.getUTCHours(),r=t.getUTCMinutes(),i=t.getUTCSeconds(),o=t.getUTCMilliseconds();return isNaN(t)?"Invalid Date":((n=t.getUTCFullYear())<0?"-"+Qu(-n,6):n>9999?"+"+Qu(n,6):Qu(n,4))+"-"+Qu(t.getUTCMonth()+1,2)+"-"+Qu(t.getUTCDate(),2)+(o?"T"+Qu(e,2)+":"+Qu(r,2)+":"+Qu(i,2)+"."+Qu(o,3)+"Z":i?"T"+Qu(e,2)+":"+Qu(r,2)+":"+Qu(i,2)+"Z":r||e?"T"+Qu(e,2)+":"+Qu(r,2)+"Z":"")}function tc(t){var n=new RegExp('["'+t+"\n\r]"),e=t.charCodeAt(0);function r(t,n){var r,i=[],o=t.length,a=0,u=0,c=o<=0,f=!1;function s(){if(c)return Xu;if(f)return f=!1,Hu;var n,r,i=a;if(t.charCodeAt(i)===Gu){for(;a++<o&&t.charCodeAt(a)!==Gu||t.charCodeAt(++a)===Gu;);return(n=a)>=o?c=!0:(r=t.charCodeAt(a++))===Vu?f=!0:r===Wu&&(f=!0,t.charCodeAt(a)===Vu&&++a),t.slice(i+1,n-1).replace(/""/g,'"')}for(;a<o;){if((r=t.charCodeAt(n=a++))===Vu)f=!0;else if(r===Wu)f=!0,t.charCodeAt(a)===Vu&&++a;else if(r!==e)continue;return t.slice(i,n)}return c=!0,t.slice(i,o)}for(t.charCodeAt(o-1)===Vu&&--o,t.charCodeAt(o-1)===Wu&&--o;(r=s())!==Xu;){for(var l=[];r!==Hu&&r!==Xu;)l.push(r),r=s();n&&null==(l=n(l,u++))||i.push(l)}return i}function i(n,e){return n.map((function(n){return e.map((function(t){return a(n[t])})).join(t)}))}function o(n){return n.map(a).join(t)}function a(t){return null==t?"":t instanceof Date?Ju(t):n.test(t+="")?'"'+t.replace(/"/g,'""')+'"':t}return{parse:function(t,n){var e,i,o=r(t,(function(t,r){if(e)return e(t,r-1);i=t,e=n?function(t,n){var e=Zu(t);return function(r,i){return n(e(r),i,t)}}(t,n):Zu(t)}));return o.columns=i||[],o},parseRows:r,format:function(n,e){return null==e&&(e=Ku(n)),[e.map(a).join(t)].concat(i(n,e)).join("\n")},formatBody:function(t,n){return null==n&&(n=Ku(t)),i(t,n).join("\n")},formatRows:function(t){return t.map(o).join("\n")},formatRow:o,formatValue:a}}var nc=tc(","),ec=nc.parse,rc=nc.parseRows,ic=nc.format,oc=nc.formatBody,ac=nc.formatRows,uc=nc.formatRow,cc=nc.formatValue,fc=tc("\t"),sc=fc.parse,lc=fc.parseRows,hc=fc.format,dc=fc.formatBody,pc=fc.formatRows,gc=fc.formatRow,yc=fc.formatValue;const vc=new Date("2019-01-01T00:00").getHours()||new Date("2019-07-01T00:00").getHours();function _c(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.blob()}function bc(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.arrayBuffer()}function mc(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.text()}function xc(t,n){return fetch(t,n).then(mc)}function wc(t){return function(n,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=void 0),xc(n,e).then((function(n){return t(n,r)}))}}var Mc=wc(ec),Tc=wc(sc);function Ac(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);if(204!==t.status&&205!==t.status)return t.json()}function Sc(t){return(n,e)=>xc(n,e).then((n=>(new DOMParser).parseFromString(n,t)))}var Ec=Sc("application/xml"),Nc=Sc("text/html"),kc=Sc("image/svg+xml");function Cc(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,a,u,c,f,s,l,h,d=t._root,p={data:r},g=t._x0,y=t._y0,v=t._x1,_=t._y1;if(!d)return t._root=p,t;for(;d.length;)if((f=n>=(o=(g+v)/2))?g=o:v=o,(s=e>=(a=(y+_)/2))?y=a:_=a,i=d,!(d=d[l=s<<1|f]))return i[l]=p,t;if(u=+t._x.call(null,d.data),c=+t._y.call(null,d.data),n===u&&e===c)return p.next=d,i?i[l]=p:t._root=p,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(f=n>=(o=(g+v)/2))?g=o:v=o,(s=e>=(a=(y+_)/2))?y=a:_=a}while((l=s<<1|f)==(h=(c>=a)<<1|u>=o));return i[h]=d,i[l]=p,t}function Pc(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i}function zc(t){return t[0]}function $c(t){return t[1]}function Dc(t,n,e){var r=new Rc(null==n?zc:n,null==e?$c:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Rc(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function Fc(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var qc=Dc.prototype=Rc.prototype;function Uc(t){return function(){return t}}function Ic(t){return 1e-6*(t()-.5)}function Oc(t){return t.x+t.vx}function Bc(t){return t.y+t.vy}function Yc(t){return t.index}function Lc(t,n){var e=t.get(n);if(!e)throw new Error("node not found: "+n);return e}qc.copy=function(){var t,n,e=new Rc(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=Fc(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=Fc(n));return e},qc.add=function(t){const n=+this._x.call(null,t),e=+this._y.call(null,t);return Cc(this.cover(n,e),n,e,t)},qc.addAll=function(t){var n,e,r,i,o=t.length,a=new Array(o),u=new Array(o),c=1/0,f=1/0,s=-1/0,l=-1/0;for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(a[e]=r,u[e]=i,r<c&&(c=r),r>s&&(s=r),i<f&&(f=i),i>l&&(l=i));if(c>s||f>l)return this;for(this.cover(c,f).cover(s,l),e=0;e<o;++e)Cc(this,a[e],u[e],t[e]);return this},qc.cover=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{for(var a,u,c=i-e||1,f=this._root;e>t||t>=i||r>n||n>=o;)switch(u=(n<r)<<1|t<e,(a=new Array(4))[u]=f,f=a,c*=2,u){case 0:i=e+c,o=r+c;break;case 1:e=i-c,o=r+c;break;case 2:i=e+c,r=o-c;break;case 3:e=i-c,r=o-c}this._root&&this._root.length&&(this._root=f)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},qc.data=function(){var t=[];return this.visit((function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)})),t},qc.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},qc.find=function(t,n,e){var r,i,o,a,u,c,f,s=this._x0,l=this._y0,h=this._x1,d=this._y1,p=[],g=this._root;for(g&&p.push(new Pc(g,s,l,h,d)),null==e?e=1/0:(s=t-e,l=n-e,h=t+e,d=n+e,e*=e);c=p.pop();)if(!(!(g=c.node)||(i=c.x0)>h||(o=c.y0)>d||(a=c.x1)<s||(u=c.y1)<l))if(g.length){var y=(i+a)/2,v=(o+u)/2;p.push(new Pc(g[3],y,v,a,u),new Pc(g[2],i,v,y,u),new Pc(g[1],y,o,a,v),new Pc(g[0],i,o,y,v)),(f=(n>=v)<<1|t>=y)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-f],p[p.length-1-f]=c)}else{var _=t-+this._x.call(null,g.data),b=n-+this._y.call(null,g.data),m=_*_+b*b;if(m<e){var x=Math.sqrt(e=m);s=t-x,l=n-x,h=t+x,d=n+x,r=g.data}}return r},qc.remove=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(a=+this._y.call(null,t)))return this;var n,e,r,i,o,a,u,c,f,s,l,h,d=this._root,p=this._x0,g=this._y0,y=this._x1,v=this._y1;if(!d)return this;if(d.length)for(;;){if((f=o>=(u=(p+y)/2))?p=u:y=u,(s=a>=(c=(g+v)/2))?g=c:v=c,n=d,!(d=d[l=s<<1|f]))return this;if(!d.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[h]=d:this._root=d),this):(this._root=i,this)},qc.removeAll=function(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this},qc.root=function(){return this._root},qc.size=function(){var t=0;return this.visit((function(n){if(!n.length)do{++t}while(n=n.next)})),t},qc.visit=function(t){var n,e,r,i,o,a,u=[],c=this._root;for(c&&u.push(new Pc(c,this._x0,this._y0,this._x1,this._y1));n=u.pop();)if(!t(c=n.node,r=n.x0,i=n.y0,o=n.x1,a=n.y1)&&c.length){var f=(r+o)/2,s=(i+a)/2;(e=c[3])&&u.push(new Pc(e,f,s,o,a)),(e=c[2])&&u.push(new Pc(e,r,s,f,a)),(e=c[1])&&u.push(new Pc(e,f,i,o,s)),(e=c[0])&&u.push(new Pc(e,r,i,f,s))}return this},qc.visitAfter=function(t){var n,e=[],r=[];for(this._root&&e.push(new Pc(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,a=n.x0,u=n.y0,c=n.x1,f=n.y1,s=(a+c)/2,l=(u+f)/2;(o=i[0])&&e.push(new Pc(o,a,u,s,l)),(o=i[1])&&e.push(new Pc(o,s,u,c,l)),(o=i[2])&&e.push(new Pc(o,a,l,s,f)),(o=i[3])&&e.push(new Pc(o,s,l,c,f))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},qc.x=function(t){return arguments.length?(this._x=t,this):this._x},qc.y=function(t){return arguments.length?(this._y=t,this):this._y};const jc=1664525,Hc=1013904223,Xc=4294967296;function Gc(t){return t.x}function Vc(t){return t.y}var Wc=Math.PI*(3-Math.sqrt(5));function Zc(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]}function Kc(t){return(t=Zc(Math.abs(t)))?t[1]:NaN}var Qc,Jc=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function tf(t){if(!(n=Jc.exec(t)))throw new Error("invalid format: "+t);var n;return new nf({fill:n[1],align:n[2],sign:n[3],symbol:n[4],zero:n[5],width:n[6],comma:n[7],precision:n[8]&&n[8].slice(1),trim:n[9],type:n[10]})}function nf(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function ef(t,n){var e=Zc(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}tf.prototype=nf.prototype,nf.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var rf={"%":(t,n)=>(100*t).toFixed(n),b:t=>Math.round(t).toString(2),c:t=>t+"",d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:(t,n)=>t.toExponential(n),f:(t,n)=>t.toFixed(n),g:(t,n)=>t.toPrecision(n),o:t=>Math.round(t).toString(8),p:(t,n)=>ef(100*t,n),r:ef,s:function(t,n){var e=Zc(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(Qc=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,a=r.length;return o===a?r:o>a?r+new Array(o-a+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+Zc(t,Math.max(0,n+o-1))[0]},X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function of(t){return t}var af,uf=Array.prototype.map,cf=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function ff(t){var n,e,r=void 0===t.grouping||void 0===t.thousands?of:(n=uf.call(t.grouping,Number),e=t.thousands+"",function(t,r){for(var i=t.length,o=[],a=0,u=n[0],c=0;i>0&&u>0&&(c+u+1>r&&(u=Math.max(1,r-c)),o.push(t.substring(i-=u,i+u)),!((c+=u+1)>r));)u=n[a=(a+1)%n.length];return o.reverse().join(e)}),i=void 0===t.currency?"":t.currency[0]+"",o=void 0===t.currency?"":t.currency[1]+"",a=void 0===t.decimal?".":t.decimal+"",u=void 0===t.numerals?of:function(t){return function(n){return n.replace(/[0-9]/g,(function(n){return t[+n]}))}}(uf.call(t.numerals,String)),c=void 0===t.percent?"%":t.percent+"",f=void 0===t.minus?"−":t.minus+"",s=void 0===t.nan?"NaN":t.nan+"";function l(t){var n=(t=tf(t)).fill,e=t.align,l=t.sign,h=t.symbol,d=t.zero,p=t.width,g=t.comma,y=t.precision,v=t.trim,_=t.type;"n"===_?(g=!0,_="g"):rf[_]||(void 0===y&&(y=12),v=!0,_="g"),(d||"0"===n&&"="===e)&&(d=!0,n="0",e="=");var b="$"===h?i:"#"===h&&/[boxX]/.test(_)?"0"+_.toLowerCase():"",m="$"===h?o:/[%p]/.test(_)?c:"",x=rf[_],w=/[defgprs%]/.test(_);function M(t){var i,o,c,h=b,M=m;if("c"===_)M=x(t)+M,t="";else{var T=(t=+t)<0||1/t<0;if(t=isNaN(t)?s:x(Math.abs(t),y),v&&(t=function(t){t:for(var n,e=t.length,r=1,i=-1;r<e;++r)switch(t[r]){case".":i=n=r;break;case"0":0===i&&(i=r),n=r;break;default:if(!+t[r])break t;i>0&&(i=0)}return i>0?t.slice(0,i)+t.slice(n+1):t}(t)),T&&0==+t&&"+"!==l&&(T=!1),h=(T?"("===l?l:f:"-"===l||"("===l?"":l)+h,M=("s"===_?cf[8+Qc/3]:"")+M+(T&&"("===l?")":""),w)for(i=-1,o=t.length;++i<o;)if(48>(c=t.charCodeAt(i))||c>57){M=(46===c?a+t.slice(i+1):t.slice(i))+M,t=t.slice(0,i);break}}g&&!d&&(t=r(t,1/0));var A=h.length+t.length+M.length,S=A<p?new Array(p-A+1).join(n):"";switch(g&&d&&(t=r(S+t,S.length?p-M.length:1/0),S=""),e){case"<":t=h+t+M+S;break;case"=":t=h+S+t+M;break;case"^":t=S.slice(0,A=S.length>>1)+h+t+M+S.slice(A);break;default:t=S+h+t+M}return u(t)}return y=void 0===y?6:/[gprs]/.test(_)?Math.max(1,Math.min(21,y)):Math.max(0,Math.min(20,y)),M.toString=function(){return t+""},M}return{format:l,formatPrefix:function(t,n){var e=l(((t=tf(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(Kc(n)/3))),i=Math.pow(10,-r),o=cf[8+r/3];return function(t){return e(i*t)+o}}}}function sf(n){return af=ff(n),t.format=af.format,t.formatPrefix=af.formatPrefix,af}function lf(t){return Math.max(0,-Kc(Math.abs(t)))}function hf(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(Kc(n)/3)))-Kc(Math.abs(t)))}function df(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,Kc(n)-Kc(t))+1}t.format=void 0,t.formatPrefix=void 0,sf({thousands:",",grouping:[3],currency:["$",""]});var pf=1e-6,gf=1e-12,yf=Math.PI,vf=yf/2,_f=yf/4,bf=2*yf,mf=180/yf,xf=yf/180,wf=Math.abs,Mf=Math.atan,Tf=Math.atan2,Af=Math.cos,Sf=Math.ceil,Ef=Math.exp,Nf=Math.hypot,kf=Math.log,Cf=Math.pow,Pf=Math.sin,zf=Math.sign||function(t){return t>0?1:t<0?-1:0},$f=Math.sqrt,Df=Math.tan;function Rf(t){return t>1?0:t<-1?yf:Math.acos(t)}function Ff(t){return t>1?vf:t<-1?-vf:Math.asin(t)}function qf(t){return(t=Pf(t/2))*t}function Uf(){}function If(t,n){t&&Bf.hasOwnProperty(t.type)&&Bf[t.type](t,n)}var Of={Feature:function(t,n){If(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)If(e[r].geometry,n)}},Bf={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){Yf(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)Yf(e[r],n,0)},Polygon:function(t,n){Lf(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)Lf(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)If(e[r],n)}};function Yf(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function Lf(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)Yf(t[e],n,1);n.polygonEnd()}function jf(t,n){t&&Of.hasOwnProperty(t.type)?Of[t.type](t,n):If(t,n)}var Hf,Xf,Gf,Vf,Wf,Zf,Kf,Qf,Jf,ts,ns,es,rs,is,os,as,us=new A,cs=new A,fs={point:Uf,lineStart:Uf,lineEnd:Uf,polygonStart:function(){us=new A,fs.lineStart=ss,fs.lineEnd=ls},polygonEnd:function(){var t=+us;cs.add(t<0?bf+t:t),this.lineStart=this.lineEnd=this.point=Uf},sphere:function(){cs.add(bf)}};function ss(){fs.point=hs}function ls(){ds(Hf,Xf)}function hs(t,n){fs.point=ds,Hf=t,Xf=n,Gf=t*=xf,Vf=Af(n=(n*=xf)/2+_f),Wf=Pf(n)}function ds(t,n){var e=(t*=xf)-Gf,r=e>=0?1:-1,i=r*e,o=Af(n=(n*=xf)/2+_f),a=Pf(n),u=Wf*a,c=Vf*o+u*Af(i),f=u*r*Pf(i);us.add(Tf(f,c)),Gf=t,Vf=o,Wf=a}function ps(t){return[Tf(t[1],t[0]),Ff(t[2])]}function gs(t){var n=t[0],e=t[1],r=Af(e);return[r*Af(n),r*Pf(n),Pf(e)]}function ys(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function vs(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function _s(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function bs(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function ms(t){var n=$f(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}var xs,ws,Ms,Ts,As,Ss,Es,Ns,ks,Cs,Ps,zs,$s,Ds,Rs,Fs,qs={point:Us,lineStart:Os,lineEnd:Bs,polygonStart:function(){qs.point=Ys,qs.lineStart=Ls,qs.lineEnd=js,is=new A,fs.polygonStart()},polygonEnd:function(){fs.polygonEnd(),qs.point=Us,qs.lineStart=Os,qs.lineEnd=Bs,us<0?(Zf=-(Qf=180),Kf=-(Jf=90)):is>pf?Jf=90:is<-pf&&(Kf=-90),as[0]=Zf,as[1]=Qf},sphere:function(){Zf=-(Qf=180),Kf=-(Jf=90)}};function Us(t,n){os.push(as=[Zf=t,Qf=t]),n<Kf&&(Kf=n),n>Jf&&(Jf=n)}function Is(t,n){var e=gs([t*xf,n*xf]);if(rs){var r=vs(rs,e),i=vs([r[1],-r[0],0],r);ms(i),i=ps(i);var o,a=t-ts,u=a>0?1:-1,c=i[0]*mf*u,f=wf(a)>180;f^(u*ts<c&&c<u*t)?(o=i[1]*mf)>Jf&&(Jf=o):f^(u*ts<(c=(c+360)%360-180)&&c<u*t)?(o=-i[1]*mf)<Kf&&(Kf=o):(n<Kf&&(Kf=n),n>Jf&&(Jf=n)),f?t<ts?Hs(Zf,t)>Hs(Zf,Qf)&&(Qf=t):Hs(t,Qf)>Hs(Zf,Qf)&&(Zf=t):Qf>=Zf?(t<Zf&&(Zf=t),t>Qf&&(Qf=t)):t>ts?Hs(Zf,t)>Hs(Zf,Qf)&&(Qf=t):Hs(t,Qf)>Hs(Zf,Qf)&&(Zf=t)}else os.push(as=[Zf=t,Qf=t]);n<Kf&&(Kf=n),n>Jf&&(Jf=n),rs=e,ts=t}function Os(){qs.point=Is}function Bs(){as[0]=Zf,as[1]=Qf,qs.point=Us,rs=null}function Ys(t,n){if(rs){var e=t-ts;is.add(wf(e)>180?e+(e>0?360:-360):e)}else ns=t,es=n;fs.point(t,n),Is(t,n)}function Ls(){fs.lineStart()}function js(){Ys(ns,es),fs.lineEnd(),wf(is)>pf&&(Zf=-(Qf=180)),as[0]=Zf,as[1]=Qf,rs=null}function Hs(t,n){return(n-=t)<0?n+360:n}function Xs(t,n){return t[0]-n[0]}function Gs(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var Vs={sphere:Uf,point:Ws,lineStart:Ks,lineEnd:tl,polygonStart:function(){Vs.lineStart=nl,Vs.lineEnd=el},polygonEnd:function(){Vs.lineStart=Ks,Vs.lineEnd=tl}};function Ws(t,n){t*=xf;var e=Af(n*=xf);Zs(e*Af(t),e*Pf(t),Pf(n))}function Zs(t,n,e){++xs,Ms+=(t-Ms)/xs,Ts+=(n-Ts)/xs,As+=(e-As)/xs}function Ks(){Vs.point=Qs}function Qs(t,n){t*=xf;var e=Af(n*=xf);Ds=e*Af(t),Rs=e*Pf(t),Fs=Pf(n),Vs.point=Js,Zs(Ds,Rs,Fs)}function Js(t,n){t*=xf;var e=Af(n*=xf),r=e*Af(t),i=e*Pf(t),o=Pf(n),a=Tf($f((a=Rs*o-Fs*i)*a+(a=Fs*r-Ds*o)*a+(a=Ds*i-Rs*r)*a),Ds*r+Rs*i+Fs*o);ws+=a,Ss+=a*(Ds+(Ds=r)),Es+=a*(Rs+(Rs=i)),Ns+=a*(Fs+(Fs=o)),Zs(Ds,Rs,Fs)}function tl(){Vs.point=Ws}function nl(){Vs.point=rl}function el(){il(zs,$s),Vs.point=Ws}function rl(t,n){zs=t,$s=n,t*=xf,n*=xf,Vs.point=il;var e=Af(n);Ds=e*Af(t),Rs=e*Pf(t),Fs=Pf(n),Zs(Ds,Rs,Fs)}function il(t,n){t*=xf;var e=Af(n*=xf),r=e*Af(t),i=e*Pf(t),o=Pf(n),a=Rs*o-Fs*i,u=Fs*r-Ds*o,c=Ds*i-Rs*r,f=Nf(a,u,c),s=Ff(f),l=f&&-s/f;ks.add(l*a),Cs.add(l*u),Ps.add(l*c),ws+=s,Ss+=s*(Ds+(Ds=r)),Es+=s*(Rs+(Rs=i)),Ns+=s*(Fs+(Fs=o)),Zs(Ds,Rs,Fs)}function ol(t){return function(){return t}}function al(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return(e=n.invert(e,r))&&t.invert(e[0],e[1])}),e}function ul(t,n){return wf(t)>yf&&(t-=Math.round(t/bf)*bf),[t,n]}function cl(t,n,e){return(t%=bf)?n||e?al(sl(t),ll(n,e)):sl(t):n||e?ll(n,e):ul}function fl(t){return function(n,e){return wf(n+=t)>yf&&(n-=Math.round(n/bf)*bf),[n,e]}}function sl(t){var n=fl(t);return n.invert=fl(-t),n}function ll(t,n){var e=Af(t),r=Pf(t),i=Af(n),o=Pf(n);function a(t,n){var a=Af(n),u=Af(t)*a,c=Pf(t)*a,f=Pf(n),s=f*e+u*r;return[Tf(c*i-s*o,u*e-f*r),Ff(s*i+c*o)]}return a.invert=function(t,n){var a=Af(n),u=Af(t)*a,c=Pf(t)*a,f=Pf(n),s=f*i-c*o;return[Tf(c*i+f*o,u*e+s*r),Ff(s*e-u*r)]},a}function hl(t){function n(n){return(n=t(n[0]*xf,n[1]*xf))[0]*=mf,n[1]*=mf,n}return t=cl(t[0]*xf,t[1]*xf,t.length>2?t[2]*xf:0),n.invert=function(n){return(n=t.invert(n[0]*xf,n[1]*xf))[0]*=mf,n[1]*=mf,n},n}function dl(t,n,e,r,i,o){if(e){var a=Af(n),u=Pf(n),c=r*e;null==i?(i=n+r*bf,o=n-c/2):(i=pl(a,i),o=pl(a,o),(r>0?i<o:i>o)&&(i+=r*bf));for(var f,s=i;r>0?s>o:s<o;s-=c)f=ps([a,-u*Af(s),-u*Pf(s)]),t.point(f[0],f[1])}}function pl(t,n){(n=gs(n))[0]-=t,ms(n);var e=Rf(-n[1]);return((-n[2]<0?-e:e)+bf-pf)%bf}function gl(){var t,n=[];return{point:function(n,e,r){t.push([n,e,r])},lineStart:function(){n.push(t=[])},lineEnd:Uf,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}}function yl(t,n){return wf(t[0]-n[0])<pf&&wf(t[1]-n[1])<pf}function vl(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function _l(t,n,e,r,i){var o,a,u=[],c=[];if(t.forEach((function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],a=t[n];if(yl(r,a)){if(!r[2]&&!a[2]){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);return void i.lineEnd()}a[0]+=2*pf}u.push(e=new vl(r,t,null,!0)),c.push(e.o=new vl(r,null,e,!1)),u.push(e=new vl(a,t,null,!1)),c.push(e.o=new vl(a,null,e,!0))}})),u.length){for(c.sort(n),bl(u),bl(c),o=0,a=c.length;o<a;++o)c[o].e=e=!e;for(var f,s,l=u[0];;){for(var h=l,d=!0;h.v;)if((h=h.n)===l)return;f=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(d)for(o=0,a=f.length;o<a;++o)i.point((s=f[o])[0],s[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(d)for(f=h.p.z,o=f.length-1;o>=0;--o)i.point((s=f[o])[0],s[1]);else r(h.x,h.p.x,-1,i);h=h.p}f=(h=h.o).z,d=!d}while(!h.v);i.lineEnd()}}}function bl(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}function ml(t){return wf(t[0])<=yf?t[0]:zf(t[0])*((wf(t[0])+yf)%bf-yf)}function xl(t,n){var e=ml(n),r=n[1],i=Pf(r),o=[Pf(e),-Af(e),0],a=0,u=0,c=new A;1===i?r=vf+pf:-1===i&&(r=-vf-pf);for(var f=0,s=t.length;f<s;++f)if(h=(l=t[f]).length)for(var l,h,d=l[h-1],p=ml(d),g=d[1]/2+_f,y=Pf(g),v=Af(g),_=0;_<h;++_,p=m,y=w,v=M,d=b){var b=l[_],m=ml(b),x=b[1]/2+_f,w=Pf(x),M=Af(x),T=m-p,S=T>=0?1:-1,E=S*T,N=E>yf,k=y*w;if(c.add(Tf(k*S*Pf(E),v*M+k*Af(E))),a+=N?T+S*bf:T,N^p>=e^m>=e){var C=vs(gs(d),gs(b));ms(C);var P=vs(o,C);ms(P);var z=(N^T>=0?-1:1)*Ff(P[2]);(r>z||r===z&&(C[0]||C[1]))&&(u+=N^T>=0?1:-1)}}return(a<-pf||a<pf&&c<-gf)^1&u}function wl(t,n,e,r){return function(i){var o,a,u,c=n(i),f=gl(),s=n(f),l=!1,h={point:d,lineStart:g,lineEnd:y,polygonStart:function(){h.point=v,h.lineStart=_,h.lineEnd=b,a=[],o=[]},polygonEnd:function(){h.point=d,h.lineStart=g,h.lineEnd=y,a=st(a);var t=xl(o,r);a.length?(l||(i.polygonStart(),l=!0),_l(a,Tl,t,e,i)):t&&(l||(i.polygonStart(),l=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),l&&(i.polygonEnd(),l=!1),a=o=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}};function d(n,e){t(n,e)&&i.point(n,e)}function p(t,n){c.point(t,n)}function g(){h.point=p,c.lineStart()}function y(){h.point=d,c.lineEnd()}function v(t,n){u.push([t,n]),s.point(t,n)}function _(){s.lineStart(),u=[]}function b(){v(u[0][0],u[0][1]),s.lineEnd();var t,n,e,r,c=s.clean(),h=f.result(),d=h.length;if(u.pop(),o.push(u),u=null,d)if(1&c){if((n=(e=h[0]).length-1)>0){for(l||(i.polygonStart(),l=!0),i.lineStart(),t=0;t<n;++t)i.point((r=e[t])[0],r[1]);i.lineEnd()}}else d>1&&2&c&&h.push(h.pop().concat(h.shift())),a.push(h.filter(Ml))}return h}}function Ml(t){return t.length>1}function Tl(t,n){return((t=t.x)[0]<0?t[1]-vf-pf:vf-t[1])-((n=n.x)[0]<0?n[1]-vf-pf:vf-n[1])}ul.invert=ul;var Al=wl((function(){return!0}),(function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,a){var u=o>0?yf:-yf,c=wf(o-e);wf(c-yf)<pf?(t.point(e,r=(r+a)/2>0?vf:-vf),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),t.point(o,r),n=0):i!==u&&c>=yf&&(wf(e-i)<pf&&(e-=i*pf),wf(o-u)<pf&&(o-=u*pf),r=function(t,n,e,r){var i,o,a=Pf(t-e);return wf(a)>pf?Mf((Pf(n)*(o=Af(r))*Pf(e)-Pf(r)*(i=Af(n))*Pf(t))/(i*o*a)):(n+r)/2}(e,r,o,a),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),n=0),t.point(e=o,r=a),i=u},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}}),(function(t,n,e,r){var i;if(null==t)i=e*vf,r.point(-yf,i),r.point(0,i),r.point(yf,i),r.point(yf,0),r.point(yf,-i),r.point(0,-i),r.point(-yf,-i),r.point(-yf,0),r.point(-yf,i);else if(wf(t[0]-n[0])>pf){var o=t[0]<n[0]?yf:-yf;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])}),[-yf,-vf]);function Sl(t){var n=Af(t),e=6*xf,r=n>0,i=wf(n)>pf;function o(t,e){return Af(t)*Af(e)>n}function a(t,e,r){var i=[1,0,0],o=vs(gs(t),gs(e)),a=ys(o,o),u=o[0],c=a-u*u;if(!c)return!r&&t;var f=n*a/c,s=-n*u/c,l=vs(i,o),h=bs(i,f);_s(h,bs(o,s));var d=l,p=ys(h,d),g=ys(d,d),y=p*p-g*(ys(h,h)-1);if(!(y<0)){var v=$f(y),_=bs(d,(-p-v)/g);if(_s(_,h),_=ps(_),!r)return _;var b,m=t[0],x=e[0],w=t[1],M=e[1];x<m&&(b=m,m=x,x=b);var T=x-m,A=wf(T-yf)<pf;if(!A&&M<w&&(b=w,w=M,M=b),A||T<pf?A?w+M>0^_[1]<(wf(_[0]-m)<pf?w:M):w<=_[1]&&_[1]<=M:T>yf^(m<=_[0]&&_[0]<=x)){var S=bs(d,(-p+v)/g);return _s(S,h),[_,ps(S)]}}}function u(n,e){var i=r?t:yf-t,o=0;return n<-i?o|=1:n>i&&(o|=2),e<-i?o|=4:e>i&&(o|=8),o}return wl(o,(function(t){var n,e,c,f,s;return{lineStart:function(){f=c=!1,s=1},point:function(l,h){var d,p=[l,h],g=o(l,h),y=r?g?0:u(l,h):g?u(l+(l<0?yf:-yf),h):0;if(!n&&(f=c=g)&&t.lineStart(),g!==c&&(!(d=a(n,p))||yl(n,d)||yl(p,d))&&(p[2]=1),g!==c)s=0,g?(t.lineStart(),d=a(p,n),t.point(d[0],d[1])):(d=a(n,p),t.point(d[0],d[1],2),t.lineEnd()),n=d;else if(i&&n&&r^g){var v;y&e||!(v=a(p,n,!0))||(s=0,r?(t.lineStart(),t.point(v[0][0],v[0][1]),t.point(v[1][0],v[1][1]),t.lineEnd()):(t.point(v[1][0],v[1][1]),t.lineEnd(),t.lineStart(),t.point(v[0][0],v[0][1],3)))}!g||n&&yl(n,p)||t.point(p[0],p[1]),n=p,c=g,e=y},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return s|(f&&c)<<1}}}),(function(n,r,i,o){dl(o,t,e,i,n,r)}),r?[0,-t]:[-yf,t-yf])}var El,Nl,kl,Cl,Pl=1e9,zl=-Pl;function $l(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,u,f){var s=0,l=0;if(null==i||(s=a(i,u))!==(l=a(o,u))||c(i,o)<0^u>0)do{f.point(0===s||3===s?t:e,s>1?r:n)}while((s=(s+u+4)%4)!==l);else f.point(o[0],o[1])}function a(r,i){return wf(r[0]-t)<pf?i>0?0:3:wf(r[0]-e)<pf?i>0?2:1:wf(r[1]-n)<pf?i>0?1:0:i>0?3:2}function u(t,n){return c(t.x,n.x)}function c(t,n){var e=a(t,1),r=a(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(a){var c,f,s,l,h,d,p,g,y,v,_,b=a,m=gl(),x={point:w,lineStart:function(){x.point=M,f&&f.push(s=[]);v=!0,y=!1,p=g=NaN},lineEnd:function(){c&&(M(l,h),d&&y&&m.rejoin(),c.push(m.result()));x.point=w,y&&b.lineEnd()},polygonStart:function(){b=m,c=[],f=[],_=!0},polygonEnd:function(){var n=function(){for(var n=0,e=0,i=f.length;e<i;++e)for(var o,a,u=f[e],c=1,s=u.length,l=u[0],h=l[0],d=l[1];c<s;++c)o=h,a=d,h=(l=u[c])[0],d=l[1],a<=r?d>r&&(h-o)*(r-a)>(d-a)*(t-o)&&++n:d<=r&&(h-o)*(r-a)<(d-a)*(t-o)&&--n;return n}(),e=_&&n,i=(c=st(c)).length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),o(null,null,1,a),a.lineEnd()),i&&_l(c,u,n,o,a),a.polygonEnd());b=a,c=f=s=null}};function w(t,n){i(t,n)&&b.point(t,n)}function M(o,a){var u=i(o,a);if(f&&s.push([o,a]),v)l=o,h=a,d=u,v=!1,u&&(b.lineStart(),b.point(o,a));else if(u&&y)b.point(o,a);else{var c=[p=Math.max(zl,Math.min(Pl,p)),g=Math.max(zl,Math.min(Pl,g))],m=[o=Math.max(zl,Math.min(Pl,o)),a=Math.max(zl,Math.min(Pl,a))];!function(t,n,e,r,i,o){var a,u=t[0],c=t[1],f=0,s=1,l=n[0]-u,h=n[1]-c;if(a=e-u,l||!(a>0)){if(a/=l,l<0){if(a<f)return;a<s&&(s=a)}else if(l>0){if(a>s)return;a>f&&(f=a)}if(a=i-u,l||!(a<0)){if(a/=l,l<0){if(a>s)return;a>f&&(f=a)}else if(l>0){if(a<f)return;a<s&&(s=a)}if(a=r-c,h||!(a>0)){if(a/=h,h<0){if(a<f)return;a<s&&(s=a)}else if(h>0){if(a>s)return;a>f&&(f=a)}if(a=o-c,h||!(a<0)){if(a/=h,h<0){if(a>s)return;a>f&&(f=a)}else if(h>0){if(a<f)return;a<s&&(s=a)}return f>0&&(t[0]=u+f*l,t[1]=c+f*h),s<1&&(n[0]=u+s*l,n[1]=c+s*h),!0}}}}}(c,m,t,n,e,r)?u&&(b.lineStart(),b.point(o,a),_=!1):(y||(b.lineStart(),b.point(c[0],c[1])),b.point(m[0],m[1]),u||b.lineEnd(),_=!1)}p=o,g=a,y=u}return x}}var Dl={sphere:Uf,point:Uf,lineStart:function(){Dl.point=Fl,Dl.lineEnd=Rl},lineEnd:Uf,polygonStart:Uf,polygonEnd:Uf};function Rl(){Dl.point=Dl.lineEnd=Uf}function Fl(t,n){Nl=t*=xf,kl=Pf(n*=xf),Cl=Af(n),Dl.point=ql}function ql(t,n){t*=xf;var e=Pf(n*=xf),r=Af(n),i=wf(t-Nl),o=Af(i),a=r*Pf(i),u=Cl*e-kl*r*o,c=kl*e+Cl*r*o;El.add(Tf($f(a*a+u*u),c)),Nl=t,kl=e,Cl=r}function Ul(t){return El=new A,jf(t,Dl),+El}var Il=[null,null],Ol={type:"LineString",coordinates:Il};function Bl(t,n){return Il[0]=t,Il[1]=n,Ul(Ol)}var Yl={Feature:function(t,n){return jl(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)if(jl(e[r].geometry,n))return!0;return!1}},Ll={Sphere:function(){return!0},Point:function(t,n){return Hl(t.coordinates,n)},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Hl(e[r],n))return!0;return!1},LineString:function(t,n){return Xl(t.coordinates,n)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Xl(e[r],n))return!0;return!1},Polygon:function(t,n){return Gl(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Gl(e[r],n))return!0;return!1},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)if(jl(e[r],n))return!0;return!1}};function jl(t,n){return!(!t||!Ll.hasOwnProperty(t.type))&&Ll[t.type](t,n)}function Hl(t,n){return 0===Bl(t,n)}function Xl(t,n){for(var e,r,i,o=0,a=t.length;o<a;o++){if(0===(r=Bl(t[o],n)))return!0;if(o>0&&(i=Bl(t[o],t[o-1]))>0&&e<=i&&r<=i&&(e+r-i)*(1-Math.pow((e-r)/i,2))<gf*i)return!0;e=r}return!1}function Gl(t,n){return!!xl(t.map(Vl),Wl(n))}function Vl(t){return(t=t.map(Wl)).pop(),t}function Wl(t){return[t[0]*xf,t[1]*xf]}function Zl(t,n,e){var r=ht(t,n-pf,e).concat(n);return function(t){return r.map((function(n){return[t,n]}))}}function Kl(t,n,e){var r=ht(t,n-pf,e).concat(n);return function(t){return r.map((function(n){return[n,t]}))}}function Ql(){var t,n,e,r,i,o,a,u,c,f,s,l,h=10,d=h,p=90,g=360,y=2.5;function v(){return{type:"MultiLineString",coordinates:_()}}function _(){return ht(Sf(r/p)*p,e,p).map(s).concat(ht(Sf(u/g)*g,a,g).map(l)).concat(ht(Sf(n/h)*h,t,h).filter((function(t){return wf(t%p)>pf})).map(c)).concat(ht(Sf(o/d)*d,i,d).filter((function(t){return wf(t%g)>pf})).map(f))}return v.lines=function(){return _().map((function(t){return{type:"LineString",coordinates:t}}))},v.outline=function(){return{type:"Polygon",coordinates:[s(r).concat(l(a).slice(1),s(e).reverse().slice(1),l(u).reverse().slice(1))]}},v.extent=function(t){return arguments.length?v.extentMajor(t).extentMinor(t):v.extentMinor()},v.extentMajor=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],u=+t[0][1],a=+t[1][1],r>e&&(t=r,r=e,e=t),u>a&&(t=u,u=a,a=t),v.precision(y)):[[r,u],[e,a]]},v.extentMinor=function(e){return arguments.length?(n=+e[0][0],t=+e[1][0],o=+e[0][1],i=+e[1][1],n>t&&(e=n,n=t,t=e),o>i&&(e=o,o=i,i=e),v.precision(y)):[[n,o],[t,i]]},v.step=function(t){return arguments.length?v.stepMajor(t).stepMinor(t):v.stepMinor()},v.stepMajor=function(t){return arguments.length?(p=+t[0],g=+t[1],v):[p,g]},v.stepMinor=function(t){return arguments.length?(h=+t[0],d=+t[1],v):[h,d]},v.precision=function(h){return arguments.length?(y=+h,c=Zl(o,i,90),f=Kl(n,t,y),s=Zl(u,a,90),l=Kl(r,e,y),v):y},v.extentMajor([[-180,-90+pf],[180,90-pf]]).extentMinor([[-180,-80-pf],[180,80+pf]])}var Jl,th,nh,eh,rh=t=>t,ih=new A,oh=new A,ah={point:Uf,lineStart:Uf,lineEnd:Uf,polygonStart:function(){ah.lineStart=uh,ah.lineEnd=sh},polygonEnd:function(){ah.lineStart=ah.lineEnd=ah.point=Uf,ih.add(wf(oh)),oh=new A},result:function(){var t=ih/2;return ih=new A,t}};function uh(){ah.point=ch}function ch(t,n){ah.point=fh,Jl=nh=t,th=eh=n}function fh(t,n){oh.add(eh*t-nh*n),nh=t,eh=n}function sh(){fh(Jl,th)}var lh=ah,hh=1/0,dh=hh,ph=-hh,gh=ph,yh={point:function(t,n){t<hh&&(hh=t);t>ph&&(ph=t);n<dh&&(dh=n);n>gh&&(gh=n)},lineStart:Uf,lineEnd:Uf,polygonStart:Uf,polygonEnd:Uf,result:function(){var t=[[hh,dh],[ph,gh]];return ph=gh=-(dh=hh=1/0),t}};var vh,_h,bh,mh,xh=yh,wh=0,Mh=0,Th=0,Ah=0,Sh=0,Eh=0,Nh=0,kh=0,Ch=0,Ph={point:zh,lineStart:$h,lineEnd:Fh,polygonStart:function(){Ph.lineStart=qh,Ph.lineEnd=Uh},polygonEnd:function(){Ph.point=zh,Ph.lineStart=$h,Ph.lineEnd=Fh},result:function(){var t=Ch?[Nh/Ch,kh/Ch]:Eh?[Ah/Eh,Sh/Eh]:Th?[wh/Th,Mh/Th]:[NaN,NaN];return wh=Mh=Th=Ah=Sh=Eh=Nh=kh=Ch=0,t}};function zh(t,n){wh+=t,Mh+=n,++Th}function $h(){Ph.point=Dh}function Dh(t,n){Ph.point=Rh,zh(bh=t,mh=n)}function Rh(t,n){var e=t-bh,r=n-mh,i=$f(e*e+r*r);Ah+=i*(bh+t)/2,Sh+=i*(mh+n)/2,Eh+=i,zh(bh=t,mh=n)}function Fh(){Ph.point=zh}function qh(){Ph.point=Ih}function Uh(){Oh(vh,_h)}function Ih(t,n){Ph.point=Oh,zh(vh=bh=t,_h=mh=n)}function Oh(t,n){var e=t-bh,r=n-mh,i=$f(e*e+r*r);Ah+=i*(bh+t)/2,Sh+=i*(mh+n)/2,Eh+=i,Nh+=(i=mh*t-bh*n)*(bh+t),kh+=i*(mh+n),Ch+=3*i,zh(bh=t,mh=n)}var Bh=Ph;function Yh(t){this._context=t}Yh.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,bf)}},result:Uf};var Lh,jh,Hh,Xh,Gh,Vh=new A,Wh={point:Uf,lineStart:function(){Wh.point=Zh},lineEnd:function(){Lh&&Kh(jh,Hh),Wh.point=Uf},polygonStart:function(){Lh=!0},polygonEnd:function(){Lh=null},result:function(){var t=+Vh;return Vh=new A,t}};function Zh(t,n){Wh.point=Kh,jh=Xh=t,Hh=Gh=n}function Kh(t,n){Xh-=t,Gh-=n,Vh.add($f(Xh*Xh+Gh*Gh)),Xh=t,Gh=n}var Qh=Wh;let Jh,td,nd,ed;class rd{constructor(t){this._append=null==t?id:function(t){const n=Math.floor(t);if(!(n>=0))throw new RangeError(`invalid digits: ${t}`);if(n>15)return id;if(n!==Jh){const t=10**n;Jh=n,td=function(n){let e=1;this._+=n[0];for(const r=n.length;e<r;++e)this._+=Math.round(arguments[e]*t)/t+n[e]}}return td}(t),this._radius=4.5,this._=""}pointRadius(t){return this._radius=+t,this}polygonStart(){this._line=0}polygonEnd(){this._line=NaN}lineStart(){this._point=0}lineEnd(){0===this._line&&(this._+="Z"),this._point=NaN}point(t,n){switch(this._point){case 0:this._append`M${t},${n}`,this._point=1;break;case 1:this._append`L${t},${n}`;break;default:if(this._append`M${t},${n}`,this._radius!==nd||this._append!==td){const t=this._radius,n=this._;this._="",this._append`m0,${t}a${t},${t} 0 1,1 0,${-2*t}a${t},${t} 0 1,1 0,${2*t}z`,nd=t,td=this._append,ed=this._,this._=n}this._+=ed}}result(){const t=this._;return this._="",t.length?t:null}}function id(t){let n=1;this._+=t[0];for(const e=t.length;n<e;++n)this._+=arguments[n]+t[n]}function od(t){return function(n){var e=new ad;for(var r in t)e[r]=t[r];return e.stream=n,e}}function ad(){}function ud(t,n,e){var r=t.clipExtent&&t.clipExtent();return t.scale(150).translate([0,0]),null!=r&&t.clipExtent(null),jf(e,t.stream(xh)),n(xh.result()),null!=r&&t.clipExtent(r),t}function cd(t,n,e){return ud(t,(function(e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=Math.min(r/(e[1][0]-e[0][0]),i/(e[1][1]-e[0][1])),a=+n[0][0]+(r-o*(e[1][0]+e[0][0]))/2,u=+n[0][1]+(i-o*(e[1][1]+e[0][1]))/2;t.scale(150*o).translate([a,u])}),e)}function fd(t,n,e){return cd(t,[[0,0],n],e)}function sd(t,n,e){return ud(t,(function(e){var r=+n,i=r/(e[1][0]-e[0][0]),o=(r-i*(e[1][0]+e[0][0]))/2,a=-i*e[0][1];t.scale(150*i).translate([o,a])}),e)}function ld(t,n,e){return ud(t,(function(e){var r=+n,i=r/(e[1][1]-e[0][1]),o=-i*e[0][0],a=(r-i*(e[1][1]+e[0][1]))/2;t.scale(150*i).translate([o,a])}),e)}ad.prototype={constructor:ad,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var hd=16,dd=Af(30*xf);function pd(t,n){return+n?function(t,n){function e(r,i,o,a,u,c,f,s,l,h,d,p,g,y){var v=f-r,_=s-i,b=v*v+_*_;if(b>4*n&&g--){var m=a+h,x=u+d,w=c+p,M=$f(m*m+x*x+w*w),T=Ff(w/=M),A=wf(wf(w)-1)<pf||wf(o-l)<pf?(o+l)/2:Tf(x,m),S=t(A,T),E=S[0],N=S[1],k=E-r,C=N-i,P=_*k-v*C;(P*P/b>n||wf((v*k+_*C)/b-.5)>.3||a*h+u*d+c*p<dd)&&(e(r,i,o,a,u,c,E,N,A,m/=M,x/=M,w,g,y),y.point(E,N),e(E,N,A,m,x,w,f,s,l,h,d,p,g,y))}}return function(n){var r,i,o,a,u,c,f,s,l,h,d,p,g={point:y,lineStart:v,lineEnd:b,polygonStart:function(){n.polygonStart(),g.lineStart=m},polygonEnd:function(){n.polygonEnd(),g.lineStart=v}};function y(e,r){e=t(e,r),n.point(e[0],e[1])}function v(){s=NaN,g.point=_,n.lineStart()}function _(r,i){var o=gs([r,i]),a=t(r,i);e(s,l,f,h,d,p,s=a[0],l=a[1],f=r,h=o[0],d=o[1],p=o[2],hd,n),n.point(s,l)}function b(){g.point=y,n.lineEnd()}function m(){v(),g.point=x,g.lineEnd=w}function x(t,n){_(r=t,n),i=s,o=l,a=h,u=d,c=p,g.point=_}function w(){e(s,l,f,h,d,p,i,o,r,a,u,c,hd,n),g.lineEnd=b,b()}return g}}(t,n):function(t){return od({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}(t)}var gd=od({point:function(t,n){this.stream.point(t*xf,n*xf)}});function yd(t,n,e,r,i,o){if(!o)return function(t,n,e,r,i){function o(o,a){return[n+t*(o*=r),e-t*(a*=i)]}return o.invert=function(o,a){return[(o-n)/t*r,(e-a)/t*i]},o}(t,n,e,r,i);var a=Af(o),u=Pf(o),c=a*t,f=u*t,s=a/t,l=u/t,h=(u*e-a*n)/t,d=(u*n+a*e)/t;function p(t,o){return[c*(t*=r)-f*(o*=i)+n,e-f*t-c*o]}return p.invert=function(t,n){return[r*(s*t-l*n+h),i*(d-l*t-s*n)]},p}function vd(t){return _d((function(){return t}))()}function _d(t){var n,e,r,i,o,a,u,c,f,s,l=150,h=480,d=250,p=0,g=0,y=0,v=0,_=0,b=0,m=1,x=1,w=null,M=Al,T=null,A=rh,S=.5;function E(t){return c(t[0]*xf,t[1]*xf)}function N(t){return(t=c.invert(t[0],t[1]))&&[t[0]*mf,t[1]*mf]}function k(){var t=yd(l,0,0,m,x,b).apply(null,n(p,g)),r=yd(l,h-t[0],d-t[1],m,x,b);return e=cl(y,v,_),u=al(n,r),c=al(e,u),a=pd(u,S),C()}function C(){return f=s=null,E}return E.stream=function(t){return f&&s===t?f:f=gd(function(t){return od({point:function(n,e){var r=t(n,e);return this.stream.point(r[0],r[1])}})}(e)(M(a(A(s=t)))))},E.preclip=function(t){return arguments.length?(M=t,w=void 0,C()):M},E.postclip=function(t){return arguments.length?(A=t,T=r=i=o=null,C()):A},E.clipAngle=function(t){return arguments.length?(M=+t?Sl(w=t*xf):(w=null,Al),C()):w*mf},E.clipExtent=function(t){return arguments.length?(A=null==t?(T=r=i=o=null,rh):$l(T=+t[0][0],r=+t[0][1],i=+t[1][0],o=+t[1][1]),C()):null==T?null:[[T,r],[i,o]]},E.scale=function(t){return arguments.length?(l=+t,k()):l},E.translate=function(t){return arguments.length?(h=+t[0],d=+t[1],k()):[h,d]},E.center=function(t){return arguments.length?(p=t[0]%360*xf,g=t[1]%360*xf,k()):[p*mf,g*mf]},E.rotate=function(t){return arguments.length?(y=t[0]%360*xf,v=t[1]%360*xf,_=t.length>2?t[2]%360*xf:0,k()):[y*mf,v*mf,_*mf]},E.angle=function(t){return arguments.length?(b=t%360*xf,k()):b*mf},E.reflectX=function(t){return arguments.length?(m=t?-1:1,k()):m<0},E.reflectY=function(t){return arguments.length?(x=t?-1:1,k()):x<0},E.precision=function(t){return arguments.length?(a=pd(u,S=t*t),C()):$f(S)},E.fitExtent=function(t,n){return cd(E,t,n)},E.fitSize=function(t,n){return fd(E,t,n)},E.fitWidth=function(t,n){return sd(E,t,n)},E.fitHeight=function(t,n){return ld(E,t,n)},function(){return n=t.apply(this,arguments),E.invert=n.invert&&N,k()}}function bd(t){var n=0,e=yf/3,r=_d(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*xf,e=t[1]*xf):[n*mf,e*mf]},i}function md(t,n){var e=Pf(t),r=(e+Pf(n))/2;if(wf(r)<pf)return function(t){var n=Af(t);function e(t,e){return[t*n,Pf(e)/n]}return e.invert=function(t,e){return[t/n,Ff(e*n)]},e}(t);var i=1+e*(2*r-e),o=$f(i)/r;function a(t,n){var e=$f(i-2*r*Pf(n))/r;return[e*Pf(t*=r),o-e*Af(t)]}return a.invert=function(t,n){var e=o-n,a=Tf(t,wf(e))*zf(e);return e*r<0&&(a-=yf*zf(t)*zf(e)),[a/r,Ff((i-(t*t+e*e)*r*r)/(2*r))]},a}function xd(){return bd(md).scale(155.424).center([0,33.6442])}function wd(){return xd().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])}function Md(t){return function(n,e){var r=Af(n),i=Af(e),o=t(r*i);return o===1/0?[2,0]:[o*i*Pf(n),o*Pf(e)]}}function Td(t){return function(n,e){var r=$f(n*n+e*e),i=t(r),o=Pf(i),a=Af(i);return[Tf(n*o,r*a),Ff(r&&e*o/r)]}}var Ad=Md((function(t){return $f(2/(1+t))}));Ad.invert=Td((function(t){return 2*Ff(t/2)}));var Sd=Md((function(t){return(t=Rf(t))&&t/Pf(t)}));function Ed(t,n){return[t,kf(Df((vf+n)/2))]}function Nd(t){var n,e,r,i=vd(t),o=i.center,a=i.scale,u=i.translate,c=i.clipExtent,f=null;function s(){var o=yf*a(),u=i(hl(i.rotate()).invert([0,0]));return c(null==f?[[u[0]-o,u[1]-o],[u[0]+o,u[1]+o]]:t===Ed?[[Math.max(u[0]-o,f),n],[Math.min(u[0]+o,e),r]]:[[f,Math.max(u[1]-o,n)],[e,Math.min(u[1]+o,r)]])}return i.scale=function(t){return arguments.length?(a(t),s()):a()},i.translate=function(t){return arguments.length?(u(t),s()):u()},i.center=function(t){return arguments.length?(o(t),s()):o()},i.clipExtent=function(t){return arguments.length?(null==t?f=n=e=r=null:(f=+t[0][0],n=+t[0][1],e=+t[1][0],r=+t[1][1]),s()):null==f?null:[[f,n],[e,r]]},s()}function kd(t){return Df((vf+t)/2)}function Cd(t,n){var e=Af(t),r=t===n?Pf(t):kf(e/Af(n))/kf(kd(n)/kd(t)),i=e*Cf(kd(t),r)/r;if(!r)return Ed;function o(t,n){i>0?n<-vf+pf&&(n=-vf+pf):n>vf-pf&&(n=vf-pf);var e=i/Cf(kd(n),r);return[e*Pf(r*t),i-e*Af(r*t)]}return o.invert=function(t,n){var e=i-n,o=zf(r)*$f(t*t+e*e),a=Tf(t,wf(e))*zf(e);return e*r<0&&(a-=yf*zf(t)*zf(e)),[a/r,2*Mf(Cf(i/o,1/r))-vf]},o}function Pd(t,n){return[t,n]}function zd(t,n){var e=Af(t),r=t===n?Pf(t):(e-Af(n))/(n-t),i=e/r+t;if(wf(r)<pf)return Pd;function o(t,n){var e=i-n,o=r*t;return[e*Pf(o),i-e*Af(o)]}return o.invert=function(t,n){var e=i-n,o=Tf(t,wf(e))*zf(e);return e*r<0&&(o-=yf*zf(t)*zf(e)),[o/r,i-zf(r)*$f(t*t+e*e)]},o}Sd.invert=Td((function(t){return t})),Ed.invert=function(t,n){return[t,2*Mf(Ef(n))-vf]},Pd.invert=Pd;var $d=1.340264,Dd=-.081106,Rd=893e-6,Fd=.003796,qd=$f(3)/2;function Ud(t,n){var e=Ff(qd*Pf(n)),r=e*e,i=r*r*r;return[t*Af(e)/(qd*($d+3*Dd*r+i*(7*Rd+9*Fd*r))),e*($d+Dd*r+i*(Rd+Fd*r))]}function Id(t,n){var e=Af(n),r=Af(t)*e;return[e*Pf(t)/r,Pf(n)/r]}function Od(t,n){var e=n*n,r=e*e;return[t*(.8707-.131979*e+r*(r*(.003971*e-.001529*r)-.013791)),n*(1.007226+e*(.015085+r*(.028874*e-.044475-.005916*r)))]}function Bd(t,n){return[Af(n)*Pf(t),Pf(n)]}function Yd(t,n){var e=Af(n),r=1+Af(t)*e;return[e*Pf(t)/r,Pf(n)/r]}function Ld(t,n){return[kf(Df((vf+n)/2)),-t]}function jd(t,n){return t.parent===n.parent?1:2}function Hd(t,n){return t+n.x}function Xd(t,n){return Math.max(t,n.y)}function Gd(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function Vd(t,n){t instanceof Map?(t=[void 0,t],void 0===n&&(n=Zd)):void 0===n&&(n=Wd);for(var e,r,i,o,a,u=new Jd(t),c=[u];e=c.pop();)if((i=n(e.data))&&(a=(i=Array.from(i)).length))for(e.children=i,o=a-1;o>=0;--o)c.push(r=i[o]=new Jd(i[o])),r.parent=e,r.depth=e.depth+1;return u.eachBefore(Qd)}function Wd(t){return t.children}function Zd(t){return Array.isArray(t)?t[1]:null}function Kd(t){void 0!==t.data.value&&(t.value=t.data.value),t.data=t.data.data}function Qd(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function Jd(t){this.data=t,this.depth=this.height=0,this.parent=null}function tp(t){return null==t?null:np(t)}function np(t){if("function"!=typeof t)throw new Error;return t}function ep(){return 0}function rp(t){return function(){return t}}Ud.invert=function(t,n){for(var e,r=n,i=r*r,o=i*i*i,a=0;a<12&&(o=(i=(r-=e=(r*($d+Dd*i+o*(Rd+Fd*i))-n)/($d+3*Dd*i+o*(7*Rd+9*Fd*i)))*r)*i*i,!(wf(e)<gf));++a);return[qd*t*($d+3*Dd*i+o*(7*Rd+9*Fd*i))/Af(r),Ff(Pf(r)/qd)]},Id.invert=Td(Mf),Od.invert=function(t,n){var e,r=n,i=25;do{var o=r*r,a=o*o;r-=e=(r*(1.007226+o*(.015085+a*(.028874*o-.044475-.005916*a)))-n)/(1.007226+o*(.045255+a*(.259866*o-.311325-.005916*11*a)))}while(wf(e)>pf&&--i>0);return[t/(.8707+(o=r*r)*(o*(o*o*o*(.003971-.001529*o)-.013791)-.131979)),r]},Bd.invert=Td(Ff),Yd.invert=Td((function(t){return 2*Mf(t)})),Ld.invert=function(t,n){return[-n,2*Mf(Ef(t))-vf]},Jd.prototype=Vd.prototype={constructor:Jd,count:function(){return this.eachAfter(Gd)},each:function(t,n){let e=-1;for(const r of this)t.call(n,r,++e,this);return this},eachAfter:function(t,n){for(var e,r,i,o=this,a=[o],u=[],c=-1;o=a.pop();)if(u.push(o),e=o.children)for(r=0,i=e.length;r<i;++r)a.push(e[r]);for(;o=u.pop();)t.call(n,o,++c,this);return this},eachBefore:function(t,n){for(var e,r,i=this,o=[i],a=-1;i=o.pop();)if(t.call(n,i,++a,this),e=i.children)for(r=e.length-1;r>=0;--r)o.push(e[r]);return this},find:function(t,n){let e=-1;for(const r of this)if(t.call(n,r,++e,this))return r},sum:function(t){return this.eachAfter((function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e}))},sort:function(t){return this.eachBefore((function(n){n.children&&n.children.sort(t)}))},path:function(t){for(var n=this,e=function(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;t=e.pop(),n=r.pop();for(;t===n;)i=t,t=e.pop(),n=r.pop();return i}(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){return Array.from(this)},leaves:function(){var t=[];return this.eachBefore((function(n){n.children||t.push(n)})),t},links:function(){var t=this,n=[];return t.each((function(e){e!==t&&n.push({source:e.parent,target:e})})),n},copy:function(){return Vd(this).eachBefore(Kd)},[Symbol.iterator]:function*(){var t,n,e,r,i=this,o=[i];do{for(t=o.reverse(),o=[];i=t.pop();)if(yield i,n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e])}while(o.length)}};const ip=1664525,op=1013904223,ap=4294967296;function up(){let t=1;return()=>(t=(ip*t+op)%ap)/ap}function cp(t,n){for(var e,r,i=0,o=(t=function(t,n){let e,r,i=t.length;for(;i;)r=n()*i--|0,e=t[i],t[i]=t[r],t[r]=e;return t}(Array.from(t),n)).length,a=[];i<o;)e=t[i],r&&lp(r,e)?++i:(r=dp(a=fp(a,e)),i=0);return r}function fp(t,n){var e,r;if(hp(n,t))return[n];for(e=0;e<t.length;++e)if(sp(n,t[e])&&hp(pp(t[e],n),t))return[t[e],n];for(e=0;e<t.length-1;++e)for(r=e+1;r<t.length;++r)if(sp(pp(t[e],t[r]),n)&&sp(pp(t[e],n),t[r])&&sp(pp(t[r],n),t[e])&&hp(gp(t[e],t[r],n),t))return[t[e],t[r],n];throw new Error}function sp(t,n){var e=t.r-n.r,r=n.x-t.x,i=n.y-t.y;return e<0||e*e<r*r+i*i}function lp(t,n){var e=t.r-n.r+1e-9*Math.max(t.r,n.r,1),r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function hp(t,n){for(var e=0;e<n.length;++e)if(!lp(t,n[e]))return!1;return!0}function dp(t){switch(t.length){case 1:return function(t){return{x:t.x,y:t.y,r:t.r}}(t[0]);case 2:return pp(t[0],t[1]);case 3:return gp(t[0],t[1],t[2])}}function pp(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,a=n.y,u=n.r,c=o-e,f=a-r,s=u-i,l=Math.sqrt(c*c+f*f);return{x:(e+o+c/l*s)/2,y:(r+a+f/l*s)/2,r:(l+i+u)/2}}function gp(t,n,e){var r=t.x,i=t.y,o=t.r,a=n.x,u=n.y,c=n.r,f=e.x,s=e.y,l=e.r,h=r-a,d=r-f,p=i-u,g=i-s,y=c-o,v=l-o,_=r*r+i*i-o*o,b=_-a*a-u*u+c*c,m=_-f*f-s*s+l*l,x=d*p-h*g,w=(p*m-g*b)/(2*x)-r,M=(g*y-p*v)/x,T=(d*b-h*m)/(2*x)-i,A=(h*v-d*y)/x,S=M*M+A*A-1,E=2*(o+w*M+T*A),N=w*w+T*T-o*o,k=-(Math.abs(S)>1e-6?(E+Math.sqrt(E*E-4*S*N))/(2*S):N/E);return{x:r+w+M*k,y:i+T+A*k,r:k}}function yp(t,n,e){var r,i,o,a,u=t.x-n.x,c=t.y-n.y,f=u*u+c*c;f?(i=n.r+e.r,i*=i,a=t.r+e.r,i>(a*=a)?(r=(f+a-i)/(2*f),o=Math.sqrt(Math.max(0,a/f-r*r)),e.x=t.x-r*u-o*c,e.y=t.y-r*c+o*u):(r=(f+i-a)/(2*f),o=Math.sqrt(Math.max(0,i/f-r*r)),e.x=n.x+r*u-o*c,e.y=n.y+r*c+o*u)):(e.x=n.x+e.r,e.y=n.y)}function vp(t,n){var e=t.r+n.r-1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function _p(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function bp(t){this._=t,this.next=null,this.previous=null}function mp(t,n){if(!(o=(t=function(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}(t)).length))return 0;var e,r,i,o,a,u,c,f,s,l,h;if((e=t[0]).x=0,e.y=0,!(o>1))return e.r;if(r=t[1],e.x=-r.r,r.x=e.r,r.y=0,!(o>2))return e.r+r.r;yp(r,e,i=t[2]),e=new bp(e),r=new bp(r),i=new bp(i),e.next=i.previous=r,r.next=e.previous=i,i.next=r.previous=e;t:for(c=3;c<o;++c){yp(e._,r._,i=t[c]),i=new bp(i),f=r.next,s=e.previous,l=r._.r,h=e._.r;do{if(l<=h){if(vp(f._,i._)){r=f,e.next=r,r.previous=e,--c;continue t}l+=f._.r,f=f.next}else{if(vp(s._,i._)){(e=s).next=r,r.previous=e,--c;continue t}h+=s._.r,s=s.previous}}while(f!==s.next);for(i.previous=e,i.next=r,e.next=r.previous=r=i,a=_p(e);(i=i.next)!==r;)(u=_p(i))<a&&(e=i,a=u);r=e.next}for(e=[r._],i=r;(i=i.next)!==r;)e.push(i._);for(i=cp(e,n),c=0;c<o;++c)(e=t[c]).x-=i.x,e.y-=i.y;return i.r}function xp(t){return Math.sqrt(t.value)}function wp(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function Mp(t,n,e){return function(r){if(i=r.children){var i,o,a,u=i.length,c=t(r)*n||0;if(c)for(o=0;o<u;++o)i[o].r+=c;if(a=mp(i,e),c)for(o=0;o<u;++o)i[o].r-=c;r.r=a+c}}}function Tp(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function Ap(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)}function Sp(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(r-n)/t.value;++u<c;)(o=a[u]).y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*f}var Ep={depth:-1},Np={},kp={};function Cp(t){return t.id}function Pp(t){return t.parentId}function zp(t){let n=t.length;if(n<2)return"";for(;--n>1&&!$p(t,n););return t.slice(0,n)}function $p(t,n){if("/"===t[n]){let e=0;for(;n>0&&"\\"===t[--n];)++e;if(0==(1&e))return!0}return!1}function Dp(t,n){return t.parent===n.parent?1:2}function Rp(t){var n=t.children;return n?n[0]:t.t}function Fp(t){var n=t.children;return n?n[n.length-1]:t.t}function qp(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function Up(t,n,e){return t.a.parent===n.parent?t.a:e}function Ip(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function Op(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(i-e)/t.value;++u<c;)(o=a[u]).x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*f}Ip.prototype=Object.create(Jd.prototype);var Bp=(1+Math.sqrt(5))/2;function Yp(t,n,e,r,i,o){for(var a,u,c,f,s,l,h,d,p,g,y,v=[],_=n.children,b=0,m=0,x=_.length,w=n.value;b<x;){c=i-e,f=o-r;do{s=_[m++].value}while(!s&&m<x);for(l=h=s,y=s*s*(g=Math.max(f/c,c/f)/(w*t)),p=Math.max(h/y,y/l);m<x;++m){if(s+=u=_[m].value,u<l&&(l=u),u>h&&(h=u),y=s*s*g,(d=Math.max(h/y,y/l))>p){s-=u;break}p=d}v.push(a={value:s,dice:c<f,children:_.slice(b,m)}),a.dice?Sp(a,e,r,i,w?r+=f*s/w:o):Op(a,e,r,w?e+=c*s/w:i,o),w-=s,b=m}return v}var Lp=function t(n){function e(t,e,r,i,o){Yp(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Bp);var jp=function t(n){function e(t,e,r,i,o){if((a=t._squarify)&&a.ratio===n)for(var a,u,c,f,s,l=-1,h=a.length,d=t.value;++l<h;){for(c=(u=a[l]).children,f=u.value=0,s=c.length;f<s;++f)u.value+=c[f].value;u.dice?Sp(u,e,r,i,d?r+=(o-r)*u.value/d:o):Op(u,e,r,d?e+=(i-e)*u.value/d:i,o),d-=u.value}else t._squarify=a=Yp(n,t,e,r,i,o),a.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Bp);function Hp(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])}function Xp(t,n){return t[0]-n[0]||t[1]-n[1]}function Gp(t){const n=t.length,e=[0,1];let r,i=2;for(r=2;r<n;++r){for(;i>1&&Hp(t[e[i-2]],t[e[i-1]],t[r])<=0;)--i;e[i++]=r}return e.slice(0,i)}var Vp=Math.random,Wp=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(Vp),Zp=function t(n){function e(t,e){return arguments.length<2&&(e=t,t=0),t=Math.floor(t),e=Math.floor(e)-t,function(){return Math.floor(n()*e+t)}}return e.source=t,e}(Vp),Kp=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(Vp),Qp=function t(n){var e=Kp.source(n);function r(){var t=e.apply(this,arguments);return function(){return Math.exp(t())}}return r.source=t,r}(Vp),Jp=function t(n){function e(t){return(t=+t)<=0?()=>0:function(){for(var e=0,r=t;r>1;--r)e+=n();return e+r*n()}}return e.source=t,e}(Vp),tg=function t(n){var e=Jp.source(n);function r(t){if(0==(t=+t))return n;var r=e(t);return function(){return r()/t}}return r.source=t,r}(Vp),ng=function t(n){function e(t){return function(){return-Math.log1p(-n())/t}}return e.source=t,e}(Vp),eg=function t(n){function e(t){if((t=+t)<0)throw new RangeError("invalid alpha");return t=1/-t,function(){return Math.pow(1-n(),t)}}return e.source=t,e}(Vp),rg=function t(n){function e(t){if((t=+t)<0||t>1)throw new RangeError("invalid p");return function(){return Math.floor(n()+t)}}return e.source=t,e}(Vp),ig=function t(n){function e(t){if((t=+t)<0||t>1)throw new RangeError("invalid p");return 0===t?()=>1/0:1===t?()=>1:(t=Math.log1p(-t),function(){return 1+Math.floor(Math.log1p(-n())/t)})}return e.source=t,e}(Vp),og=function t(n){var e=Kp.source(n)();function r(t,r){if((t=+t)<0)throw new RangeError("invalid k");if(0===t)return()=>0;if(r=null==r?1:+r,1===t)return()=>-Math.log1p(-n())*r;var i=(t<1?t+1:t)-1/3,o=1/(3*Math.sqrt(i)),a=t<1?()=>Math.pow(n(),1/t):()=>1;return function(){do{do{var t=e(),u=1+o*t}while(u<=0);u*=u*u;var c=1-n()}while(c>=1-.0331*t*t*t*t&&Math.log(c)>=.5*t*t+i*(1-u+Math.log(u)));return i*u*a()*r}}return r.source=t,r}(Vp),ag=function t(n){var e=og.source(n);function r(t,n){var r=e(t),i=e(n);return function(){var t=r();return 0===t?0:t/(t+i())}}return r.source=t,r}(Vp),ug=function t(n){var e=ig.source(n),r=ag.source(n);function i(t,n){return t=+t,(n=+n)>=1?()=>t:n<=0?()=>0:function(){for(var i=0,o=t,a=n;o*a>16&&o*(1-a)>16;){var u=Math.floor((o+1)*a),c=r(u,o-u+1)();c<=a?(i+=u,o-=u,a=(a-c)/(1-c)):(o=u-1,a/=c)}for(var f=a<.5,s=e(f?a:1-a),l=s(),h=0;l<=o;++h)l+=s();return i+(f?h:o-h)}}return i.source=t,i}(Vp),cg=function t(n){function e(t,e,r){var i;return 0==(t=+t)?i=t=>-Math.log(t):(t=1/t,i=n=>Math.pow(n,t)),e=null==e?0:+e,r=null==r?1:+r,function(){return e+r*i(-Math.log1p(-n()))}}return e.source=t,e}(Vp),fg=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,function(){return t+e*Math.tan(Math.PI*n())}}return e.source=t,e}(Vp),sg=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,function(){var r=n();return t+e*Math.log(r/(1-r))}}return e.source=t,e}(Vp),lg=function t(n){var e=og.source(n),r=ug.source(n);function i(t){return function(){for(var i=0,o=t;o>16;){var a=Math.floor(.875*o),u=e(a)();if(u>o)return i+r(a-1,o/u)();i+=a,o-=u}for(var c=-Math.log1p(-n()),f=0;c<=o;++f)c-=Math.log1p(-n());return i+f}}return i.source=t,i}(Vp);const hg=1/4294967296;function dg(t,n){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(n).domain(t)}return this}function pg(t,n){switch(arguments.length){case 0:break;case 1:"function"==typeof t?this.interpolator(t):this.range(t);break;default:this.domain(t),"function"==typeof n?this.interpolator(n):this.range(n)}return this}const gg=Symbol("implicit");function yg(){var t=new InternMap,n=[],e=[],r=gg;function i(i){let o=t.get(i);if(void 0===o){if(r!==gg)return r;t.set(i,o=n.push(i)-1)}return e[o%e.length]}return i.domain=function(e){if(!arguments.length)return n.slice();n=[],t=new InternMap;for(const r of e)t.has(r)||t.set(r,n.push(r)-1);return i},i.range=function(t){return arguments.length?(e=Array.from(t),i):e.slice()},i.unknown=function(t){return arguments.length?(r=t,i):r},i.copy=function(){return yg(n,e).unknown(r)},dg.apply(i,arguments),i}function vg(){var t,n,e=yg().unknown(void 0),r=e.domain,i=e.range,o=0,a=1,u=!1,c=0,f=0,s=.5;function l(){var e=r().length,l=a<o,h=l?a:o,d=l?o:a;t=(d-h)/Math.max(1,e-c+2*f),u&&(t=Math.floor(t)),h+=(d-h-t*(e-c))*s,n=t*(1-c),u&&(h=Math.round(h),n=Math.round(n));var p=ht(e).map((function(n){return h+t*n}));return i(l?p.reverse():p)}return delete e.unknown,e.domain=function(t){return arguments.length?(r(t),l()):r()},e.range=function(t){return arguments.length?([o,a]=t,o=+o,a=+a,l()):[o,a]},e.rangeRound=function(t){return[o,a]=t,o=+o,a=+a,u=!0,l()},e.bandwidth=function(){return n},e.step=function(){return t},e.round=function(t){return arguments.length?(u=!!t,l()):u},e.padding=function(t){return arguments.length?(c=Math.min(1,f=+t),l()):c},e.paddingInner=function(t){return arguments.length?(c=Math.min(1,t),l()):c},e.paddingOuter=function(t){return arguments.length?(f=+t,l()):f},e.align=function(t){return arguments.length?(s=Math.max(0,Math.min(1,t)),l()):s},e.copy=function(){return vg(r(),[o,a]).round(u).paddingInner(c).paddingOuter(f).align(s)},dg.apply(l(),arguments)}function _g(t){var n=t.copy;return t.padding=t.paddingOuter,delete t.paddingInner,delete t.paddingOuter,t.copy=function(){return _g(n())},t}function bg(t){return+t}var mg=[0,1];function xg(t){return t}function wg(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:function(t){return function(){return t}}(isNaN(n)?NaN:.5)}function Mg(t,n,e){var r=t[0],i=t[1],o=n[0],a=n[1];return i<r?(r=wg(i,r),o=e(a,o)):(r=wg(r,i),o=e(o,a)),function(t){return o(r(t))}}function Tg(t,n,e){var r=Math.min(t.length,n.length)-1,i=new Array(r),o=new Array(r),a=-1;for(t[r]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++a<r;)i[a]=wg(t[a],t[a+1]),o[a]=e(n[a],n[a+1]);return function(n){var e=l(t,n,1,r)-1;return o[e](i[e](n))}}function Ag(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp()).unknown(t.unknown())}function Sg(){var t,n,e,r,i,o,a=mg,u=mg,c=Vr,f=xg;function s(){var t=Math.min(a.length,u.length);return f!==xg&&(f=function(t,n){var e;return t>n&&(e=t,t=n,n=e),function(e){return Math.max(t,Math.min(n,e))}}(a[0],a[t-1])),r=t>2?Tg:Mg,i=o=null,l}function l(n){return null==n||isNaN(n=+n)?e:(i||(i=r(a.map(t),u,c)))(t(f(n)))}return l.invert=function(e){return f(n((o||(o=r(u,a.map(t),Lr)))(e)))},l.domain=function(t){return arguments.length?(a=Array.from(t,bg),s()):a.slice()},l.range=function(t){return arguments.length?(u=Array.from(t),s()):u.slice()},l.rangeRound=function(t){return u=Array.from(t),c=Wr,s()},l.clamp=function(t){return arguments.length?(f=!!t||xg,s()):f!==xg},l.interpolate=function(t){return arguments.length?(c=t,s()):c},l.unknown=function(t){return arguments.length?(e=t,l):e},function(e,r){return t=e,n=r,s()}}function Eg(){return Sg()(xg,xg)}function Ng(n,e,r,i){var o,a=Z(n,e,r);switch((i=tf(null==i?",f":i)).type){case"s":var u=Math.max(Math.abs(n),Math.abs(e));return null!=i.precision||isNaN(o=hf(a,u))||(i.precision=o),t.formatPrefix(i,u);case"":case"e":case"g":case"p":case"r":null!=i.precision||isNaN(o=df(a,Math.max(Math.abs(n),Math.abs(e))))||(i.precision=o-("e"===i.type));break;case"f":case"%":null!=i.precision||isNaN(o=lf(a))||(i.precision=o-2*("%"===i.type))}return t.format(i)}function kg(t){var n=t.domain;return t.ticks=function(t){var e=n();return V(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){var r=n();return Ng(r[0],r[r.length-1],null==t?10:t,e)},t.nice=function(e){null==e&&(e=10);var r,i,o=n(),a=0,u=o.length-1,c=o[a],f=o[u],s=10;for(f<c&&(i=c,c=f,f=i,i=a,a=u,u=i);s-- >0;){if((i=W(c,f,e))===r)return o[a]=c,o[u]=f,n(o);if(i>0)c=Math.floor(c/i)*i,f=Math.ceil(f/i)*i;else{if(!(i<0))break;c=Math.ceil(c*i)/i,f=Math.floor(f*i)/i}r=i}return t},t}function Cg(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],a=t[i];return a<o&&(e=r,r=i,i=e,e=o,o=a,a=e),t[r]=n.floor(o),t[i]=n.ceil(a),t}function Pg(t){return Math.log(t)}function zg(t){return Math.exp(t)}function $g(t){return-Math.log(-t)}function Dg(t){return-Math.exp(-t)}function Rg(t){return isFinite(t)?+("1e"+t):t<0?0:t}function Fg(t){return(n,e)=>-t(-n,e)}function qg(n){const e=n(Pg,zg),r=e.domain;let i,o,a=10;function u(){return i=function(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),n=>Math.log(n)/t)}(a),o=function(t){return 10===t?Rg:t===Math.E?Math.exp:n=>Math.pow(t,n)}(a),r()[0]<0?(i=Fg(i),o=Fg(o),n($g,Dg)):n(Pg,zg),e}return e.base=function(t){return arguments.length?(a=+t,u()):a},e.domain=function(t){return arguments.length?(r(t),u()):r()},e.ticks=t=>{const n=r();let e=n[0],u=n[n.length-1];const c=u<e;c&&([e,u]=[u,e]);let f,s,l=i(e),h=i(u);const d=null==t?10:+t;let p=[];if(!(a%1)&&h-l<d){if(l=Math.floor(l),h=Math.ceil(h),e>0){for(;l<=h;++l)for(f=1;f<a;++f)if(s=l<0?f/o(-l):f*o(l),!(s<e)){if(s>u)break;p.push(s)}}else for(;l<=h;++l)for(f=a-1;f>=1;--f)if(s=l>0?f/o(-l):f*o(l),!(s<e)){if(s>u)break;p.push(s)}2*p.length<d&&(p=V(e,u,d))}else p=V(l,h,Math.min(h-l,d)).map(o);return c?p.reverse():p},e.tickFormat=(n,r)=>{if(null==n&&(n=10),null==r&&(r=10===a?"s":","),"function"!=typeof r&&(a%1||null!=(r=tf(r)).precision||(r.trim=!0),r=t.format(r)),n===1/0)return r;const u=Math.max(1,a*n/e.ticks().length);return t=>{let n=t/o(Math.round(i(t)));return n*a<a-.5&&(n*=a),n<=u?r(t):""}},e.nice=()=>r(Cg(r(),{floor:t=>o(Math.floor(i(t))),ceil:t=>o(Math.ceil(i(t)))})),e}function Ug(t){return function(n){return Math.sign(n)*Math.log1p(Math.abs(n/t))}}function Ig(t){return function(n){return Math.sign(n)*Math.expm1(Math.abs(n))*t}}function Og(t){var n=1,e=t(Ug(n),Ig(n));return e.constant=function(e){return arguments.length?t(Ug(n=+e),Ig(n)):n},kg(e)}function Bg(t){return function(n){return n<0?-Math.pow(-n,t):Math.pow(n,t)}}function Yg(t){return t<0?-Math.sqrt(-t):Math.sqrt(t)}function Lg(t){return t<0?-t*t:t*t}function jg(t){var n=t(xg,xg),e=1;return n.exponent=function(n){return arguments.length?1===(e=+n)?t(xg,xg):.5===e?t(Yg,Lg):t(Bg(e),Bg(1/e)):e},kg(n)}function Hg(){var t=jg(Sg());return t.copy=function(){return Ag(t,Hg()).exponent(t.exponent())},dg.apply(t,arguments),t}function Xg(t){return Math.sign(t)*t*t}const Gg=new Date,Vg=new Date;function Wg(t,n,e,r){function i(n){return t(n=0===arguments.length?new Date:new Date(+n)),n}return i.floor=n=>(t(n=new Date(+n)),n),i.ceil=e=>(t(e=new Date(e-1)),n(e,1),t(e),e),i.round=t=>{const n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=(t,e)=>(n(t=new Date(+t),null==e?1:Math.floor(e)),t),i.range=(e,r,o)=>{const a=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return a;let u;do{a.push(u=new Date(+e)),n(e,o),t(e)}while(u<e&&e<r);return a},i.filter=e=>Wg((n=>{if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)}),((t,r)=>{if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})),e&&(i.count=(n,r)=>(Gg.setTime(+n),Vg.setTime(+r),t(Gg),t(Vg),Math.floor(e(Gg,Vg))),i.every=t=>(t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?n=>r(n)%t==0:n=>i.count(0,n)%t==0):i:null)),i}const Zg=Wg((()=>{}),((t,n)=>{t.setTime(+t+n)}),((t,n)=>n-t));Zg.every=t=>(t=Math.floor(t),isFinite(t)&&t>0?t>1?Wg((n=>{n.setTime(Math.floor(n/t)*t)}),((n,e)=>{n.setTime(+n+e*t)}),((n,e)=>(e-n)/t)):Zg:null);const Kg=Zg.range,Qg=1e3,Jg=6e4,ty=60*Jg,ny=24*ty,ey=7*ny,ry=30*ny,iy=365*ny,oy=Wg((t=>{t.setTime(t-t.getMilliseconds())}),((t,n)=>{t.setTime(+t+n*Qg)}),((t,n)=>(n-t)/Qg),(t=>t.getUTCSeconds())),ay=oy.range,uy=Wg((t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*Qg)}),((t,n)=>{t.setTime(+t+n*Jg)}),((t,n)=>(n-t)/Jg),(t=>t.getMinutes())),cy=uy.range,fy=Wg((t=>{t.setUTCSeconds(0,0)}),((t,n)=>{t.setTime(+t+n*Jg)}),((t,n)=>(n-t)/Jg),(t=>t.getUTCMinutes())),sy=fy.range,ly=Wg((t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*Qg-t.getMinutes()*Jg)}),((t,n)=>{t.setTime(+t+n*ty)}),((t,n)=>(n-t)/ty),(t=>t.getHours())),hy=ly.range,dy=Wg((t=>{t.setUTCMinutes(0,0,0)}),((t,n)=>{t.setTime(+t+n*ty)}),((t,n)=>(n-t)/ty),(t=>t.getUTCHours())),py=dy.range,gy=Wg((t=>t.setHours(0,0,0,0)),((t,n)=>t.setDate(t.getDate()+n)),((t,n)=>(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Jg)/ny),(t=>t.getDate()-1)),yy=gy.range,vy=Wg((t=>{t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCDate(t.getUTCDate()+n)}),((t,n)=>(n-t)/ny),(t=>t.getUTCDate()-1)),_y=vy.range,by=Wg((t=>{t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCDate(t.getUTCDate()+n)}),((t,n)=>(n-t)/ny),(t=>Math.floor(t/ny))),my=by.range;function xy(t){return Wg((n=>{n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)}),((t,n)=>{t.setDate(t.getDate()+7*n)}),((t,n)=>(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Jg)/ey))}const wy=xy(0),My=xy(1),Ty=xy(2),Ay=xy(3),Sy=xy(4),Ey=xy(5),Ny=xy(6),ky=wy.range,Cy=My.range,Py=Ty.range,zy=Ay.range,$y=Sy.range,Dy=Ey.range,Ry=Ny.range;function Fy(t){return Wg((n=>{n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCDate(t.getUTCDate()+7*n)}),((t,n)=>(n-t)/ey))}const qy=Fy(0),Uy=Fy(1),Iy=Fy(2),Oy=Fy(3),By=Fy(4),Yy=Fy(5),Ly=Fy(6),jy=qy.range,Hy=Uy.range,Xy=Iy.range,Gy=Oy.range,Vy=By.range,Wy=Yy.range,Zy=Ly.range,Ky=Wg((t=>{t.setDate(1),t.setHours(0,0,0,0)}),((t,n)=>{t.setMonth(t.getMonth()+n)}),((t,n)=>n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())),(t=>t.getMonth())),Qy=Ky.range,Jy=Wg((t=>{t.setUTCDate(1),t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCMonth(t.getUTCMonth()+n)}),((t,n)=>n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())),(t=>t.getUTCMonth())),tv=Jy.range,nv=Wg((t=>{t.setMonth(0,1),t.setHours(0,0,0,0)}),((t,n)=>{t.setFullYear(t.getFullYear()+n)}),((t,n)=>n.getFullYear()-t.getFullYear()),(t=>t.getFullYear()));nv.every=t=>isFinite(t=Math.floor(t))&&t>0?Wg((n=>{n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)}),((n,e)=>{n.setFullYear(n.getFullYear()+e*t)})):null;const ev=nv.range,rv=Wg((t=>{t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCFullYear(t.getUTCFullYear()+n)}),((t,n)=>n.getUTCFullYear()-t.getUTCFullYear()),(t=>t.getUTCFullYear()));rv.every=t=>isFinite(t=Math.floor(t))&&t>0?Wg((n=>{n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)}),((n,e)=>{n.setUTCFullYear(n.getUTCFullYear()+e*t)})):null;const iv=rv.range;function ov(t,n,e,i,o,a){const u=[[oy,1,Qg],[oy,5,5e3],[oy,15,15e3],[oy,30,3e4],[a,1,Jg],[a,5,5*Jg],[a,15,15*Jg],[a,30,30*Jg],[o,1,ty],[o,3,3*ty],[o,6,6*ty],[o,12,12*ty],[i,1,ny],[i,2,2*ny],[e,1,ey],[n,1,ry],[n,3,3*ry],[t,1,iy]];function c(n,e,i){const o=Math.abs(e-n)/i,a=r((([,,t])=>t)).right(u,o);if(a===u.length)return t.every(Z(n/iy,e/iy,i));if(0===a)return Zg.every(Math.max(Z(n,e,i),1));const[c,f]=u[o/u[a-1][2]<u[a][2]/o?a-1:a];return c.every(f)}return[function(t,n,e){const r=n<t;r&&([t,n]=[n,t]);const i=e&&"function"==typeof e.range?e:c(t,n,e),o=i?i.range(t,+n+1):[];return r?o.reverse():o},c]}const[av,uv]=ov(rv,Jy,qy,by,dy,fy),[cv,fv]=ov(nv,Ky,wy,gy,ly,uy);function sv(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function lv(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function hv(t,n,e){return{y:t,m:n,d:e,H:0,M:0,S:0,L:0}}function dv(t){var n=t.dateTime,e=t.date,r=t.time,i=t.periods,o=t.days,a=t.shortDays,u=t.months,c=t.shortMonths,f=xv(i),s=wv(i),l=xv(o),h=wv(o),d=xv(a),p=wv(a),g=xv(u),y=wv(u),v=xv(c),_=wv(c),b={a:function(t){return a[t.getDay()]},A:function(t){return o[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return u[t.getMonth()]},c:null,d:Lv,e:Lv,f:Vv,g:o_,G:u_,H:jv,I:Hv,j:Xv,L:Gv,m:Wv,M:Zv,p:function(t){return i[+(t.getHours()>=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:C_,s:P_,S:Kv,u:Qv,U:Jv,V:n_,w:e_,W:r_,x:null,X:null,y:i_,Y:a_,Z:c_,"%":k_},m={a:function(t){return a[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return u[t.getUTCMonth()]},c:null,d:f_,e:f_,f:p_,g:A_,G:E_,H:s_,I:l_,j:h_,L:d_,m:g_,M:y_,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:C_,s:P_,S:v_,u:__,U:b_,V:x_,w:w_,W:M_,x:null,X:null,y:T_,Y:S_,Z:N_,"%":k_},x={a:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=p.get(r[0].toLowerCase()),e+r[0].length):-1},A:function(t,n,e){var r=l.exec(n.slice(e));return r?(t.w=h.get(r[0].toLowerCase()),e+r[0].length):-1},b:function(t,n,e){var r=v.exec(n.slice(e));return r?(t.m=_.get(r[0].toLowerCase()),e+r[0].length):-1},B:function(t,n,e){var r=g.exec(n.slice(e));return r?(t.m=y.get(r[0].toLowerCase()),e+r[0].length):-1},c:function(t,e,r){return T(t,n,e,r)},d:$v,e:$v,f:Iv,g:kv,G:Nv,H:Rv,I:Rv,j:Dv,L:Uv,m:zv,M:Fv,p:function(t,n,e){var r=f.exec(n.slice(e));return r?(t.p=s.get(r[0].toLowerCase()),e+r[0].length):-1},q:Pv,Q:Bv,s:Yv,S:qv,u:Tv,U:Av,V:Sv,w:Mv,W:Ev,x:function(t,n,r){return T(t,e,n,r)},X:function(t,n,e){return T(t,r,n,e)},y:kv,Y:Nv,Z:Cv,"%":Ov};function w(t,n){return function(e){var r,i,o,a=[],u=-1,c=0,f=t.length;for(e instanceof Date||(e=new Date(+e));++u<f;)37===t.charCodeAt(u)&&(a.push(t.slice(c,u)),null!=(i=gv[r=t.charAt(++u)])?r=t.charAt(++u):i="e"===r?" ":"0",(o=n[r])&&(r=o(e,i)),a.push(r),c=u+1);return a.push(t.slice(c,u)),a.join("")}}function M(t,n){return function(e){var r,i,o=hv(1900,void 0,1);if(T(o,t,e+="",0)!=e.length)return null;if("Q"in o)return new Date(o.Q);if("s"in o)return new Date(1e3*o.s+("L"in o?o.L:0));if(n&&!("Z"in o)&&(o.Z=0),"p"in o&&(o.H=o.H%12+12*o.p),void 0===o.m&&(o.m="q"in o?o.q:0),"V"in o){if(o.V<1||o.V>53)return null;"w"in o||(o.w=1),"Z"in o?(i=(r=lv(hv(o.y,0,1))).getUTCDay(),r=i>4||0===i?Uy.ceil(r):Uy(r),r=vy.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(i=(r=sv(hv(o.y,0,1))).getDay(),r=i>4||0===i?My.ceil(r):My(r),r=gy.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?lv(hv(o.y,0,1)).getUTCDay():sv(hv(o.y,0,1)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,lv(o)):sv(o)}}function T(t,n,e,r){for(var i,o,a=0,u=n.length,c=e.length;a<u;){if(r>=c)return-1;if(37===(i=n.charCodeAt(a++))){if(i=n.charAt(a++),!(o=x[i in gv?n.charAt(a++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}return b.x=w(e,b),b.X=w(r,b),b.c=w(n,b),m.x=w(e,m),m.X=w(r,m),m.c=w(n,m),{format:function(t){var n=w(t+="",b);return n.toString=function(){return t},n},parse:function(t){var n=M(t+="",!1);return n.toString=function(){return t},n},utcFormat:function(t){var n=w(t+="",m);return n.toString=function(){return t},n},utcParse:function(t){var n=M(t+="",!0);return n.toString=function(){return t},n}}}var pv,gv={"-":"",_:" ",0:"0"},yv=/^\s*\d+/,vv=/^%/,_v=/[\\^$*+?|[\]().{}]/g;function bv(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function mv(t){return t.replace(_v,"\\$&")}function xv(t){return new RegExp("^(?:"+t.map(mv).join("|")+")","i")}function wv(t){return new Map(t.map(((t,n)=>[t.toLowerCase(),n])))}function Mv(t,n,e){var r=yv.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function Tv(t,n,e){var r=yv.exec(n.slice(e,e+1));return r?(t.u=+r[0],e+r[0].length):-1}function Av(t,n,e){var r=yv.exec(n.slice(e,e+2));return r?(t.U=+r[0],e+r[0].length):-1}function Sv(t,n,e){var r=yv.exec(n.slice(e,e+2));return r?(t.V=+r[0],e+r[0].length):-1}function Ev(t,n,e){var r=yv.exec(n.slice(e,e+2));return r?(t.W=+r[0],e+r[0].length):-1}function Nv(t,n,e){var r=yv.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function kv(t,n,e){var r=yv.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function Cv(t,n,e){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function Pv(t,n,e){var r=yv.exec(n.slice(e,e+1));return r?(t.q=3*r[0]-3,e+r[0].length):-1}function zv(t,n,e){var r=yv.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function $v(t,n,e){var r=yv.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function Dv(t,n,e){var r=yv.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function Rv(t,n,e){var r=yv.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function Fv(t,n,e){var r=yv.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function qv(t,n,e){var r=yv.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function Uv(t,n,e){var r=yv.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function Iv(t,n,e){var r=yv.exec(n.slice(e,e+6));return r?(t.L=Math.floor(r[0]/1e3),e+r[0].length):-1}function Ov(t,n,e){var r=vv.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function Bv(t,n,e){var r=yv.exec(n.slice(e));return r?(t.Q=+r[0],e+r[0].length):-1}function Yv(t,n,e){var r=yv.exec(n.slice(e));return r?(t.s=+r[0],e+r[0].length):-1}function Lv(t,n){return bv(t.getDate(),n,2)}function jv(t,n){return bv(t.getHours(),n,2)}function Hv(t,n){return bv(t.getHours()%12||12,n,2)}function Xv(t,n){return bv(1+gy.count(nv(t),t),n,3)}function Gv(t,n){return bv(t.getMilliseconds(),n,3)}function Vv(t,n){return Gv(t,n)+"000"}function Wv(t,n){return bv(t.getMonth()+1,n,2)}function Zv(t,n){return bv(t.getMinutes(),n,2)}function Kv(t,n){return bv(t.getSeconds(),n,2)}function Qv(t){var n=t.getDay();return 0===n?7:n}function Jv(t,n){return bv(wy.count(nv(t)-1,t),n,2)}function t_(t){var n=t.getDay();return n>=4||0===n?Sy(t):Sy.ceil(t)}function n_(t,n){return t=t_(t),bv(Sy.count(nv(t),t)+(4===nv(t).getDay()),n,2)}function e_(t){return t.getDay()}function r_(t,n){return bv(My.count(nv(t)-1,t),n,2)}function i_(t,n){return bv(t.getFullYear()%100,n,2)}function o_(t,n){return bv((t=t_(t)).getFullYear()%100,n,2)}function a_(t,n){return bv(t.getFullYear()%1e4,n,4)}function u_(t,n){var e=t.getDay();return bv((t=e>=4||0===e?Sy(t):Sy.ceil(t)).getFullYear()%1e4,n,4)}function c_(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+bv(n/60|0,"0",2)+bv(n%60,"0",2)}function f_(t,n){return bv(t.getUTCDate(),n,2)}function s_(t,n){return bv(t.getUTCHours(),n,2)}function l_(t,n){return bv(t.getUTCHours()%12||12,n,2)}function h_(t,n){return bv(1+vy.count(rv(t),t),n,3)}function d_(t,n){return bv(t.getUTCMilliseconds(),n,3)}function p_(t,n){return d_(t,n)+"000"}function g_(t,n){return bv(t.getUTCMonth()+1,n,2)}function y_(t,n){return bv(t.getUTCMinutes(),n,2)}function v_(t,n){return bv(t.getUTCSeconds(),n,2)}function __(t){var n=t.getUTCDay();return 0===n?7:n}function b_(t,n){return bv(qy.count(rv(t)-1,t),n,2)}function m_(t){var n=t.getUTCDay();return n>=4||0===n?By(t):By.ceil(t)}function x_(t,n){return t=m_(t),bv(By.count(rv(t),t)+(4===rv(t).getUTCDay()),n,2)}function w_(t){return t.getUTCDay()}function M_(t,n){return bv(Uy.count(rv(t)-1,t),n,2)}function T_(t,n){return bv(t.getUTCFullYear()%100,n,2)}function A_(t,n){return bv((t=m_(t)).getUTCFullYear()%100,n,2)}function S_(t,n){return bv(t.getUTCFullYear()%1e4,n,4)}function E_(t,n){var e=t.getUTCDay();return bv((t=e>=4||0===e?By(t):By.ceil(t)).getUTCFullYear()%1e4,n,4)}function N_(){return"+0000"}function k_(){return"%"}function C_(t){return+t}function P_(t){return Math.floor(+t/1e3)}function z_(n){return pv=dv(n),t.timeFormat=pv.format,t.timeParse=pv.parse,t.utcFormat=pv.utcFormat,t.utcParse=pv.utcParse,pv}t.timeFormat=void 0,t.timeParse=void 0,t.utcFormat=void 0,t.utcParse=void 0,z_({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var $_="%Y-%m-%dT%H:%M:%S.%LZ";var D_=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat($_),R_=D_;var F_=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse($_),q_=F_;function U_(t){return new Date(t)}function I_(t){return t instanceof Date?+t:+new Date(+t)}function O_(t,n,e,r,i,o,a,u,c,f){var s=Eg(),l=s.invert,h=s.domain,d=f(".%L"),p=f(":%S"),g=f("%I:%M"),y=f("%I %p"),v=f("%a %d"),_=f("%b %d"),b=f("%B"),m=f("%Y");function x(t){return(c(t)<t?d:u(t)<t?p:a(t)<t?g:o(t)<t?y:r(t)<t?i(t)<t?v:_:e(t)<t?b:m)(t)}return s.invert=function(t){return new Date(l(t))},s.domain=function(t){return arguments.length?h(Array.from(t,I_)):h().map(U_)},s.ticks=function(n){var e=h();return t(e[0],e[e.length-1],null==n?10:n)},s.tickFormat=function(t,n){return null==n?x:f(n)},s.nice=function(t){var e=h();return t&&"function"==typeof t.range||(t=n(e[0],e[e.length-1],null==t?10:t)),t?h(Cg(e,t)):s},s.copy=function(){return Ag(s,O_(t,n,e,r,i,o,a,u,c,f))},s}function B_(){var t,n,e,r,i,o=0,a=1,u=xg,c=!1;function f(n){return null==n||isNaN(n=+n)?i:u(0===e?.5:(n=(r(n)-t)*e,c?Math.max(0,Math.min(1,n)):n))}function s(t){return function(n){var e,r;return arguments.length?([e,r]=n,u=t(e,r),f):[u(0),u(1)]}}return f.domain=function(i){return arguments.length?([o,a]=i,t=r(o=+o),n=r(a=+a),e=t===n?0:1/(n-t),f):[o,a]},f.clamp=function(t){return arguments.length?(c=!!t,f):c},f.interpolator=function(t){return arguments.length?(u=t,f):u},f.range=s(Vr),f.rangeRound=s(Wr),f.unknown=function(t){return arguments.length?(i=t,f):i},function(i){return r=i,t=i(o),n=i(a),e=t===n?0:1/(n-t),f}}function Y_(t,n){return n.domain(t.domain()).interpolator(t.interpolator()).clamp(t.clamp()).unknown(t.unknown())}function L_(){var t=jg(B_());return t.copy=function(){return Y_(t,L_()).exponent(t.exponent())},pg.apply(t,arguments)}function j_(){var t,n,e,r,i,o,a,u=0,c=.5,f=1,s=1,l=xg,h=!1;function d(t){return isNaN(t=+t)?a:(t=.5+((t=+o(t))-n)*(s*t<s*n?r:i),l(h?Math.max(0,Math.min(1,t)):t))}function p(t){return function(n){var e,r,i;return arguments.length?([e,r,i]=n,l=pi(t,[e,r,i]),d):[l(0),l(.5),l(1)]}}return d.domain=function(a){return arguments.length?([u,c,f]=a,t=o(u=+u),n=o(c=+c),e=o(f=+f),r=t===n?0:.5/(n-t),i=n===e?0:.5/(e-n),s=n<t?-1:1,d):[u,c,f]},d.clamp=function(t){return arguments.length?(h=!!t,d):h},d.interpolator=function(t){return arguments.length?(l=t,d):l},d.range=p(Vr),d.rangeRound=p(Wr),d.unknown=function(t){return arguments.length?(a=t,d):a},function(a){return o=a,t=a(u),n=a(c),e=a(f),r=t===n?0:.5/(n-t),i=n===e?0:.5/(e-n),s=n<t?-1:1,d}}function H_(){var t=jg(j_());return t.copy=function(){return Y_(t,H_()).exponent(t.exponent())},pg.apply(t,arguments)}function X_(t){for(var n=t.length/6|0,e=new Array(n),r=0;r<n;)e[r]="#"+t.slice(6*r,6*++r);return e}var G_=X_("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),V_=X_("7fc97fbeaed4fdc086ffff99386cb0f0027fbf5b17666666"),W_=X_("1b9e77d95f027570b3e7298a66a61ee6ab02a6761d666666"),Z_=X_("a6cee31f78b4b2df8a33a02cfb9a99e31a1cfdbf6fff7f00cab2d66a3d9affff99b15928"),K_=X_("fbb4aeb3cde3ccebc5decbe4fed9a6ffffcce5d8bdfddaecf2f2f2"),Q_=X_("b3e2cdfdcdaccbd5e8f4cae4e6f5c9fff2aef1e2cccccccc"),J_=X_("e41a1c377eb84daf4a984ea3ff7f00ffff33a65628f781bf999999"),tb=X_("66c2a5fc8d628da0cbe78ac3a6d854ffd92fe5c494b3b3b3"),nb=X_("8dd3c7ffffb3bebadafb807280b1d3fdb462b3de69fccde5d9d9d9bc80bdccebc5ffed6f"),eb=X_("4e79a7f28e2ce1575976b7b259a14fedc949af7aa1ff9da79c755fbab0ab"),rb=t=>qr(t[t.length-1]),ib=new Array(3).concat("d8b365f5f5f55ab4ac","a6611adfc27d80cdc1018571","a6611adfc27df5f5f580cdc1018571","8c510ad8b365f6e8c3c7eae55ab4ac01665e","8c510ad8b365f6e8c3f5f5f5c7eae55ab4ac01665e","8c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e","8c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e","5430058c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e003c30","5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30").map(X_),ob=rb(ib),ab=new Array(3).concat("af8dc3f7f7f77fbf7b","7b3294c2a5cfa6dba0008837","7b3294c2a5cff7f7f7a6dba0008837","762a83af8dc3e7d4e8d9f0d37fbf7b1b7837","762a83af8dc3e7d4e8f7f7f7d9f0d37fbf7b1b7837","762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b7837","762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b7837","40004b762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b783700441b","40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b").map(X_),ub=rb(ab),cb=new Array(3).concat("e9a3c9f7f7f7a1d76a","d01c8bf1b6dab8e1864dac26","d01c8bf1b6daf7f7f7b8e1864dac26","c51b7de9a3c9fde0efe6f5d0a1d76a4d9221","c51b7de9a3c9fde0eff7f7f7e6f5d0a1d76a4d9221","c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221","c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221","8e0152c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221276419","8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419").map(X_),fb=rb(cb),sb=new Array(3).concat("998ec3f7f7f7f1a340","5e3c99b2abd2fdb863e66101","5e3c99b2abd2f7f7f7fdb863e66101","542788998ec3d8daebfee0b6f1a340b35806","542788998ec3d8daebf7f7f7fee0b6f1a340b35806","5427888073acb2abd2d8daebfee0b6fdb863e08214b35806","5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b35806","2d004b5427888073acb2abd2d8daebfee0b6fdb863e08214b358067f3b08","2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08").map(X_),lb=rb(sb),hb=new Array(3).concat("ef8a62f7f7f767a9cf","ca0020f4a58292c5de0571b0","ca0020f4a582f7f7f792c5de0571b0","b2182bef8a62fddbc7d1e5f067a9cf2166ac","b2182bef8a62fddbc7f7f7f7d1e5f067a9cf2166ac","b2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac","b2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac","67001fb2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac053061","67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061").map(X_),db=rb(hb),pb=new Array(3).concat("ef8a62ffffff999999","ca0020f4a582bababa404040","ca0020f4a582ffffffbababa404040","b2182bef8a62fddbc7e0e0e09999994d4d4d","b2182bef8a62fddbc7ffffffe0e0e09999994d4d4d","b2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d","b2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d","67001fb2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d1a1a1a","67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a").map(X_),gb=rb(pb),yb=new Array(3).concat("fc8d59ffffbf91bfdb","d7191cfdae61abd9e92c7bb6","d7191cfdae61ffffbfabd9e92c7bb6","d73027fc8d59fee090e0f3f891bfdb4575b4","d73027fc8d59fee090ffffbfe0f3f891bfdb4575b4","d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4","d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4","a50026d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4313695","a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695").map(X_),vb=rb(yb),_b=new Array(3).concat("fc8d59ffffbf91cf60","d7191cfdae61a6d96a1a9641","d7191cfdae61ffffbfa6d96a1a9641","d73027fc8d59fee08bd9ef8b91cf601a9850","d73027fc8d59fee08bffffbfd9ef8b91cf601a9850","d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850","d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850","a50026d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850006837","a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837").map(X_),bb=rb(_b),mb=new Array(3).concat("fc8d59ffffbf99d594","d7191cfdae61abdda42b83ba","d7191cfdae61ffffbfabdda42b83ba","d53e4ffc8d59fee08be6f59899d5943288bd","d53e4ffc8d59fee08bffffbfe6f59899d5943288bd","d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd","d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd","9e0142d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd5e4fa2","9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2").map(X_),xb=rb(mb),wb=new Array(3).concat("e5f5f999d8c92ca25f","edf8fbb2e2e266c2a4238b45","edf8fbb2e2e266c2a42ca25f006d2c","edf8fbccece699d8c966c2a42ca25f006d2c","edf8fbccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b").map(X_),Mb=rb(wb),Tb=new Array(3).concat("e0ecf49ebcda8856a7","edf8fbb3cde38c96c688419d","edf8fbb3cde38c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b").map(X_),Ab=rb(Tb),Sb=new Array(3).concat("e0f3dba8ddb543a2ca","f0f9e8bae4bc7bccc42b8cbe","f0f9e8bae4bc7bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081").map(X_),Eb=rb(Sb),Nb=new Array(3).concat("fee8c8fdbb84e34a33","fef0d9fdcc8afc8d59d7301f","fef0d9fdcc8afc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000").map(X_),kb=rb(Nb),Cb=new Array(3).concat("ece2f0a6bddb1c9099","f6eff7bdc9e167a9cf02818a","f6eff7bdc9e167a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636").map(X_),Pb=rb(Cb),zb=new Array(3).concat("ece7f2a6bddb2b8cbe","f1eef6bdc9e174a9cf0570b0","f1eef6bdc9e174a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858").map(X_),$b=rb(zb),Db=new Array(3).concat("e7e1efc994c7dd1c77","f1eef6d7b5d8df65b0ce1256","f1eef6d7b5d8df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f").map(X_),Rb=rb(Db),Fb=new Array(3).concat("fde0ddfa9fb5c51b8a","feebe2fbb4b9f768a1ae017e","feebe2fbb4b9f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a").map(X_),qb=rb(Fb),Ub=new Array(3).concat("edf8b17fcdbb2c7fb8","ffffcca1dab441b6c4225ea8","ffffcca1dab441b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58").map(X_),Ib=rb(Ub),Ob=new Array(3).concat("f7fcb9addd8e31a354","ffffccc2e69978c679238443","ffffccc2e69978c67931a354006837","ffffccd9f0a3addd8e78c67931a354006837","ffffccd9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529").map(X_),Bb=rb(Ob),Yb=new Array(3).concat("fff7bcfec44fd95f0e","ffffd4fed98efe9929cc4c02","ffffd4fed98efe9929d95f0e993404","ffffd4fee391fec44ffe9929d95f0e993404","ffffd4fee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506").map(X_),Lb=rb(Yb),jb=new Array(3).concat("ffeda0feb24cf03b20","ffffb2fecc5cfd8d3ce31a1c","ffffb2fecc5cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026").map(X_),Hb=rb(jb),Xb=new Array(3).concat("deebf79ecae13182bd","eff3ffbdd7e76baed62171b5","eff3ffbdd7e76baed63182bd08519c","eff3ffc6dbef9ecae16baed63182bd08519c","eff3ffc6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b").map(X_),Gb=rb(Xb),Vb=new Array(3).concat("e5f5e0a1d99b31a354","edf8e9bae4b374c476238b45","edf8e9bae4b374c47631a354006d2c","edf8e9c7e9c0a1d99b74c47631a354006d2c","edf8e9c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b").map(X_),Wb=rb(Vb),Zb=new Array(3).concat("f0f0f0bdbdbd636363","f7f7f7cccccc969696525252","f7f7f7cccccc969696636363252525","f7f7f7d9d9d9bdbdbd969696636363252525","f7f7f7d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000").map(X_),Kb=rb(Zb),Qb=new Array(3).concat("efedf5bcbddc756bb1","f2f0f7cbc9e29e9ac86a51a3","f2f0f7cbc9e29e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d").map(X_),Jb=rb(Qb),tm=new Array(3).concat("fee0d2fc9272de2d26","fee5d9fcae91fb6a4acb181d","fee5d9fcae91fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d").map(X_),nm=rb(tm),em=new Array(3).concat("fee6cefdae6be6550d","feeddefdbe85fd8d3cd94701","feeddefdbe85fd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704").map(X_),rm=rb(em);var im=di(Ar(300,.5,0),Ar(-240,.5,1)),om=di(Ar(-100,.75,.35),Ar(80,1.5,.8)),am=di(Ar(260,.75,.35),Ar(80,1.5,.8)),um=Ar();var cm=qe(),fm=Math.PI/3,sm=2*Math.PI/3;function lm(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}var hm=lm(X_("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),dm=lm(X_("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),pm=lm(X_("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),gm=lm(X_("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function ym(t){return function(){return t}}const vm=Math.abs,_m=Math.atan2,bm=Math.cos,mm=Math.max,xm=Math.min,wm=Math.sin,Mm=Math.sqrt,Tm=1e-12,Am=Math.PI,Sm=Am/2,Em=2*Am;function Nm(t){return t>=1?Sm:t<=-1?-Sm:Math.asin(t)}function km(t){let n=3;return t.digits=function(e){if(!arguments.length)return n;if(null==e)n=null;else{const t=Math.floor(e);if(!(t>=0))throw new RangeError(`invalid digits: ${e}`);n=t}return t},()=>new Ia(n)}function Cm(t){return t.innerRadius}function Pm(t){return t.outerRadius}function zm(t){return t.startAngle}function $m(t){return t.endAngle}function Dm(t){return t&&t.padAngle}function Rm(t,n,e,r,i,o,a){var u=t-e,c=n-r,f=(a?o:-o)/Mm(u*u+c*c),s=f*c,l=-f*u,h=t+s,d=n+l,p=e+s,g=r+l,y=(h+p)/2,v=(d+g)/2,_=p-h,b=g-d,m=_*_+b*b,x=i-o,w=h*g-p*d,M=(b<0?-1:1)*Mm(mm(0,x*x*m-w*w)),T=(w*b-_*M)/m,A=(-w*_-b*M)/m,S=(w*b+_*M)/m,E=(-w*_+b*M)/m,N=T-y,k=A-v,C=S-y,P=E-v;return N*N+k*k>C*C+P*P&&(T=S,A=E),{cx:T,cy:A,x01:-s,y01:-l,x11:T*(i/x-1),y11:A*(i/x-1)}}var Fm=Array.prototype.slice;function qm(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}function Um(t){this._context=t}function Im(t){return new Um(t)}function Om(t){return t[0]}function Bm(t){return t[1]}function Ym(t,n){var e=ym(!0),r=null,i=Im,o=null,a=km(u);function u(u){var c,f,s,l=(u=qm(u)).length,h=!1;for(null==r&&(o=i(s=a())),c=0;c<=l;++c)!(c<l&&e(f=u[c],c,u))===h&&((h=!h)?o.lineStart():o.lineEnd()),h&&o.point(+t(f,c,u),+n(f,c,u));if(s)return o=null,s+""||null}return t="function"==typeof t?t:void 0===t?Om:ym(t),n="function"==typeof n?n:void 0===n?Bm:ym(n),u.x=function(n){return arguments.length?(t="function"==typeof n?n:ym(+n),u):t},u.y=function(t){return arguments.length?(n="function"==typeof t?t:ym(+t),u):n},u.defined=function(t){return arguments.length?(e="function"==typeof t?t:ym(!!t),u):e},u.curve=function(t){return arguments.length?(i=t,null!=r&&(o=i(r)),u):i},u.context=function(t){return arguments.length?(null==t?r=o=null:o=i(r=t),u):r},u}function Lm(t,n,e){var r=null,i=ym(!0),o=null,a=Im,u=null,c=km(f);function f(f){var s,l,h,d,p,g=(f=qm(f)).length,y=!1,v=new Array(g),_=new Array(g);for(null==o&&(u=a(p=c())),s=0;s<=g;++s){if(!(s<g&&i(d=f[s],s,f))===y)if(y=!y)l=s,u.areaStart(),u.lineStart();else{for(u.lineEnd(),u.lineStart(),h=s-1;h>=l;--h)u.point(v[h],_[h]);u.lineEnd(),u.areaEnd()}y&&(v[s]=+t(d,s,f),_[s]=+n(d,s,f),u.point(r?+r(d,s,f):v[s],e?+e(d,s,f):_[s]))}if(p)return u=null,p+""||null}function s(){return Ym().defined(i).curve(a).context(o)}return t="function"==typeof t?t:void 0===t?Om:ym(+t),n="function"==typeof n?n:ym(void 0===n?0:+n),e="function"==typeof e?e:void 0===e?Bm:ym(+e),f.x=function(n){return arguments.length?(t="function"==typeof n?n:ym(+n),r=null,f):t},f.x0=function(n){return arguments.length?(t="function"==typeof n?n:ym(+n),f):t},f.x1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:ym(+t),f):r},f.y=function(t){return arguments.length?(n="function"==typeof t?t:ym(+t),e=null,f):n},f.y0=function(t){return arguments.length?(n="function"==typeof t?t:ym(+t),f):n},f.y1=function(t){return arguments.length?(e=null==t?null:"function"==typeof t?t:ym(+t),f):e},f.lineX0=f.lineY0=function(){return s().x(t).y(n)},f.lineY1=function(){return s().x(t).y(e)},f.lineX1=function(){return s().x(r).y(n)},f.defined=function(t){return arguments.length?(i="function"==typeof t?t:ym(!!t),f):i},f.curve=function(t){return arguments.length?(a=t,null!=o&&(u=a(o)),f):a},f.context=function(t){return arguments.length?(null==t?o=u=null:u=a(o=t),f):o},f}function jm(t,n){return n<t?-1:n>t?1:n>=t?0:NaN}function Hm(t){return t}Um.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var Xm=Vm(Im);function Gm(t){this._curve=t}function Vm(t){function n(n){return new Gm(t(n))}return n._curve=t,n}function Wm(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(Vm(t)):n()._curve},t}function Zm(){return Wm(Ym().curve(Xm))}function Km(){var t=Lm().curve(Xm),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return Wm(e())},delete t.lineX0,t.lineEndAngle=function(){return Wm(r())},delete t.lineX1,t.lineInnerRadius=function(){return Wm(i())},delete t.lineY0,t.lineOuterRadius=function(){return Wm(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(Vm(t)):n()._curve},t}function Qm(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]}Gm.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};class Jm{constructor(t,n){this._context=t,this._x=n}areaStart(){this._line=0}areaEnd(){this._line=NaN}lineStart(){this._point=0}lineEnd(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line}point(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._x?this._context.bezierCurveTo(this._x0=(this._x0+t)/2,this._y0,this._x0,n,t,n):this._context.bezierCurveTo(this._x0,this._y0=(this._y0+n)/2,t,this._y0,t,n)}this._x0=t,this._y0=n}}class tx{constructor(t){this._context=t}lineStart(){this._point=0}lineEnd(){}point(t,n){if(t=+t,n=+n,0===this._point)this._point=1;else{const e=Qm(this._x0,this._y0),r=Qm(this._x0,this._y0=(this._y0+n)/2),i=Qm(t,this._y0),o=Qm(t,n);this._context.moveTo(...e),this._context.bezierCurveTo(...r,...i,...o)}this._x0=t,this._y0=n}}function nx(t){return new Jm(t,!0)}function ex(t){return new Jm(t,!1)}function rx(t){return new tx(t)}function ix(t){return t.source}function ox(t){return t.target}function ax(t){let n=ix,e=ox,r=Om,i=Bm,o=null,a=null,u=km(c);function c(){let c;const f=Fm.call(arguments),s=n.apply(this,f),l=e.apply(this,f);if(null==o&&(a=t(c=u())),a.lineStart(),f[0]=s,a.point(+r.apply(this,f),+i.apply(this,f)),f[0]=l,a.point(+r.apply(this,f),+i.apply(this,f)),a.lineEnd(),c)return a=null,c+""||null}return c.source=function(t){return arguments.length?(n=t,c):n},c.target=function(t){return arguments.length?(e=t,c):e},c.x=function(t){return arguments.length?(r="function"==typeof t?t:ym(+t),c):r},c.y=function(t){return arguments.length?(i="function"==typeof t?t:ym(+t),c):i},c.context=function(n){return arguments.length?(null==n?o=a=null:a=t(o=n),c):o},c}const ux=Mm(3);var cx={draw(t,n){const e=.59436*Mm(n+xm(n/28,.75)),r=e/2,i=r*ux;t.moveTo(0,e),t.lineTo(0,-e),t.moveTo(-i,-r),t.lineTo(i,r),t.moveTo(-i,r),t.lineTo(i,-r)}},fx={draw(t,n){const e=Mm(n/Am);t.moveTo(e,0),t.arc(0,0,e,0,Em)}},sx={draw(t,n){const e=Mm(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}};const lx=Mm(1/3),hx=2*lx;var dx={draw(t,n){const e=Mm(n/hx),r=e*lx;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},px={draw(t,n){const e=.62625*Mm(n);t.moveTo(0,-e),t.lineTo(e,0),t.lineTo(0,e),t.lineTo(-e,0),t.closePath()}},gx={draw(t,n){const e=.87559*Mm(n-xm(n/7,2));t.moveTo(-e,0),t.lineTo(e,0),t.moveTo(0,e),t.lineTo(0,-e)}},yx={draw(t,n){const e=Mm(n),r=-e/2;t.rect(r,r,e,e)}},vx={draw(t,n){const e=.4431*Mm(n);t.moveTo(e,e),t.lineTo(e,-e),t.lineTo(-e,-e),t.lineTo(-e,e),t.closePath()}};const _x=wm(Am/10)/wm(7*Am/10),bx=wm(Em/10)*_x,mx=-bm(Em/10)*_x;var xx={draw(t,n){const e=Mm(.8908130915292852*n),r=bx*e,i=mx*e;t.moveTo(0,-e),t.lineTo(r,i);for(let n=1;n<5;++n){const o=Em*n/5,a=bm(o),u=wm(o);t.lineTo(u*e,-a*e),t.lineTo(a*r-u*i,u*r+a*i)}t.closePath()}};const wx=Mm(3);var Mx={draw(t,n){const e=-Mm(n/(3*wx));t.moveTo(0,2*e),t.lineTo(-wx*e,-e),t.lineTo(wx*e,-e),t.closePath()}};const Tx=Mm(3);var Ax={draw(t,n){const e=.6824*Mm(n),r=e/2,i=e*Tx/2;t.moveTo(0,-e),t.lineTo(i,r),t.lineTo(-i,r),t.closePath()}};const Sx=-.5,Ex=Mm(3)/2,Nx=1/Mm(12),kx=3*(Nx/2+1);var Cx={draw(t,n){const e=Mm(n/kx),r=e/2,i=e*Nx,o=r,a=e*Nx+e,u=-o,c=a;t.moveTo(r,i),t.lineTo(o,a),t.lineTo(u,c),t.lineTo(Sx*r-Ex*i,Ex*r+Sx*i),t.lineTo(Sx*o-Ex*a,Ex*o+Sx*a),t.lineTo(Sx*u-Ex*c,Ex*u+Sx*c),t.lineTo(Sx*r+Ex*i,Sx*i-Ex*r),t.lineTo(Sx*o+Ex*a,Sx*a-Ex*o),t.lineTo(Sx*u+Ex*c,Sx*c-Ex*u),t.closePath()}},Px={draw(t,n){const e=.6189*Mm(n-xm(n/6,1.7));t.moveTo(-e,-e),t.lineTo(e,e),t.moveTo(-e,e),t.lineTo(e,-e)}};const zx=[fx,sx,dx,yx,xx,Mx,Cx],$x=[fx,gx,Px,Ax,cx,vx,px];function Dx(){}function Rx(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function Fx(t){this._context=t}function qx(t){this._context=t}function Ux(t){this._context=t}function Ix(t,n){this._basis=new Fx(t),this._beta=n}Fx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Rx(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Rx(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},qx.prototype={areaStart:Dx,areaEnd:Dx,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:Rx(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},Ux.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:Rx(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},Ix.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],a=t[e]-i,u=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*a),this._beta*n[c]+(1-this._beta)*(o+r*u));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var Ox=function t(n){function e(t){return 1===n?new Fx(t):new Ix(t,n)}return e.beta=function(n){return t(+n)},e}(.85);function Bx(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function Yx(t,n){this._context=t,this._k=(1-n)/6}Yx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:Bx(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:Bx(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Lx=function t(n){function e(t){return new Yx(t,n)}return e.tension=function(n){return t(+n)},e}(0);function jx(t,n){this._context=t,this._k=(1-n)/6}jx.prototype={areaStart:Dx,areaEnd:Dx,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:Bx(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Hx=function t(n){function e(t){return new jx(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Xx(t,n){this._context=t,this._k=(1-n)/6}Xx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Bx(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Gx=function t(n){function e(t){return new Xx(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Vx(t,n,e){var r=t._x1,i=t._y1,o=t._x2,a=t._y2;if(t._l01_a>Tm){var u=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*u-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*u-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>Tm){var f=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,s=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*f+t._x1*t._l23_2a-n*t._l12_2a)/s,a=(a*f+t._y1*t._l23_2a-e*t._l12_2a)/s}t._context.bezierCurveTo(r,i,o,a,t._x2,t._y2)}function Wx(t,n){this._context=t,this._alpha=n}Wx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:Vx(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Zx=function t(n){function e(t){return n?new Wx(t,n):new Yx(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function Kx(t,n){this._context=t,this._alpha=n}Kx.prototype={areaStart:Dx,areaEnd:Dx,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:Vx(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Qx=function t(n){function e(t){return n?new Kx(t,n):new jx(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function Jx(t,n){this._context=t,this._alpha=n}Jx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Vx(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var tw=function t(n){function e(t){return n?new Jx(t,n):new Xx(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function nw(t){this._context=t}function ew(t){return t<0?-1:1}function rw(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),a=(e-t._y1)/(i||r<0&&-0),u=(o*i+a*r)/(r+i);return(ew(o)+ew(a))*Math.min(Math.abs(o),Math.abs(a),.5*Math.abs(u))||0}function iw(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function ow(t,n,e){var r=t._x0,i=t._y0,o=t._x1,a=t._y1,u=(o-r)/3;t._context.bezierCurveTo(r+u,i+u*n,o-u,a-u*e,o,a)}function aw(t){this._context=t}function uw(t){this._context=new cw(t)}function cw(t){this._context=t}function fw(t){this._context=t}function sw(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),a=new Array(r);for(i[0]=0,o[0]=2,a[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,a[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,a[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,a[n]-=e*a[n-1];for(i[r-1]=a[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(a[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function lw(t,n){this._context=t,this._t=n}function hw(t,n){if((i=t.length)>1)for(var e,r,i,o=1,a=t[n[0]],u=a.length;o<i;++o)for(r=a,a=t[n[o]],e=0;e<u;++e)a[e][1]+=a[e][0]=isNaN(r[e][1])?r[e][0]:r[e][1]}function dw(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e}function pw(t,n){return t[n]}function gw(t){const n=[];return n.key=t,n}function yw(t){var n=t.map(vw);return dw(t).sort((function(t,e){return n[t]-n[e]}))}function vw(t){for(var n,e=-1,r=0,i=t.length,o=-1/0;++e<i;)(n=+t[e][1])>o&&(o=n,r=e);return r}function _w(t){var n=t.map(bw);return dw(t).sort((function(t,e){return n[t]-n[e]}))}function bw(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}nw.prototype={areaStart:Dx,areaEnd:Dx,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}},aw.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:ow(this,this._t0,iw(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(n=+n,(t=+t)!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,ow(this,iw(this,e=rw(this,t,n)),e);break;default:ow(this,this._t0,e=rw(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(uw.prototype=Object.create(aw.prototype)).point=function(t,n){aw.prototype.point.call(this,n,t)},cw.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},fw.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=sw(t),i=sw(n),o=0,a=1;a<e;++o,++a)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[a],n[a]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}},lw.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var mw=t=>()=>t;function xw(t,{sourceEvent:n,target:e,transform:r,dispatch:i}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},target:{value:e,enumerable:!0,configurable:!0},transform:{value:r,enumerable:!0,configurable:!0},_:{value:i}})}function ww(t,n,e){this.k=t,this.x=n,this.y=e}ww.prototype={constructor:ww,scale:function(t){return 1===t?this:new ww(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new ww(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var Mw=new ww(1,0,0);function Tw(t){for(;!t.__zoom;)if(!(t=t.parentNode))return Mw;return t.__zoom}function Aw(t){t.stopImmediatePropagation()}function Sw(t){t.preventDefault(),t.stopImmediatePropagation()}function Ew(t){return!(t.ctrlKey&&"wheel"!==t.type||t.button)}function Nw(){var t=this;return t instanceof SVGElement?(t=t.ownerSVGElement||t).hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]:[[0,0],[t.clientWidth,t.clientHeight]]}function kw(){return this.__zoom||Mw}function Cw(t){return-t.deltaY*(1===t.deltaMode?.05:t.deltaMode?1:.002)*(t.ctrlKey?10:1)}function Pw(){return navigator.maxTouchPoints||"ontouchstart"in this}function zw(t,n,e){var r=t.invertX(n[0][0])-e[0][0],i=t.invertX(n[1][0])-e[1][0],o=t.invertY(n[0][1])-e[0][1],a=t.invertY(n[1][1])-e[1][1];return t.translate(i>r?(r+i)/2:Math.min(0,r)||Math.max(0,i),a>o?(o+a)/2:Math.min(0,o)||Math.max(0,a))}Tw.prototype=ww.prototype,t.Adder=A,t.Delaunay=ju,t.FormatSpecifier=nf,t.InternMap=InternMap,t.InternSet=InternSet,t.Node=Jd,t.Path=Ia,t.Voronoi=Uu,t.ZoomTransform=ww,t.active=function(t,n){var e,r,i=t.__transition;if(i)for(r in n=null==n?null:n+"",i)if((e=i[r]).state>Ui&&e.name===n)return new go([[t]],Ko,n,+r);return null},t.arc=function(){var t=Cm,n=Pm,e=ym(0),r=null,i=zm,o=$m,a=Dm,u=null,c=km(f);function f(){var f,s,l=+t.apply(this,arguments),h=+n.apply(this,arguments),d=i.apply(this,arguments)-Sm,p=o.apply(this,arguments)-Sm,g=vm(p-d),y=p>d;if(u||(u=f=c()),h<l&&(s=h,h=l,l=s),h>Tm)if(g>Em-Tm)u.moveTo(h*bm(d),h*wm(d)),u.arc(0,0,h,d,p,!y),l>Tm&&(u.moveTo(l*bm(p),l*wm(p)),u.arc(0,0,l,p,d,y));else{var v,_,b=d,m=p,x=d,w=p,M=g,T=g,A=a.apply(this,arguments)/2,S=A>Tm&&(r?+r.apply(this,arguments):Mm(l*l+h*h)),E=xm(vm(h-l)/2,+e.apply(this,arguments)),N=E,k=E;if(S>Tm){var C=Nm(S/l*wm(A)),P=Nm(S/h*wm(A));(M-=2*C)>Tm?(x+=C*=y?1:-1,w-=C):(M=0,x=w=(d+p)/2),(T-=2*P)>Tm?(b+=P*=y?1:-1,m-=P):(T=0,b=m=(d+p)/2)}var z=h*bm(b),$=h*wm(b),D=l*bm(w),R=l*wm(w);if(E>Tm){var F,q=h*bm(m),U=h*wm(m),I=l*bm(x),O=l*wm(x);if(g<Am)if(F=function(t,n,e,r,i,o,a,u){var c=e-t,f=r-n,s=a-i,l=u-o,h=l*c-s*f;if(!(h*h<Tm))return[t+(h=(s*(n-o)-l*(t-i))/h)*c,n+h*f]}(z,$,I,O,q,U,D,R)){var B=z-F[0],Y=$-F[1],L=q-F[0],j=U-F[1],H=1/wm(function(t){return t>1?0:t<-1?Am:Math.acos(t)}((B*L+Y*j)/(Mm(B*B+Y*Y)*Mm(L*L+j*j)))/2),X=Mm(F[0]*F[0]+F[1]*F[1]);N=xm(E,(l-X)/(H-1)),k=xm(E,(h-X)/(H+1))}else N=k=0}T>Tm?k>Tm?(v=Rm(I,O,z,$,h,k,y),_=Rm(q,U,D,R,h,k,y),u.moveTo(v.cx+v.x01,v.cy+v.y01),k<E?u.arc(v.cx,v.cy,k,_m(v.y01,v.x01),_m(_.y01,_.x01),!y):(u.arc(v.cx,v.cy,k,_m(v.y01,v.x01),_m(v.y11,v.x11),!y),u.arc(0,0,h,_m(v.cy+v.y11,v.cx+v.x11),_m(_.cy+_.y11,_.cx+_.x11),!y),u.arc(_.cx,_.cy,k,_m(_.y11,_.x11),_m(_.y01,_.x01),!y))):(u.moveTo(z,$),u.arc(0,0,h,b,m,!y)):u.moveTo(z,$),l>Tm&&M>Tm?N>Tm?(v=Rm(D,R,q,U,l,-N,y),_=Rm(z,$,I,O,l,-N,y),u.lineTo(v.cx+v.x01,v.cy+v.y01),N<E?u.arc(v.cx,v.cy,N,_m(v.y01,v.x01),_m(_.y01,_.x01),!y):(u.arc(v.cx,v.cy,N,_m(v.y01,v.x01),_m(v.y11,v.x11),!y),u.arc(0,0,l,_m(v.cy+v.y11,v.cx+v.x11),_m(_.cy+_.y11,_.cx+_.x11),y),u.arc(_.cx,_.cy,N,_m(_.y11,_.x11),_m(_.y01,_.x01),!y))):u.arc(0,0,l,w,x,y):u.lineTo(D,R)}else u.moveTo(0,0);if(u.closePath(),f)return u=null,f+""||null}return f.centroid=function(){var e=(+t.apply(this,arguments)+ +n.apply(this,arguments))/2,r=(+i.apply(this,arguments)+ +o.apply(this,arguments))/2-Am/2;return[bm(r)*e,wm(r)*e]},f.innerRadius=function(n){return arguments.length?(t="function"==typeof n?n:ym(+n),f):t},f.outerRadius=function(t){return arguments.length?(n="function"==typeof t?t:ym(+t),f):n},f.cornerRadius=function(t){return arguments.length?(e="function"==typeof t?t:ym(+t),f):e},f.padRadius=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:ym(+t),f):r},f.startAngle=function(t){return arguments.length?(i="function"==typeof t?t:ym(+t),f):i},f.endAngle=function(t){return arguments.length?(o="function"==typeof t?t:ym(+t),f):o},f.padAngle=function(t){return arguments.length?(a="function"==typeof t?t:ym(+t),f):a},f.context=function(t){return arguments.length?(u=null==t?null:t,f):u},f},t.area=Lm,t.areaRadial=Km,t.ascending=n,t.autoType=function(t){for(var n in t){var e,r,i=t[n].trim();if(i)if("true"===i)i=!0;else if("false"===i)i=!1;else if("NaN"===i)i=NaN;else if(isNaN(e=+i)){if(!(r=i.match(/^([-+]\d{2})?\d{4}(-\d{2}(-\d{2})?)?(T\d{2}:\d{2}(:\d{2}(\.\d{3})?)?(Z|[-+]\d{2}:\d{2})?)?$/)))continue;vc&&r[4]&&!r[7]&&(i=i.replace(/-/g,"/").replace(/T/," ")),i=new Date(i)}else i=e;else i=null;t[n]=i}return t},t.axisBottom=function(t){return zt(Tt,t)},t.axisLeft=function(t){return zt(At,t)},t.axisRight=function(t){return zt(Mt,t)},t.axisTop=function(t){return zt(wt,t)},t.bin=J,t.bisect=l,t.bisectCenter=s,t.bisectLeft=f,t.bisectRight=c,t.bisector=r,t.blob=function(t,n){return fetch(t,n).then(_c)},t.blur=function(t,n){if(!((n=+n)>=0))throw new RangeError("invalid r");let e=t.length;if(!((e=Math.floor(e))>=0))throw new RangeError("invalid length");if(!e||!n)return t;const r=v(n),i=t.slice();return r(t,i,0,e,1),r(i,t,0,e,1),r(t,i,0,e,1),t},t.blur2=h,t.blurImage=d,t.brush=function(){return Ma(ha)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.brushX=function(){return Ma(sa)},t.brushY=function(){return Ma(la)},t.buffer=function(t,n){return fetch(t,n).then(bc)},t.chord=function(){return $a(!1,!1)},t.chordDirected=function(){return $a(!0,!1)},t.chordTranspose=function(){return $a(!1,!0)},t.cluster=function(){var t=jd,n=1,e=1,r=!1;function i(i){var o,a=0;i.eachAfter((function(n){var e=n.children;e?(n.x=function(t){return t.reduce(Hd,0)/t.length}(e),n.y=function(t){return 1+t.reduce(Xd,0)}(e)):(n.x=o?a+=t(n,o):0,n.y=0,o=n)}));var u=function(t){for(var n;n=t.children;)t=n[0];return t}(i),c=function(t){for(var n;n=t.children;)t=n[n.length-1];return t}(i),f=u.x-t(u,c)/2,s=c.x+t(c,u)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*n,t.y=(i.y-t.y)*e}:function(t){t.x=(t.x-f)/(s-f)*n,t.y=(1-(i.y?t.y/i.y:1))*e})}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.color=$e,t.contourDensity=function(){var t=su,n=lu,e=hu,r=960,i=500,o=20,a=2,u=3*o,c=r+2*u>>a,f=i+2*u>>a,s=Ja(20);function l(r){var i=new Float32Array(c*f),s=Math.pow(2,-a),l=-1;for(const o of r){var d=(t(o,++l,r)+u)*s,p=(n(o,l,r)+u)*s,g=+e(o,l,r);if(g&&d>=0&&d<c&&p>=0&&p<f){var y=Math.floor(d),v=Math.floor(p),_=d-y-.5,b=p-v-.5;i[y+v*c]+=(1-_)*(1-b)*g,i[y+1+v*c]+=_*(1-b)*g,i[y+1+(v+1)*c]+=_*b*g,i[y+(v+1)*c]+=(1-_)*b*g}}return h({data:i,width:c,height:f},o*s),i}function d(t){var n=l(t),e=s(n),r=Math.pow(2,2*a);return Array.isArray(e)||(e=V(Number.MIN_VALUE,tt(n)/r,e)),ou().size([c,f]).thresholds(e.map((t=>t*r)))(n).map(((t,n)=>(t.value=+e[n],p(t))))}function p(t){return t.coordinates.forEach(g),t}function g(t){t.forEach(y)}function y(t){t.forEach(v)}function v(t){t[0]=t[0]*Math.pow(2,a)-u,t[1]=t[1]*Math.pow(2,a)-u}function _(){return c=r+2*(u=3*o)>>a,f=i+2*u>>a,d}return d.contours=function(t){var n=l(t),e=ou().size([c,f]),r=Math.pow(2,2*a),i=t=>{t=+t;var i=p(e.contour(n,t*r));return i.value=t,i};return Object.defineProperty(i,"max",{get:()=>tt(n)/r}),i},d.x=function(n){return arguments.length?(t="function"==typeof n?n:Ja(+n),d):t},d.y=function(t){return arguments.length?(n="function"==typeof t?t:Ja(+t),d):n},d.weight=function(t){return arguments.length?(e="function"==typeof t?t:Ja(+t),d):e},d.size=function(t){if(!arguments.length)return[r,i];var n=+t[0],e=+t[1];if(!(n>=0&&e>=0))throw new Error("invalid size");return r=n,i=e,_()},d.cellSize=function(t){if(!arguments.length)return 1<<a;if(!((t=+t)>=1))throw new Error("invalid cell size");return a=Math.floor(Math.log(t)/Math.LN2),_()},d.thresholds=function(t){return arguments.length?(s="function"==typeof t?t:Array.isArray(t)?Ja(Ka.call(t)):Ja(t),d):s},d.bandwidth=function(t){if(!arguments.length)return Math.sqrt(o*(o+1));if(!((t=+t)>=0))throw new Error("invalid bandwidth");return o=(Math.sqrt(4*t*t+1)-1)/2,_()},d},t.contours=ou,t.count=_,t.create=function(t){return Kn(Lt(t).call(document.documentElement))},t.creator=Lt,t.cross=function(...t){const n="function"==typeof t[t.length-1]&&function(t){return n=>t(...n)}(t.pop()),e=(t=t.map(x)).map(b),r=t.length-1,i=new Array(r+1).fill(0),o=[];if(r<0||e.some(m))return o;for(;;){o.push(i.map(((n,e)=>t[e][n])));let a=r;for(;++i[a]===e[a];){if(0===a)return n?o.map(n):o;i[a--]=0}}},t.csv=Mc,t.csvFormat=ic,t.csvFormatBody=oc,t.csvFormatRow=uc,t.csvFormatRows=ac,t.csvFormatValue=cc,t.csvParse=ec,t.csvParseRows=rc,t.cubehelix=Ar,t.cumsum=function(t,n){var e=0,r=0;return Float64Array.from(t,void 0===n?t=>e+=+t||0:i=>e+=+n(i,r++,t)||0)},t.curveBasis=function(t){return new Fx(t)},t.curveBasisClosed=function(t){return new qx(t)},t.curveBasisOpen=function(t){return new Ux(t)},t.curveBumpX=nx,t.curveBumpY=ex,t.curveBundle=Ox,t.curveCardinal=Lx,t.curveCardinalClosed=Hx,t.curveCardinalOpen=Gx,t.curveCatmullRom=Zx,t.curveCatmullRomClosed=Qx,t.curveCatmullRomOpen=tw,t.curveLinear=Im,t.curveLinearClosed=function(t){return new nw(t)},t.curveMonotoneX=function(t){return new aw(t)},t.curveMonotoneY=function(t){return new uw(t)},t.curveNatural=function(t){return new fw(t)},t.curveStep=function(t){return new lw(t,.5)},t.curveStepAfter=function(t){return new lw(t,1)},t.curveStepBefore=function(t){return new lw(t,0)},t.descending=e,t.deviation=M,t.difference=function(t,...n){t=new InternSet(t);for(const e of n)for(const n of e)t.delete(n);return t},t.disjoint=function(t,n){const e=n[Symbol.iterator](),r=new InternSet;for(const n of t){if(r.has(n))return!1;let t,i;for(;({value:t,done:i}=e.next())&&!i;){if(Object.is(n,t))return!1;r.add(t)}}return!0},t.dispatch=Dt,t.drag=function(){var t,n,e,r,i=le,o=he,a=de,u=pe,c={},f=Dt("start","drag","end"),s=0,l=0;function h(t){t.on("mousedown.drag",d).filter(u).on("touchstart.drag",y).on("touchmove.drag",v,re).on("touchend.drag touchcancel.drag",_).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function d(a,u){if(!r&&i.call(this,a,u)){var c=b(this,o.call(this,a,u),a,u,"mouse");c&&(Kn(a.view).on("mousemove.drag",p,ie).on("mouseup.drag",g,ie),ue(a.view),oe(a),e=!1,t=a.clientX,n=a.clientY,c("start",a))}}function p(r){if(ae(r),!e){var i=r.clientX-t,o=r.clientY-n;e=i*i+o*o>l}c.mouse("drag",r)}function g(t){Kn(t.view).on("mousemove.drag mouseup.drag",null),ce(t.view,e),ae(t),c.mouse("end",t)}function y(t,n){if(i.call(this,t,n)){var e,r,a=t.changedTouches,u=o.call(this,t,n),c=a.length;for(e=0;e<c;++e)(r=b(this,u,t,n,a[e].identifier,a[e]))&&(oe(t),r("start",t,a[e]))}}function v(t){var n,e,r=t.changedTouches,i=r.length;for(n=0;n<i;++n)(e=c[r[n].identifier])&&(ae(t),e("drag",t,r[n]))}function _(t){var n,e,i=t.changedTouches,o=i.length;for(r&&clearTimeout(r),r=setTimeout((function(){r=null}),500),n=0;n<o;++n)(e=c[i[n].identifier])&&(oe(t),e("end",t,i[n]))}function b(t,n,e,r,i,o){var u,l,d,p=f.copy(),g=ee(o||e,n);if(null!=(d=a.call(t,new se("beforestart",{sourceEvent:e,target:h,identifier:i,active:s,x:g[0],y:g[1],dx:0,dy:0,dispatch:p}),r)))return u=d.x-g[0]||0,l=d.y-g[1]||0,function e(o,a,f){var y,v=g;switch(o){case"start":c[i]=e,y=s++;break;case"end":delete c[i],--s;case"drag":g=ee(f||a,n),y=s}p.call(o,t,new se(o,{sourceEvent:a,subject:d,target:h,identifier:i,active:y,x:g[0]+u,y:g[1]+l,dx:g[0]-v[0],dy:g[1]-v[1],dispatch:p}),r)}}return h.filter=function(t){return arguments.length?(i="function"==typeof t?t:fe(!!t),h):i},h.container=function(t){return arguments.length?(o="function"==typeof t?t:fe(t),h):o},h.subject=function(t){return arguments.length?(a="function"==typeof t?t:fe(t),h):a},h.touchable=function(t){return arguments.length?(u="function"==typeof t?t:fe(!!t),h):u},h.on=function(){var t=f.on.apply(f,arguments);return t===f?h:t},h.clickDistance=function(t){return arguments.length?(l=(t=+t)*t,h):Math.sqrt(l)},h},t.dragDisable=ue,t.dragEnable=ce,t.dsv=function(t,n,e,r){3===arguments.length&&"function"==typeof e&&(r=e,e=void 0);var i=tc(t);return xc(n,e).then((function(t){return i.parse(t,r)}))},t.dsvFormat=tc,t.easeBack=jo,t.easeBackIn=Yo,t.easeBackInOut=jo,t.easeBackOut=Lo,t.easeBounce=Oo,t.easeBounceIn=function(t){return 1-Oo(1-t)},t.easeBounceInOut=function(t){return((t*=2)<=1?1-Oo(1-t):Oo(t-1)+1)/2},t.easeBounceOut=Oo,t.easeCircle=ko,t.easeCircleIn=function(t){return 1-Math.sqrt(1-t*t)},t.easeCircleInOut=ko,t.easeCircleOut=function(t){return Math.sqrt(1- --t*t)},t.easeCubic=mo,t.easeCubicIn=function(t){return t*t*t},t.easeCubicInOut=mo,t.easeCubicOut=function(t){return--t*t*t+1},t.easeElastic=Go,t.easeElasticIn=Xo,t.easeElasticInOut=Vo,t.easeElasticOut=Go,t.easeExp=No,t.easeExpIn=function(t){return Eo(1-+t)},t.easeExpInOut=No,t.easeExpOut=function(t){return 1-Eo(t)},t.easeLinear=t=>+t,t.easePoly=Mo,t.easePolyIn=xo,t.easePolyInOut=Mo,t.easePolyOut=wo,t.easeQuad=bo,t.easeQuadIn=function(t){return t*t},t.easeQuadInOut=bo,t.easeQuadOut=function(t){return t*(2-t)},t.easeSin=So,t.easeSinIn=function(t){return 1==+t?1:1-Math.cos(t*Ao)},t.easeSinInOut=So,t.easeSinOut=function(t){return Math.sin(t*Ao)},t.every=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");let e=-1;for(const r of t)if(!n(r,++e,t))return!1;return!0},t.extent=T,t.fcumsum=function(t,n){const e=new A;let r=-1;return Float64Array.from(t,void 0===n?t=>e.add(+t||0):i=>e.add(+n(i,++r,t)||0))},t.filter=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");const e=[];let r=-1;for(const i of t)n(i,++r,t)&&e.push(i);return e},t.flatGroup=function(t,...n){return $(z(t,...n),n)},t.flatRollup=function(t,n,...e){return $(R(t,n,...e),e)},t.forceCenter=function(t,n){var e,r=1;function i(){var i,o,a=e.length,u=0,c=0;for(i=0;i<a;++i)u+=(o=e[i]).x,c+=o.y;for(u=(u/a-t)*r,c=(c/a-n)*r,i=0;i<a;++i)(o=e[i]).x-=u,o.y-=c}return null==t&&(t=0),null==n&&(n=0),i.initialize=function(t){e=t},i.x=function(n){return arguments.length?(t=+n,i):t},i.y=function(t){return arguments.length?(n=+t,i):n},i.strength=function(t){return arguments.length?(r=+t,i):r},i},t.forceCollide=function(t){var n,e,r,i=1,o=1;function a(){for(var t,a,c,f,s,l,h,d=n.length,p=0;p<o;++p)for(a=Dc(n,Oc,Bc).visitAfter(u),t=0;t<d;++t)c=n[t],l=e[c.index],h=l*l,f=c.x+c.vx,s=c.y+c.vy,a.visit(g);function g(t,n,e,o,a){var u=t.data,d=t.r,p=l+d;if(!u)return n>f+p||o<f-p||e>s+p||a<s-p;if(u.index>c.index){var g=f-u.x-u.vx,y=s-u.y-u.vy,v=g*g+y*y;v<p*p&&(0===g&&(v+=(g=Ic(r))*g),0===y&&(v+=(y=Ic(r))*y),v=(p-(v=Math.sqrt(v)))/v*i,c.vx+=(g*=v)*(p=(d*=d)/(h+d)),c.vy+=(y*=v)*p,u.vx-=g*(p=1-p),u.vy-=y*p)}}}function u(t){if(t.data)return t.r=e[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function c(){if(n){var r,i,o=n.length;for(e=new Array(o),r=0;r<o;++r)i=n[r],e[i.index]=+t(i,r,n)}}return"function"!=typeof t&&(t=Uc(null==t?1:+t)),a.initialize=function(t,e){n=t,r=e,c()},a.iterations=function(t){return arguments.length?(o=+t,a):o},a.strength=function(t){return arguments.length?(i=+t,a):i},a.radius=function(n){return arguments.length?(t="function"==typeof n?n:Uc(+n),c(),a):t},a},t.forceLink=function(t){var n,e,r,i,o,a,u=Yc,c=function(t){return 1/Math.min(i[t.source.index],i[t.target.index])},f=Uc(30),s=1;function l(r){for(var i=0,u=t.length;i<s;++i)for(var c,f,l,h,d,p,g,y=0;y<u;++y)f=(c=t[y]).source,h=(l=c.target).x+l.vx-f.x-f.vx||Ic(a),d=l.y+l.vy-f.y-f.vy||Ic(a),h*=p=((p=Math.sqrt(h*h+d*d))-e[y])/p*r*n[y],d*=p,l.vx-=h*(g=o[y]),l.vy-=d*g,f.vx+=h*(g=1-g),f.vy+=d*g}function h(){if(r){var a,c,f=r.length,s=t.length,l=new Map(r.map(((t,n)=>[u(t,n,r),t])));for(a=0,i=new Array(f);a<s;++a)(c=t[a]).index=a,"object"!=typeof c.source&&(c.source=Lc(l,c.source)),"object"!=typeof c.target&&(c.target=Lc(l,c.target)),i[c.source.index]=(i[c.source.index]||0)+1,i[c.target.index]=(i[c.target.index]||0)+1;for(a=0,o=new Array(s);a<s;++a)c=t[a],o[a]=i[c.source.index]/(i[c.source.index]+i[c.target.index]);n=new Array(s),d(),e=new Array(s),p()}}function d(){if(r)for(var e=0,i=t.length;e<i;++e)n[e]=+c(t[e],e,t)}function p(){if(r)for(var n=0,i=t.length;n<i;++n)e[n]=+f(t[n],n,t)}return null==t&&(t=[]),l.initialize=function(t,n){r=t,a=n,h()},l.links=function(n){return arguments.length?(t=n,h(),l):t},l.id=function(t){return arguments.length?(u=t,l):u},l.iterations=function(t){return arguments.length?(s=+t,l):s},l.strength=function(t){return arguments.length?(c="function"==typeof t?t:Uc(+t),d(),l):c},l.distance=function(t){return arguments.length?(f="function"==typeof t?t:Uc(+t),p(),l):f},l},t.forceManyBody=function(){var t,n,e,r,i,o=Uc(-30),a=1,u=1/0,c=.81;function f(e){var i,o=t.length,a=Dc(t,Gc,Vc).visitAfter(l);for(r=e,i=0;i<o;++i)n=t[i],a.visit(h)}function s(){if(t){var n,e,r=t.length;for(i=new Array(r),n=0;n<r;++n)e=t[n],i[e.index]=+o(e,n,t)}}function l(t){var n,e,r,o,a,u=0,c=0;if(t.length){for(r=o=a=0;a<4;++a)(n=t[a])&&(e=Math.abs(n.value))&&(u+=n.value,c+=e,r+=e*n.x,o+=e*n.y);t.x=r/c,t.y=o/c}else{(n=t).x=n.data.x,n.y=n.data.y;do{u+=i[n.data.index]}while(n=n.next)}t.value=u}function h(t,o,f,s){if(!t.value)return!0;var l=t.x-n.x,h=t.y-n.y,d=s-o,p=l*l+h*h;if(d*d/c<p)return p<u&&(0===l&&(p+=(l=Ic(e))*l),0===h&&(p+=(h=Ic(e))*h),p<a&&(p=Math.sqrt(a*p)),n.vx+=l*t.value*r/p,n.vy+=h*t.value*r/p),!0;if(!(t.length||p>=u)){(t.data!==n||t.next)&&(0===l&&(p+=(l=Ic(e))*l),0===h&&(p+=(h=Ic(e))*h),p<a&&(p=Math.sqrt(a*p)));do{t.data!==n&&(d=i[t.data.index]*r/p,n.vx+=l*d,n.vy+=h*d)}while(t=t.next)}}return f.initialize=function(n,r){t=n,e=r,s()},f.strength=function(t){return arguments.length?(o="function"==typeof t?t:Uc(+t),s(),f):o},f.distanceMin=function(t){return arguments.length?(a=t*t,f):Math.sqrt(a)},f.distanceMax=function(t){return arguments.length?(u=t*t,f):Math.sqrt(u)},f.theta=function(t){return arguments.length?(c=t*t,f):Math.sqrt(c)},f},t.forceRadial=function(t,n,e){var r,i,o,a=Uc(.1);function u(t){for(var a=0,u=r.length;a<u;++a){var c=r[a],f=c.x-n||1e-6,s=c.y-e||1e-6,l=Math.sqrt(f*f+s*s),h=(o[a]-l)*i[a]*t/l;c.vx+=f*h,c.vy+=s*h}}function c(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)o[n]=+t(r[n],n,r),i[n]=isNaN(o[n])?0:+a(r[n],n,r)}}return"function"!=typeof t&&(t=Uc(+t)),null==n&&(n=0),null==e&&(e=0),u.initialize=function(t){r=t,c()},u.strength=function(t){return arguments.length?(a="function"==typeof t?t:Uc(+t),c(),u):a},u.radius=function(n){return arguments.length?(t="function"==typeof n?n:Uc(+n),c(),u):t},u.x=function(t){return arguments.length?(n=+t,u):n},u.y=function(t){return arguments.length?(e=+t,u):e},u},t.forceSimulation=function(t){var n,e=1,r=.001,i=1-Math.pow(r,1/300),o=0,a=.6,u=new Map,c=ki(l),f=Dt("tick","end"),s=function(){let t=1;return()=>(t=(jc*t+Hc)%Xc)/Xc}();function l(){h(),f.call("tick",n),e<r&&(c.stop(),f.call("end",n))}function h(r){var c,f,s=t.length;void 0===r&&(r=1);for(var l=0;l<r;++l)for(e+=(o-e)*i,u.forEach((function(t){t(e)})),c=0;c<s;++c)null==(f=t[c]).fx?f.x+=f.vx*=a:(f.x=f.fx,f.vx=0),null==f.fy?f.y+=f.vy*=a:(f.y=f.fy,f.vy=0);return n}function d(){for(var n,e=0,r=t.length;e<r;++e){if((n=t[e]).index=e,null!=n.fx&&(n.x=n.fx),null!=n.fy&&(n.y=n.fy),isNaN(n.x)||isNaN(n.y)){var i=10*Math.sqrt(.5+e),o=e*Wc;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function p(n){return n.initialize&&n.initialize(t,s),n}return null==t&&(t=[]),d(),n={tick:h,restart:function(){return c.restart(l),n},stop:function(){return c.stop(),n},nodes:function(e){return arguments.length?(t=e,d(),u.forEach(p),n):t},alpha:function(t){return arguments.length?(e=+t,n):e},alphaMin:function(t){return arguments.length?(r=+t,n):r},alphaDecay:function(t){return arguments.length?(i=+t,n):+i},alphaTarget:function(t){return arguments.length?(o=+t,n):o},velocityDecay:function(t){return arguments.length?(a=1-t,n):1-a},randomSource:function(t){return arguments.length?(s=t,u.forEach(p),n):s},force:function(t,e){return arguments.length>1?(null==e?u.delete(t):u.set(t,p(e)),n):u.get(t)},find:function(n,e,r){var i,o,a,u,c,f=0,s=t.length;for(null==r?r=1/0:r*=r,f=0;f<s;++f)(a=(i=n-(u=t[f]).x)*i+(o=e-u.y)*o)<r&&(c=u,r=a);return c},on:function(t,e){return arguments.length>1?(f.on(t,e),n):f.on(t)}}},t.forceX=function(t){var n,e,r,i=Uc(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vx+=(r[o]-i.x)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=Uc(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:Uc(+t),a(),o):i},o.x=function(n){return arguments.length?(t="function"==typeof n?n:Uc(+n),a(),o):t},o},t.forceY=function(t){var n,e,r,i=Uc(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vy+=(r[o]-i.y)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=Uc(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:Uc(+t),a(),o):i},o.y=function(n){return arguments.length?(t="function"==typeof n?n:Uc(+n),a(),o):t},o},t.formatDefaultLocale=sf,t.formatLocale=ff,t.formatSpecifier=tf,t.fsum=function(t,n){const e=new A;if(void 0===n)for(let n of t)(n=+n)&&e.add(n);else{let r=-1;for(let i of t)(i=+n(i,++r,t))&&e.add(i)}return+e},t.geoAlbers=wd,t.geoAlbersUsa=function(){var t,n,e,r,i,o,a=wd(),u=xd().rotate([154,0]).center([-2,58.5]).parallels([55,65]),c=xd().rotate([157,0]).center([-3,19.9]).parallels([8,18]),f={point:function(t,n){o=[t,n]}};function s(t){var n=t[0],a=t[1];return o=null,e.point(n,a),o||(r.point(n,a),o)||(i.point(n,a),o)}function l(){return t=n=null,s}return s.invert=function(t){var n=a.scale(),e=a.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?u:i>=.166&&i<.234&&r>=-.214&&r<-.115?c:a).invert(t)},s.stream=function(e){return t&&n===e?t:(r=[a.stream(n=e),u.stream(e),c.stream(e)],i=r.length,t={point:function(t,n){for(var e=-1;++e<i;)r[e].point(t,n)},sphere:function(){for(var t=-1;++t<i;)r[t].sphere()},lineStart:function(){for(var t=-1;++t<i;)r[t].lineStart()},lineEnd:function(){for(var t=-1;++t<i;)r[t].lineEnd()},polygonStart:function(){for(var t=-1;++t<i;)r[t].polygonStart()},polygonEnd:function(){for(var t=-1;++t<i;)r[t].polygonEnd()}});var r,i},s.precision=function(t){return arguments.length?(a.precision(t),u.precision(t),c.precision(t),l()):a.precision()},s.scale=function(t){return arguments.length?(a.scale(t),u.scale(.35*t),c.scale(t),s.translate(a.translate())):a.scale()},s.translate=function(t){if(!arguments.length)return a.translate();var n=a.scale(),o=+t[0],s=+t[1];return e=a.translate(t).clipExtent([[o-.455*n,s-.238*n],[o+.455*n,s+.238*n]]).stream(f),r=u.translate([o-.307*n,s+.201*n]).clipExtent([[o-.425*n+pf,s+.12*n+pf],[o-.214*n-pf,s+.234*n-pf]]).stream(f),i=c.translate([o-.205*n,s+.212*n]).clipExtent([[o-.214*n+pf,s+.166*n+pf],[o-.115*n-pf,s+.234*n-pf]]).stream(f),l()},s.fitExtent=function(t,n){return cd(s,t,n)},s.fitSize=function(t,n){return fd(s,t,n)},s.fitWidth=function(t,n){return sd(s,t,n)},s.fitHeight=function(t,n){return ld(s,t,n)},s.scale(1070)},t.geoArea=function(t){return cs=new A,jf(t,fs),2*cs},t.geoAzimuthalEqualArea=function(){return vd(Ad).scale(124.75).clipAngle(179.999)},t.geoAzimuthalEqualAreaRaw=Ad,t.geoAzimuthalEquidistant=function(){return vd(Sd).scale(79.4188).clipAngle(179.999)},t.geoAzimuthalEquidistantRaw=Sd,t.geoBounds=function(t){var n,e,r,i,o,a,u;if(Jf=Qf=-(Zf=Kf=1/0),os=[],jf(t,qs),e=os.length){for(os.sort(Xs),n=1,o=[r=os[0]];n<e;++n)Gs(r,(i=os[n])[0])||Gs(r,i[1])?(Hs(r[0],i[1])>Hs(r[0],r[1])&&(r[1]=i[1]),Hs(i[0],r[1])>Hs(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(a=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(u=Hs(r[1],i[0]))>a&&(a=u,Zf=i[0],Qf=r[1])}return os=as=null,Zf===1/0||Kf===1/0?[[NaN,NaN],[NaN,NaN]]:[[Zf,Kf],[Qf,Jf]]},t.geoCentroid=function(t){xs=ws=Ms=Ts=As=Ss=Es=Ns=0,ks=new A,Cs=new A,Ps=new A,jf(t,Vs);var n=+ks,e=+Cs,r=+Ps,i=Nf(n,e,r);return i<gf&&(n=Ss,e=Es,r=Ns,ws<pf&&(n=Ms,e=Ts,r=As),(i=Nf(n,e,r))<gf)?[NaN,NaN]:[Tf(e,n)*mf,Ff(r/i)*mf]},t.geoCircle=function(){var t,n,e=ol([0,0]),r=ol(90),i=ol(6),o={point:function(e,r){t.push(e=n(e,r)),e[0]*=mf,e[1]*=mf}};function a(){var a=e.apply(this,arguments),u=r.apply(this,arguments)*xf,c=i.apply(this,arguments)*xf;return t=[],n=cl(-a[0]*xf,-a[1]*xf,0).invert,dl(o,u,c,1),a={type:"Polygon",coordinates:[t]},t=n=null,a}return a.center=function(t){return arguments.length?(e="function"==typeof t?t:ol([+t[0],+t[1]]),a):e},a.radius=function(t){return arguments.length?(r="function"==typeof t?t:ol(+t),a):r},a.precision=function(t){return arguments.length?(i="function"==typeof t?t:ol(+t),a):i},a},t.geoClipAntimeridian=Al,t.geoClipCircle=Sl,t.geoClipExtent=function(){var t,n,e,r=0,i=0,o=960,a=500;return e={stream:function(e){return t&&n===e?t:t=$l(r,i,o,a)(n=e)},extent:function(u){return arguments.length?(r=+u[0][0],i=+u[0][1],o=+u[1][0],a=+u[1][1],t=n=null,e):[[r,i],[o,a]]}}},t.geoClipRectangle=$l,t.geoConicConformal=function(){return bd(Cd).scale(109.5).parallels([30,30])},t.geoConicConformalRaw=Cd,t.geoConicEqualArea=xd,t.geoConicEqualAreaRaw=md,t.geoConicEquidistant=function(){return bd(zd).scale(131.154).center([0,13.9389])},t.geoConicEquidistantRaw=zd,t.geoContains=function(t,n){return(t&&Yl.hasOwnProperty(t.type)?Yl[t.type]:jl)(t,n)},t.geoDistance=Bl,t.geoEqualEarth=function(){return vd(Ud).scale(177.158)},t.geoEqualEarthRaw=Ud,t.geoEquirectangular=function(){return vd(Pd).scale(152.63)},t.geoEquirectangularRaw=Pd,t.geoGnomonic=function(){return vd(Id).scale(144.049).clipAngle(60)},t.geoGnomonicRaw=Id,t.geoGraticule=Ql,t.geoGraticule10=function(){return Ql()()},t.geoIdentity=function(){var t,n,e,r,i,o,a,u=1,c=0,f=0,s=1,l=1,h=0,d=null,p=1,g=1,y=od({point:function(t,n){var e=b([t,n]);this.stream.point(e[0],e[1])}}),v=rh;function _(){return p=u*s,g=u*l,o=a=null,b}function b(e){var r=e[0]*p,i=e[1]*g;if(h){var o=i*t-r*n;r=r*t+i*n,i=o}return[r+c,i+f]}return b.invert=function(e){var r=e[0]-c,i=e[1]-f;if(h){var o=i*t+r*n;r=r*t-i*n,i=o}return[r/p,i/g]},b.stream=function(t){return o&&a===t?o:o=y(v(a=t))},b.postclip=function(t){return arguments.length?(v=t,d=e=r=i=null,_()):v},b.clipExtent=function(t){return arguments.length?(v=null==t?(d=e=r=i=null,rh):$l(d=+t[0][0],e=+t[0][1],r=+t[1][0],i=+t[1][1]),_()):null==d?null:[[d,e],[r,i]]},b.scale=function(t){return arguments.length?(u=+t,_()):u},b.translate=function(t){return arguments.length?(c=+t[0],f=+t[1],_()):[c,f]},b.angle=function(e){return arguments.length?(n=Pf(h=e%360*xf),t=Af(h),_()):h*mf},b.reflectX=function(t){return arguments.length?(s=t?-1:1,_()):s<0},b.reflectY=function(t){return arguments.length?(l=t?-1:1,_()):l<0},b.fitExtent=function(t,n){return cd(b,t,n)},b.fitSize=function(t,n){return fd(b,t,n)},b.fitWidth=function(t,n){return sd(b,t,n)},b.fitHeight=function(t,n){return ld(b,t,n)},b},t.geoInterpolate=function(t,n){var e=t[0]*xf,r=t[1]*xf,i=n[0]*xf,o=n[1]*xf,a=Af(r),u=Pf(r),c=Af(o),f=Pf(o),s=a*Af(e),l=a*Pf(e),h=c*Af(i),d=c*Pf(i),p=2*Ff($f(qf(o-r)+a*c*qf(i-e))),g=Pf(p),y=p?function(t){var n=Pf(t*=p)/g,e=Pf(p-t)/g,r=e*s+n*h,i=e*l+n*d,o=e*u+n*f;return[Tf(i,r)*mf,Tf(o,$f(r*r+i*i))*mf]}:function(){return[e*mf,r*mf]};return y.distance=p,y},t.geoLength=Ul,t.geoMercator=function(){return Nd(Ed).scale(961/bf)},t.geoMercatorRaw=Ed,t.geoNaturalEarth1=function(){return vd(Od).scale(175.295)},t.geoNaturalEarth1Raw=Od,t.geoOrthographic=function(){return vd(Bd).scale(249.5).clipAngle(90+pf)},t.geoOrthographicRaw=Bd,t.geoPath=function(t,n){let e,r,i=3,o=4.5;function a(t){return t&&("function"==typeof o&&r.pointRadius(+o.apply(this,arguments)),jf(t,e(r))),r.result()}return a.area=function(t){return jf(t,e(lh)),lh.result()},a.measure=function(t){return jf(t,e(Qh)),Qh.result()},a.bounds=function(t){return jf(t,e(xh)),xh.result()},a.centroid=function(t){return jf(t,e(Bh)),Bh.result()},a.projection=function(n){return arguments.length?(e=null==n?(t=null,rh):(t=n).stream,a):t},a.context=function(t){return arguments.length?(r=null==t?(n=null,new rd(i)):new Yh(n=t),"function"!=typeof o&&r.pointRadius(o),a):n},a.pointRadius=function(t){return arguments.length?(o="function"==typeof t?t:(r.pointRadius(+t),+t),a):o},a.digits=function(t){if(!arguments.length)return i;if(null==t)i=null;else{const n=Math.floor(t);if(!(n>=0))throw new RangeError(`invalid digits: ${t}`);i=n}return null===n&&(r=new rd(i)),a},a.projection(t).digits(i).context(n)},t.geoProjection=vd,t.geoProjectionMutator=_d,t.geoRotation=hl,t.geoStereographic=function(){return vd(Yd).scale(250).clipAngle(142)},t.geoStereographicRaw=Yd,t.geoStream=jf,t.geoTransform=function(t){return{stream:od(t)}},t.geoTransverseMercator=function(){var t=Nd(Ld),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):[(t=n())[1],-t[0]]},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):[(t=e())[0],t[1],t[2]-90]},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=Ld,t.gray=function(t,n){return new cr(t,0,0,null==n?1:n)},t.greatest=at,t.greatestIndex=function(t,e=n){if(1===e.length)return nt(t,e);let r,i=-1,o=-1;for(const n of t)++o,(i<0?0===e(n,n):e(n,r)>0)&&(r=n,i=o);return i},t.group=P,t.groupSort=function(t,e,r){return(2!==e.length?I(D(t,e,r),(([t,e],[r,i])=>n(e,i)||n(t,r))):I(P(t,r),(([t,r],[i,o])=>e(r,o)||n(t,i)))).map((([t])=>t))},t.groups=z,t.hcl=pr,t.hierarchy=Vd,t.histogram=J,t.hsl=Xe,t.html=Nc,t.image=function(t,n){return new Promise((function(e,r){var i=new Image;for(var o in n)i[o]=n[o];i.onerror=r,i.onload=function(){e(i)},i.src=t}))},t.index=function(t,...n){return q(t,C,F,n)},t.indexes=function(t,...n){return q(t,Array.from,F,n)},t.interpolate=Vr,t.interpolateArray=function(t,n){return(Or(n)?Ir:Br)(t,n)},t.interpolateBasis=Nr,t.interpolateBasisClosed=kr,t.interpolateBlues=Gb,t.interpolateBrBG=ob,t.interpolateBuGn=Mb,t.interpolateBuPu=Ab,t.interpolateCividis=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(-4.54-t*(35.34-t*(2381.73-t*(6402.7-t*(7024.72-2710.57*t)))))))+", "+Math.max(0,Math.min(255,Math.round(32.49+t*(170.73+t*(52.82-t*(131.46-t*(176.58-67.37*t)))))))+", "+Math.max(0,Math.min(255,Math.round(81.24+t*(442.36-t*(2482.43-t*(6167.24-t*(6614.94-2475.67*t)))))))+")"},t.interpolateCool=am,t.interpolateCubehelix=hi,t.interpolateCubehelixDefault=im,t.interpolateCubehelixLong=di,t.interpolateDate=Yr,t.interpolateDiscrete=function(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}},t.interpolateGnBu=Eb,t.interpolateGreens=Wb,t.interpolateGreys=Kb,t.interpolateHcl=fi,t.interpolateHclLong=si,t.interpolateHsl=ai,t.interpolateHslLong=ui,t.interpolateHue=function(t,n){var e=zr(+t,+n);return function(t){var n=e(t);return n-360*Math.floor(n/360)}},t.interpolateInferno=pm,t.interpolateLab=function(t,n){var e=Dr((t=ur(t)).l,(n=ur(n)).l),r=Dr(t.a,n.a),i=Dr(t.b,n.b),o=Dr(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateMagma=dm,t.interpolateNumber=Lr,t.interpolateNumberArray=Ir,t.interpolateObject=jr,t.interpolateOrRd=kb,t.interpolateOranges=rm,t.interpolatePRGn=ub,t.interpolatePiYG=fb,t.interpolatePlasma=gm,t.interpolatePuBu=$b,t.interpolatePuBuGn=Pb,t.interpolatePuOr=lb,t.interpolatePuRd=Rb,t.interpolatePurples=Jb,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return um.h=360*t-100,um.s=1.5-1.5*n,um.l=.8-.9*n,um+""},t.interpolateRdBu=db,t.interpolateRdGy=gb,t.interpolateRdPu=qb,t.interpolateRdYlBu=vb,t.interpolateRdYlGn=bb,t.interpolateReds=nm,t.interpolateRgb=Rr,t.interpolateRgbBasis=qr,t.interpolateRgbBasisClosed=Ur,t.interpolateRound=Wr,t.interpolateSinebow=function(t){var n;return t=(.5-t)*Math.PI,cm.r=255*(n=Math.sin(t))*n,cm.g=255*(n=Math.sin(t+fm))*n,cm.b=255*(n=Math.sin(t+sm))*n,cm+""},t.interpolateSpectral=xb,t.interpolateString=Gr,t.interpolateTransformCss=ni,t.interpolateTransformSvg=ei,t.interpolateTurbo=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(34.61+t*(1172.33-t*(10793.56-t*(33300.12-t*(38394.49-14825.05*t)))))))+", "+Math.max(0,Math.min(255,Math.round(23.31+t*(557.33+t*(1225.33-t*(3574.96-t*(1073.77+707.56*t)))))))+", "+Math.max(0,Math.min(255,Math.round(27.2+t*(3211.1-t*(15327.97-t*(27814-t*(22569.18-6838.66*t)))))))+")"},t.interpolateViridis=hm,t.interpolateWarm=om,t.interpolateYlGn=Bb,t.interpolateYlGnBu=Ib,t.interpolateYlOrBr=Lb,t.interpolateYlOrRd=Hb,t.interpolateZoom=ii,t.interrupt=Vi,t.intersection=function(t,...n){t=new InternSet(t),n=n.map(_t);t:for(const e of t)for(const r of n)if(!r.has(e)){t.delete(e);continue t}return t},t.interval=function(t,n,e){var r=new Ni,i=n;return null==n?(r.restart(t,n,e),r):(r._restart=r.restart,r.restart=function(t,n,e){n=+n,e=null==e?Si():+e,r._restart((function o(a){a+=i,r._restart(o,i+=n,e),t(a)}),n,e)},r.restart(t,n,e),r)},t.isoFormat=R_,t.isoParse=q_,t.json=function(t,n){return fetch(t,n).then(Ac)},t.lab=ur,t.lch=function(t,n,e,r){return 1===arguments.length?dr(t):new gr(e,n,t,null==r?1:r)},t.least=function(t,e=n){let r,i=!1;if(1===e.length){let o;for(const a of t){const t=e(a);(i?n(t,o)<0:0===n(t,t))&&(r=a,o=t,i=!0)}}else for(const n of t)(i?e(n,r)<0:0===e(n,n))&&(r=n,i=!0);return r},t.leastIndex=dt,t.line=Ym,t.lineRadial=Zm,t.link=ax,t.linkHorizontal=function(){return ax(nx)},t.linkRadial=function(){const t=ax(rx);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.linkVertical=function(){return ax(ex)},t.local=Jn,t.map=function(t,n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");if("function"!=typeof n)throw new TypeError("mapper is not a function");return Array.from(t,((e,r)=>n(e,r,t)))},t.matcher=Wt,t.max=tt,t.maxIndex=nt,t.mean=function(t,n){let e=0,r=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(++e,r+=n);else{let i=-1;for(let o of t)null!=(o=n(o,++i,t))&&(o=+o)>=o&&(++e,r+=o)}if(e)return r/e},t.median=function(t,n){return ut(t,.5,n)},t.medianIndex=function(t,n){return ft(t,.5,n)},t.merge=st,t.min=et,t.minIndex=rt,t.mode=function(t,n){const e=new InternMap;if(void 0===n)for(let n of t)null!=n&&n>=n&&e.set(n,(e.get(n)||0)+1);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&i>=i&&e.set(i,(e.get(i)||0)+1)}let r,i=0;for(const[t,n]of e)n>i&&(i=n,r=t);return r},t.namespace=Ot,t.namespaces=It,t.nice=K,t.now=Si,t.pack=function(){var t=null,n=1,e=1,r=ep;function i(i){const o=up();return i.x=n/2,i.y=e/2,t?i.eachBefore(wp(t)).eachAfter(Mp(r,.5,o)).eachBefore(Tp(1)):i.eachBefore(wp(xp)).eachAfter(Mp(ep,1,o)).eachAfter(Mp(r,i.r/Math.min(n,e),o)).eachBefore(Tp(Math.min(n,e)/(2*i.r))),i}return i.radius=function(n){return arguments.length?(t=tp(n),i):t},i.size=function(t){return arguments.length?(n=+t[0],e=+t[1],i):[n,e]},i.padding=function(t){return arguments.length?(r="function"==typeof t?t:rp(+t),i):r},i},t.packEnclose=function(t){return cp(t,up())},t.packSiblings=function(t){return mp(t,up()),t},t.pairs=function(t,n=lt){const e=[];let r,i=!1;for(const o of t)i&&e.push(n(r,o)),r=o,i=!0;return e},t.partition=function(){var t=1,n=1,e=0,r=!1;function i(i){var o=i.height+1;return i.x0=i.y0=e,i.x1=t,i.y1=n/o,i.eachBefore(function(t,n){return function(r){r.children&&Sp(r,r.x0,t*(r.depth+1)/n,r.x1,t*(r.depth+2)/n);var i=r.x0,o=r.y0,a=r.x1-e,u=r.y1-e;a<i&&(i=a=(i+a)/2),u<o&&(o=u=(o+u)/2),r.x0=i,r.y0=o,r.x1=a,r.y1=u}}(n,o)),r&&i.eachBefore(Ap),i}return i.round=function(t){return arguments.length?(r=!!t,i):r},i.size=function(e){return arguments.length?(t=+e[0],n=+e[1],i):[t,n]},i.padding=function(t){return arguments.length?(e=+t,i):e},i},t.path=Oa,t.pathRound=function(t=3){return new Ia(+t)},t.permute=U,t.pie=function(){var t=Hm,n=jm,e=null,r=ym(0),i=ym(Em),o=ym(0);function a(a){var u,c,f,s,l,h=(a=qm(a)).length,d=0,p=new Array(h),g=new Array(h),y=+r.apply(this,arguments),v=Math.min(Em,Math.max(-Em,i.apply(this,arguments)-y)),_=Math.min(Math.abs(v)/h,o.apply(this,arguments)),b=_*(v<0?-1:1);for(u=0;u<h;++u)(l=g[p[u]=u]=+t(a[u],u,a))>0&&(d+=l);for(null!=n?p.sort((function(t,e){return n(g[t],g[e])})):null!=e&&p.sort((function(t,n){return e(a[t],a[n])})),u=0,f=d?(v-h*b)/d:0;u<h;++u,y=s)c=p[u],s=y+((l=g[c])>0?l*f:0)+b,g[c]={data:a[c],index:u,value:l,startAngle:y,endAngle:s,padAngle:_};return g}return a.value=function(n){return arguments.length?(t="function"==typeof n?n:ym(+n),a):t},a.sortValues=function(t){return arguments.length?(n=t,e=null,a):n},a.sort=function(t){return arguments.length?(e=t,n=null,a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:ym(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:ym(+t),a):i},a.padAngle=function(t){return arguments.length?(o="function"==typeof t?t:ym(+t),a):o},a},t.piecewise=pi,t.pointRadial=Qm,t.pointer=ee,t.pointers=function(t,n){return t.target&&(t=ne(t),void 0===n&&(n=t.currentTarget),t=t.touches||[t]),Array.from(t,(t=>ee(t,n)))},t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},t.polygonCentroid=function(t){for(var n,e,r=-1,i=t.length,o=0,a=0,u=t[i-1],c=0;++r<i;)n=u,u=t[r],c+=e=n[0]*u[1]-u[0]*n[1],o+=(n[0]+u[0])*e,a+=(n[1]+u[1])*e;return[o/(c*=3),a/c]},t.polygonContains=function(t,n){for(var e,r,i=t.length,o=t[i-1],a=n[0],u=n[1],c=o[0],f=o[1],s=!1,l=0;l<i;++l)e=(o=t[l])[0],(r=o[1])>u!=f>u&&a<(c-e)*(u-r)/(f-r)+e&&(s=!s),c=e,f=r;return s},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(Xp),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=Gp(r),a=Gp(i),u=a[0]===o[0],c=a[a.length-1]===o[o.length-1],f=[];for(n=o.length-1;n>=0;--n)f.push(t[r[o[n]][2]]);for(n=+u;n<a.length-c;++n)f.push(t[r[a[n]][2]]);return f},t.polygonLength=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],a=o[0],u=o[1],c=0;++r<i;)n=a,e=u,n-=a=(o=t[r])[0],e-=u=o[1],c+=Math.hypot(n,e);return c},t.precisionFixed=lf,t.precisionPrefix=hf,t.precisionRound=df,t.quadtree=Dc,t.quantile=ut,t.quantileIndex=ft,t.quantileSorted=ct,t.quantize=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));return e},t.quickselect=it,t.radialArea=Km,t.radialLine=Zm,t.randomBates=tg,t.randomBernoulli=rg,t.randomBeta=ag,t.randomBinomial=ug,t.randomCauchy=fg,t.randomExponential=ng,t.randomGamma=og,t.randomGeometric=ig,t.randomInt=Zp,t.randomIrwinHall=Jp,t.randomLcg=function(t=Math.random()){let n=0|(0<=t&&t<1?t/hg:Math.abs(t));return()=>(n=1664525*n+1013904223|0,hg*(n>>>0))},t.randomLogNormal=Qp,t.randomLogistic=sg,t.randomNormal=Kp,t.randomPareto=eg,t.randomPoisson=lg,t.randomUniform=Wp,t.randomWeibull=cg,t.range=ht,t.rank=function(t,e=n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");let r=Array.from(t);const i=new Float64Array(r.length);2!==e.length&&(r=r.map(e),e=n);const o=(t,n)=>e(r[t],r[n]);let a,u;return(t=Uint32Array.from(r,((t,n)=>n))).sort(e===n?(t,n)=>B(r[t],r[n]):O(o)),t.forEach(((t,n)=>{const e=o(t,void 0===a?t:a);e>=0?((void 0===a||e>0)&&(a=t,u=n),i[t]=u):i[t]=NaN})),i},t.reduce=function(t,n,e){if("function"!=typeof n)throw new TypeError("reducer is not a function");const r=t[Symbol.iterator]();let i,o,a=-1;if(arguments.length<3){if(({done:i,value:e}=r.next()),i)return;++a}for(;({done:i,value:o}=r.next()),!i;)e=n(e,o,++a,t);return e},t.reverse=function(t){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");return Array.from(t).reverse()},t.rgb=qe,t.ribbon=function(){return Za()},t.ribbonArrow=function(){return Za(Wa)},t.rollup=D,t.rollups=R,t.scaleBand=vg,t.scaleDiverging=function t(){var n=kg(j_()(xg));return n.copy=function(){return Y_(n,t())},pg.apply(n,arguments)},t.scaleDivergingLog=function t(){var n=qg(j_()).domain([.1,1,10]);return n.copy=function(){return Y_(n,t()).base(n.base())},pg.apply(n,arguments)},t.scaleDivergingPow=H_,t.scaleDivergingSqrt=function(){return H_.apply(null,arguments).exponent(.5)},t.scaleDivergingSymlog=function t(){var n=Og(j_());return n.copy=function(){return Y_(n,t()).constant(n.constant())},pg.apply(n,arguments)},t.scaleIdentity=function t(n){var e;function r(t){return null==t||isNaN(t=+t)?e:t}return r.invert=r,r.domain=r.range=function(t){return arguments.length?(n=Array.from(t,bg),r):n.slice()},r.unknown=function(t){return arguments.length?(e=t,r):e},r.copy=function(){return t(n).unknown(e)},n=arguments.length?Array.from(n,bg):[0,1],kg(r)},t.scaleImplicit=gg,t.scaleLinear=function t(){var n=Eg();return n.copy=function(){return Ag(n,t())},dg.apply(n,arguments),kg(n)},t.scaleLog=function t(){const n=qg(Sg()).domain([1,10]);return n.copy=()=>Ag(n,t()).base(n.base()),dg.apply(n,arguments),n},t.scaleOrdinal=yg,t.scalePoint=function(){return _g(vg.apply(null,arguments).paddingInner(1))},t.scalePow=Hg,t.scaleQuantile=function t(){var e,r=[],i=[],o=[];function a(){var t=0,n=Math.max(1,i.length);for(o=new Array(n-1);++t<n;)o[t-1]=ct(r,t/n);return u}function u(t){return null==t||isNaN(t=+t)?e:i[l(o,t)]}return u.invertExtent=function(t){var n=i.indexOf(t);return n<0?[NaN,NaN]:[n>0?o[n-1]:r[0],n<o.length?o[n]:r[r.length-1]]},u.domain=function(t){if(!arguments.length)return r.slice();r=[];for(let n of t)null==n||isNaN(n=+n)||r.push(n);return r.sort(n),a()},u.range=function(t){return arguments.length?(i=Array.from(t),a()):i.slice()},u.unknown=function(t){return arguments.length?(e=t,u):e},u.quantiles=function(){return o.slice()},u.copy=function(){return t().domain(r).range(i).unknown(e)},dg.apply(u,arguments)},t.scaleQuantize=function t(){var n,e=0,r=1,i=1,o=[.5],a=[0,1];function u(t){return null!=t&&t<=t?a[l(o,t,0,i)]:n}function c(){var t=-1;for(o=new Array(i);++t<i;)o[t]=((t+1)*r-(t-i)*e)/(i+1);return u}return u.domain=function(t){return arguments.length?([e,r]=t,e=+e,r=+r,c()):[e,r]},u.range=function(t){return arguments.length?(i=(a=Array.from(t)).length-1,c()):a.slice()},u.invertExtent=function(t){var n=a.indexOf(t);return n<0?[NaN,NaN]:n<1?[e,o[0]]:n>=i?[o[i-1],r]:[o[n-1],o[n]]},u.unknown=function(t){return arguments.length?(n=t,u):u},u.thresholds=function(){return o.slice()},u.copy=function(){return t().domain([e,r]).range(a).unknown(n)},dg.apply(kg(u),arguments)},t.scaleRadial=function t(){var n,e=Eg(),r=[0,1],i=!1;function o(t){var r=function(t){return Math.sign(t)*Math.sqrt(Math.abs(t))}(e(t));return isNaN(r)?n:i?Math.round(r):r}return o.invert=function(t){return e.invert(Xg(t))},o.domain=function(t){return arguments.length?(e.domain(t),o):e.domain()},o.range=function(t){return arguments.length?(e.range((r=Array.from(t,bg)).map(Xg)),o):r.slice()},o.rangeRound=function(t){return o.range(t).round(!0)},o.round=function(t){return arguments.length?(i=!!t,o):i},o.clamp=function(t){return arguments.length?(e.clamp(t),o):e.clamp()},o.unknown=function(t){return arguments.length?(n=t,o):n},o.copy=function(){return t(e.domain(),r).round(i).clamp(e.clamp()).unknown(n)},dg.apply(o,arguments),kg(o)},t.scaleSequential=function t(){var n=kg(B_()(xg));return n.copy=function(){return Y_(n,t())},pg.apply(n,arguments)},t.scaleSequentialLog=function t(){var n=qg(B_()).domain([1,10]);return n.copy=function(){return Y_(n,t()).base(n.base())},pg.apply(n,arguments)},t.scaleSequentialPow=L_,t.scaleSequentialQuantile=function t(){var e=[],r=xg;function i(t){if(null!=t&&!isNaN(t=+t))return r((l(e,t,1)-1)/(e.length-1))}return i.domain=function(t){if(!arguments.length)return e.slice();e=[];for(let n of t)null==n||isNaN(n=+n)||e.push(n);return e.sort(n),i},i.interpolator=function(t){return arguments.length?(r=t,i):r},i.range=function(){return e.map(((t,n)=>r(n/(e.length-1))))},i.quantiles=function(t){return Array.from({length:t+1},((n,r)=>ut(e,r/t)))},i.copy=function(){return t(r).domain(e)},pg.apply(i,arguments)},t.scaleSequentialSqrt=function(){return L_.apply(null,arguments).exponent(.5)},t.scaleSequentialSymlog=function t(){var n=Og(B_());return n.copy=function(){return Y_(n,t()).constant(n.constant())},pg.apply(n,arguments)},t.scaleSqrt=function(){return Hg.apply(null,arguments).exponent(.5)},t.scaleSymlog=function t(){var n=Og(Sg());return n.copy=function(){return Ag(n,t()).constant(n.constant())},dg.apply(n,arguments)},t.scaleThreshold=function t(){var n,e=[.5],r=[0,1],i=1;function o(t){return null!=t&&t<=t?r[l(e,t,0,i)]:n}return o.domain=function(t){return arguments.length?(e=Array.from(t),i=Math.min(e.length,r.length-1),o):e.slice()},o.range=function(t){return arguments.length?(r=Array.from(t),i=Math.min(e.length,r.length-1),o):r.slice()},o.invertExtent=function(t){var n=r.indexOf(t);return[e[n-1],e[n]]},o.unknown=function(t){return arguments.length?(n=t,o):n},o.copy=function(){return t().domain(e).range(r).unknown(n)},dg.apply(o,arguments)},t.scaleTime=function(){return dg.apply(O_(cv,fv,nv,Ky,wy,gy,ly,uy,oy,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)]),arguments)},t.scaleUtc=function(){return dg.apply(O_(av,uv,rv,Jy,qy,vy,dy,fy,oy,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)]),arguments)},t.scan=function(t,n){const e=dt(t,n);return e<0?void 0:e},t.schemeAccent=V_,t.schemeBlues=Xb,t.schemeBrBG=ib,t.schemeBuGn=wb,t.schemeBuPu=Tb,t.schemeCategory10=G_,t.schemeDark2=W_,t.schemeGnBu=Sb,t.schemeGreens=Vb,t.schemeGreys=Zb,t.schemeOrRd=Nb,t.schemeOranges=em,t.schemePRGn=ab,t.schemePaired=Z_,t.schemePastel1=K_,t.schemePastel2=Q_,t.schemePiYG=cb,t.schemePuBu=zb,t.schemePuBuGn=Cb,t.schemePuOr=sb,t.schemePuRd=Db,t.schemePurples=Qb,t.schemeRdBu=hb,t.schemeRdGy=pb,t.schemeRdPu=Fb,t.schemeRdYlBu=yb,t.schemeRdYlGn=_b,t.schemeReds=tm,t.schemeSet1=J_,t.schemeSet2=tb,t.schemeSet3=nb,t.schemeSpectral=mb,t.schemeTableau10=eb,t.schemeYlGn=Ob,t.schemeYlGnBu=Ub,t.schemeYlOrBr=Yb,t.schemeYlOrRd=jb,t.select=Kn,t.selectAll=function(t){return"string"==typeof t?new Wn([document.querySelectorAll(t)],[document.documentElement]):new Wn([Xt(t)],Vn)},t.selection=Zn,t.selector=Ht,t.selectorAll=Vt,t.shuffle=pt,t.shuffler=gt,t.some=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");let e=-1;for(const r of t)if(n(r,++e,t))return!0;return!1},t.sort=I,t.stack=function(){var t=ym([]),n=dw,e=hw,r=pw;function i(i){var o,a,u=Array.from(t.apply(this,arguments),gw),c=u.length,f=-1;for(const t of i)for(o=0,++f;o<c;++o)(u[o][f]=[0,+r(t,u[o].key,f,i)]).data=t;for(o=0,a=qm(n(u));o<c;++o)u[a[o]].index=o;return e(u,a),u}return i.keys=function(n){return arguments.length?(t="function"==typeof n?n:ym(Array.from(n)),i):t},i.value=function(t){return arguments.length?(r="function"==typeof t?t:ym(+t),i):r},i.order=function(t){return arguments.length?(n=null==t?dw:"function"==typeof t?t:ym(Array.from(t)),i):n},i.offset=function(t){return arguments.length?(e=null==t?hw:t,i):e},i},t.stackOffsetDiverging=function(t,n){if((u=t.length)>0)for(var e,r,i,o,a,u,c=0,f=t[n[0]].length;c<f;++c)for(o=a=0,e=0;e<u;++e)(i=(r=t[n[e]][c])[1]-r[0])>0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=a,r[0]=a+=i):(r[0]=0,r[1]=i)},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,a=t[0].length;o<a;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}hw(t,n)}},t.stackOffsetNone=hw,t.stackOffsetSilhouette=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var a=0,u=0;a<e;++a)u+=t[a][r][1]||0;i[r][1]+=i[r][0]=-u/2}hw(t,n)}},t.stackOffsetWiggle=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,a=1;a<r;++a){for(var u=0,c=0,f=0;u<i;++u){for(var s=t[n[u]],l=s[a][1]||0,h=(l-(s[a-1][1]||0))/2,d=0;d<u;++d){var p=t[n[d]];h+=(p[a][1]||0)-(p[a-1][1]||0)}c+=l,f+=h*l}e[a-1][1]+=e[a-1][0]=o,c&&(o-=f/c)}e[a-1][1]+=e[a-1][0]=o,hw(t,n)}},t.stackOrderAppearance=yw,t.stackOrderAscending=_w,t.stackOrderDescending=function(t){return _w(t).reverse()},t.stackOrderInsideOut=function(t){var n,e,r=t.length,i=t.map(bw),o=yw(t),a=0,u=0,c=[],f=[];for(n=0;n<r;++n)e=o[n],a<u?(a+=i[e],c.push(e)):(u+=i[e],f.push(e));return f.reverse().concat(c)},t.stackOrderNone=dw,t.stackOrderReverse=function(t){return dw(t).reverse()},t.stratify=function(){var t,n=Cp,e=Pp;function r(r){var i,o,a,u,c,f,s,l,h=Array.from(r),d=n,p=e,g=new Map;if(null!=t){const n=h.map(((n,e)=>function(t){t=`${t}`;let n=t.length;$p(t,n-1)&&!$p(t,n-2)&&(t=t.slice(0,-1));return"/"===t[0]?t:`/${t}`}(t(n,e,r)))),e=n.map(zp),i=new Set(n).add("");for(const t of e)i.has(t)||(i.add(t),n.push(t),e.push(zp(t)),h.push(kp));d=(t,e)=>n[e],p=(t,n)=>e[n]}for(a=0,i=h.length;a<i;++a)o=h[a],f=h[a]=new Jd(o),null!=(s=d(o,a,r))&&(s+="")&&(l=f.id=s,g.set(l,g.has(l)?Np:f)),null!=(s=p(o,a,r))&&(s+="")&&(f.parent=s);for(a=0;a<i;++a)if(s=(f=h[a]).parent){if(!(c=g.get(s)))throw new Error("missing: "+s);if(c===Np)throw new Error("ambiguous: "+s);c.children?c.children.push(f):c.children=[f],f.parent=c}else{if(u)throw new Error("multiple roots");u=f}if(!u)throw new Error("no root");if(null!=t){for(;u.data===kp&&1===u.children.length;)u=u.children[0],--i;for(let t=h.length-1;t>=0&&(f=h[t]).data===kp;--t)f.data=null}if(u.parent=Ep,u.eachBefore((function(t){t.depth=t.parent.depth+1,--i})).eachBefore(Qd),u.parent=null,i>0)throw new Error("cycle");return u}return r.id=function(t){return arguments.length?(n=tp(t),r):n},r.parentId=function(t){return arguments.length?(e=tp(t),r):e},r.path=function(n){return arguments.length?(t=tp(n),r):t},r},t.style=bn,t.subset=function(t,n){return bt(n,t)},t.sum=function(t,n){let e=0;if(void 0===n)for(let n of t)(n=+n)&&(e+=n);else{let r=-1;for(let i of t)(i=+n(i,++r,t))&&(e+=i)}return e},t.superset=bt,t.svg=kc,t.symbol=function(t,n){let e=null,r=km(i);function i(){let i;if(e||(e=i=r()),t.apply(this,arguments).draw(e,+n.apply(this,arguments)),i)return e=null,i+""||null}return t="function"==typeof t?t:ym(t||fx),n="function"==typeof n?n:ym(void 0===n?64:+n),i.type=function(n){return arguments.length?(t="function"==typeof n?n:ym(n),i):t},i.size=function(t){return arguments.length?(n="function"==typeof t?t:ym(+t),i):n},i.context=function(t){return arguments.length?(e=null==t?null:t,i):e},i},t.symbolAsterisk=cx,t.symbolCircle=fx,t.symbolCross=sx,t.symbolDiamond=dx,t.symbolDiamond2=px,t.symbolPlus=gx,t.symbolSquare=yx,t.symbolSquare2=vx,t.symbolStar=xx,t.symbolTimes=Px,t.symbolTriangle=Mx,t.symbolTriangle2=Ax,t.symbolWye=Cx,t.symbolX=Px,t.symbols=zx,t.symbolsFill=zx,t.symbolsStroke=$x,t.text=xc,t.thresholdFreedmanDiaconis=function(t,n,e){const r=_(t),i=ut(t,.75)-ut(t,.25);return r&&i?Math.ceil((e-n)/(2*i*Math.pow(r,-1/3))):1},t.thresholdScott=function(t,n,e){const r=_(t),i=M(t);return r&&i?Math.ceil((e-n)*Math.cbrt(r)/(3.49*i)):1},t.thresholdSturges=Q,t.tickFormat=Ng,t.tickIncrement=W,t.tickStep=Z,t.ticks=V,t.timeDay=gy,t.timeDays=yy,t.timeFormatDefaultLocale=z_,t.timeFormatLocale=dv,t.timeFriday=Ey,t.timeFridays=Dy,t.timeHour=ly,t.timeHours=hy,t.timeInterval=Wg,t.timeMillisecond=Zg,t.timeMilliseconds=Kg,t.timeMinute=uy,t.timeMinutes=cy,t.timeMonday=My,t.timeMondays=Cy,t.timeMonth=Ky,t.timeMonths=Qy,t.timeSaturday=Ny,t.timeSaturdays=Ry,t.timeSecond=oy,t.timeSeconds=ay,t.timeSunday=wy,t.timeSundays=ky,t.timeThursday=Sy,t.timeThursdays=$y,t.timeTickInterval=fv,t.timeTicks=cv,t.timeTuesday=Ty,t.timeTuesdays=Py,t.timeWednesday=Ay,t.timeWednesdays=zy,t.timeWeek=wy,t.timeWeeks=ky,t.timeYear=nv,t.timeYears=ev,t.timeout=Di,t.timer=ki,t.timerFlush=Ci,t.transition=yo,t.transpose=yt,t.tree=function(){var t=Dp,n=1,e=1,r=null;function i(i){var c=function(t){for(var n,e,r,i,o,a=new Ip(t,0),u=[a];n=u.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)u.push(e=n.children[i]=new Ip(r[i],i)),e.parent=n;return(a.parent=new Ip(null,0)).children=[a],a}(i);if(c.eachAfter(o),c.parent.m=-c.z,c.eachBefore(a),r)i.eachBefore(u);else{var f=i,s=i,l=i;i.eachBefore((function(t){t.x<f.x&&(f=t),t.x>s.x&&(s=t),t.depth>l.depth&&(l=t)}));var h=f===s?1:t(f,s)/2,d=h-f.x,p=n/(s.x+h+d),g=e/(l.depth||1);i.eachBefore((function(t){t.x=(t.x+d)*p,t.y=t.depth*g}))}return i}function o(n){var e=n.children,r=n.parent.children,i=n.i?r[n.i-1]:null;if(e){!function(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}(n);var o=(e[0].z+e[e.length-1].z)/2;i?(n.z=i.z+t(n._,i._),n.m=n.z-o):n.z=o}else i&&(n.z=i.z+t(n._,i._));n.parent.A=function(n,e,r){if(e){for(var i,o=n,a=n,u=e,c=o.parent.children[0],f=o.m,s=a.m,l=u.m,h=c.m;u=Fp(u),o=Rp(o),u&&o;)c=Rp(c),(a=Fp(a)).a=n,(i=u.z+l-o.z-f+t(u._,o._))>0&&(qp(Up(u,n,r),n,i),f+=i,s+=i),l+=u.m,f+=o.m,h+=c.m,s+=a.m;u&&!Fp(a)&&(a.t=u,a.m+=l-s),o&&!Rp(c)&&(c.t=o,c.m+=f-h,r=n)}return r}(n,i,n.parent.A||r[0])}function a(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function u(t){t.x*=n,t.y=t.depth*e}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.treemap=function(){var t=Lp,n=!1,e=1,r=1,i=[0],o=ep,a=ep,u=ep,c=ep,f=ep;function s(t){return t.x0=t.y0=0,t.x1=e,t.y1=r,t.eachBefore(l),i=[0],n&&t.eachBefore(Ap),t}function l(n){var e=i[n.depth],r=n.x0+e,s=n.y0+e,l=n.x1-e,h=n.y1-e;l<r&&(r=l=(r+l)/2),h<s&&(s=h=(s+h)/2),n.x0=r,n.y0=s,n.x1=l,n.y1=h,n.children&&(e=i[n.depth+1]=o(n)/2,r+=f(n)-e,s+=a(n)-e,(l-=u(n)-e)<r&&(r=l=(r+l)/2),(h-=c(n)-e)<s&&(s=h=(s+h)/2),t(n,r,s,l,h))}return s.round=function(t){return arguments.length?(n=!!t,s):n},s.size=function(t){return arguments.length?(e=+t[0],r=+t[1],s):[e,r]},s.tile=function(n){return arguments.length?(t=np(n),s):t},s.padding=function(t){return arguments.length?s.paddingInner(t).paddingOuter(t):s.paddingInner()},s.paddingInner=function(t){return arguments.length?(o="function"==typeof t?t:rp(+t),s):o},s.paddingOuter=function(t){return arguments.length?s.paddingTop(t).paddingRight(t).paddingBottom(t).paddingLeft(t):s.paddingTop()},s.paddingTop=function(t){return arguments.length?(a="function"==typeof t?t:rp(+t),s):a},s.paddingRight=function(t){return arguments.length?(u="function"==typeof t?t:rp(+t),s):u},s.paddingBottom=function(t){return arguments.length?(c="function"==typeof t?t:rp(+t),s):c},s.paddingLeft=function(t){return arguments.length?(f="function"==typeof t?t:rp(+t),s):f},s},t.treemapBinary=function(t,n,e,r,i){var o,a,u=t.children,c=u.length,f=new Array(c+1);for(f[0]=a=o=0;o<c;++o)f[o+1]=a+=u[o].value;!function t(n,e,r,i,o,a,c){if(n>=e-1){var s=u[n];return s.x0=i,s.y0=o,s.x1=a,void(s.y1=c)}var l=f[n],h=r/2+l,d=n+1,p=e-1;for(;d<p;){var g=d+p>>>1;f[g]<h?d=g+1:p=g}h-f[d-1]<f[d]-h&&n+1<d&&--d;var y=f[d]-l,v=r-y;if(a-i>c-o){var _=r?(i*v+a*y)/r:a;t(n,d,y,i,o,_,c),t(d,e,v,_,o,a,c)}else{var b=r?(o*v+c*y)/r:c;t(n,d,y,i,o,a,b),t(d,e,v,i,b,a,c)}}(0,c,t.value,n,e,r,i)},t.treemapDice=Sp,t.treemapResquarify=jp,t.treemapSlice=Op,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?Op:Sp)(t,n,e,r,i)},t.treemapSquarify=Lp,t.tsv=Tc,t.tsvFormat=hc,t.tsvFormatBody=dc,t.tsvFormatRow=gc,t.tsvFormatRows=pc,t.tsvFormatValue=yc,t.tsvParse=sc,t.tsvParseRows=lc,t.union=function(...t){const n=new InternSet;for(const e of t)for(const t of e)n.add(t);return n},t.unixDay=by,t.unixDays=my,t.utcDay=vy,t.utcDays=_y,t.utcFriday=Yy,t.utcFridays=Wy,t.utcHour=dy,t.utcHours=py,t.utcMillisecond=Zg,t.utcMilliseconds=Kg,t.utcMinute=fy,t.utcMinutes=sy,t.utcMonday=Uy,t.utcMondays=Hy,t.utcMonth=Jy,t.utcMonths=tv,t.utcSaturday=Ly,t.utcSaturdays=Zy,t.utcSecond=oy,t.utcSeconds=ay,t.utcSunday=qy,t.utcSundays=jy,t.utcThursday=By,t.utcThursdays=Vy,t.utcTickInterval=uv,t.utcTicks=av,t.utcTuesday=Iy,t.utcTuesdays=Xy,t.utcWednesday=Oy,t.utcWednesdays=Gy,t.utcWeek=qy,t.utcWeeks=jy,t.utcYear=rv,t.utcYears=iv,t.variance=w,t.version="7.8.4",t.window=gn,t.xml=Ec,t.zip=function(){return yt(arguments)},t.zoom=function(){var t,n,e,r=Ew,i=Nw,o=zw,a=Cw,u=Pw,c=[0,1/0],f=[[-1/0,-1/0],[1/0,1/0]],s=250,l=ii,h=Dt("start","zoom","end"),d=500,p=150,g=0,y=10;function v(t){t.property("__zoom",kw).on("wheel.zoom",T,{passive:!1}).on("mousedown.zoom",A).on("dblclick.zoom",S).filter(u).on("touchstart.zoom",E).on("touchmove.zoom",N).on("touchend.zoom touchcancel.zoom",k).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function _(t,n){return(n=Math.max(c[0],Math.min(c[1],n)))===t.k?t:new ww(n,t.x,t.y)}function b(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new ww(t.k,r,i)}function m(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function x(t,n,e,r){t.on("start.zoom",(function(){w(this,arguments).event(r).start()})).on("interrupt.zoom end.zoom",(function(){w(this,arguments).event(r).end()})).tween("zoom",(function(){var t=this,o=arguments,a=w(t,o).event(r),u=i.apply(t,o),c=null==e?m(u):"function"==typeof e?e.apply(t,o):e,f=Math.max(u[1][0]-u[0][0],u[1][1]-u[0][1]),s=t.__zoom,h="function"==typeof n?n.apply(t,o):n,d=l(s.invert(c).concat(f/s.k),h.invert(c).concat(f/h.k));return function(t){if(1===t)t=h;else{var n=d(t),e=f/n[2];t=new ww(e,c[0]-n[0]*e,c[1]-n[1]*e)}a.zoom(null,t)}}))}function w(t,n,e){return!e&&t.__zooming||new M(t,n)}function M(t,n){this.that=t,this.args=n,this.active=0,this.sourceEvent=null,this.extent=i.apply(t,n),this.taps=0}function T(t,...n){if(r.apply(this,arguments)){var e=w(this,n).event(t),i=this.__zoom,u=Math.max(c[0],Math.min(c[1],i.k*Math.pow(2,a.apply(this,arguments)))),s=ee(t);if(e.wheel)e.mouse[0][0]===s[0]&&e.mouse[0][1]===s[1]||(e.mouse[1]=i.invert(e.mouse[0]=s)),clearTimeout(e.wheel);else{if(i.k===u)return;e.mouse=[s,i.invert(s)],Vi(this),e.start()}Sw(t),e.wheel=setTimeout((function(){e.wheel=null,e.end()}),p),e.zoom("mouse",o(b(_(i,u),e.mouse[0],e.mouse[1]),e.extent,f))}}function A(t,...n){if(!e&&r.apply(this,arguments)){var i=t.currentTarget,a=w(this,n,!0).event(t),u=Kn(t.view).on("mousemove.zoom",(function(t){if(Sw(t),!a.moved){var n=t.clientX-s,e=t.clientY-l;a.moved=n*n+e*e>g}a.event(t).zoom("mouse",o(b(a.that.__zoom,a.mouse[0]=ee(t,i),a.mouse[1]),a.extent,f))}),!0).on("mouseup.zoom",(function(t){u.on("mousemove.zoom mouseup.zoom",null),ce(t.view,a.moved),Sw(t),a.event(t).end()}),!0),c=ee(t,i),s=t.clientX,l=t.clientY;ue(t.view),Aw(t),a.mouse=[c,this.__zoom.invert(c)],Vi(this),a.start()}}function S(t,...n){if(r.apply(this,arguments)){var e=this.__zoom,a=ee(t.changedTouches?t.changedTouches[0]:t,this),u=e.invert(a),c=e.k*(t.shiftKey?.5:2),l=o(b(_(e,c),a,u),i.apply(this,n),f);Sw(t),s>0?Kn(this).transition().duration(s).call(x,l,a,t):Kn(this).call(v.transform,l,a,t)}}function E(e,...i){if(r.apply(this,arguments)){var o,a,u,c,f=e.touches,s=f.length,l=w(this,i,e.changedTouches.length===s).event(e);for(Aw(e),a=0;a<s;++a)c=[c=ee(u=f[a],this),this.__zoom.invert(c),u.identifier],l.touch0?l.touch1||l.touch0[2]===c[2]||(l.touch1=c,l.taps=0):(l.touch0=c,o=!0,l.taps=1+!!t);t&&(t=clearTimeout(t)),o&&(l.taps<2&&(n=c[0],t=setTimeout((function(){t=null}),d)),Vi(this),l.start())}}function N(t,...n){if(this.__zooming){var e,r,i,a,u=w(this,n).event(t),c=t.changedTouches,s=c.length;for(Sw(t),e=0;e<s;++e)i=ee(r=c[e],this),u.touch0&&u.touch0[2]===r.identifier?u.touch0[0]=i:u.touch1&&u.touch1[2]===r.identifier&&(u.touch1[0]=i);if(r=u.that.__zoom,u.touch1){var l=u.touch0[0],h=u.touch0[1],d=u.touch1[0],p=u.touch1[1],g=(g=d[0]-l[0])*g+(g=d[1]-l[1])*g,y=(y=p[0]-h[0])*y+(y=p[1]-h[1])*y;r=_(r,Math.sqrt(g/y)),i=[(l[0]+d[0])/2,(l[1]+d[1])/2],a=[(h[0]+p[0])/2,(h[1]+p[1])/2]}else{if(!u.touch0)return;i=u.touch0[0],a=u.touch0[1]}u.zoom("touch",o(b(r,i,a),u.extent,f))}}function k(t,...r){if(this.__zooming){var i,o,a=w(this,r).event(t),u=t.changedTouches,c=u.length;for(Aw(t),e&&clearTimeout(e),e=setTimeout((function(){e=null}),d),i=0;i<c;++i)o=u[i],a.touch0&&a.touch0[2]===o.identifier?delete a.touch0:a.touch1&&a.touch1[2]===o.identifier&&delete a.touch1;if(a.touch1&&!a.touch0&&(a.touch0=a.touch1,delete a.touch1),a.touch0)a.touch0[1]=this.__zoom.invert(a.touch0[0]);else if(a.end(),2===a.taps&&(o=ee(o,this),Math.hypot(n[0]-o[0],n[1]-o[1])<y)){var f=Kn(this).on("dblclick.zoom");f&&f.apply(this,arguments)}}}return v.transform=function(t,n,e,r){var i=t.selection?t.selection():t;i.property("__zoom",kw),t!==i?x(t,n,e,r):i.interrupt().each((function(){w(this,arguments).event(r).start().zoom(null,"function"==typeof n?n.apply(this,arguments):n).end()}))},v.scaleBy=function(t,n,e,r){v.scaleTo(t,(function(){return this.__zoom.k*("function"==typeof n?n.apply(this,arguments):n)}),e,r)},v.scaleTo=function(t,n,e,r){v.transform(t,(function(){var t=i.apply(this,arguments),r=this.__zoom,a=null==e?m(t):"function"==typeof e?e.apply(this,arguments):e,u=r.invert(a),c="function"==typeof n?n.apply(this,arguments):n;return o(b(_(r,c),a,u),t,f)}),e,r)},v.translateBy=function(t,n,e,r){v.transform(t,(function(){return o(this.__zoom.translate("function"==typeof n?n.apply(this,arguments):n,"function"==typeof e?e.apply(this,arguments):e),i.apply(this,arguments),f)}),null,r)},v.translateTo=function(t,n,e,r,a){v.transform(t,(function(){var t=i.apply(this,arguments),a=this.__zoom,u=null==r?m(t):"function"==typeof r?r.apply(this,arguments):r;return o(Mw.translate(u[0],u[1]).scale(a.k).translate("function"==typeof n?-n.apply(this,arguments):-n,"function"==typeof e?-e.apply(this,arguments):-e),t,f)}),r,a)},M.prototype={event:function(t){return t&&(this.sourceEvent=t),this},start:function(){return 1==++this.active&&(this.that.__zooming=this,this.emit("start")),this},zoom:function(t,n){return this.mouse&&"mouse"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&"touch"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&"touch"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit("zoom"),this},end:function(){return 0==--this.active&&(delete this.that.__zooming,this.emit("end")),this},emit:function(t){var n=Kn(this.that).datum();h.call(t,this.that,new xw(t,{sourceEvent:this.sourceEvent,target:v,type:t,transform:this.that.__zoom,dispatch:h}),n)}},v.wheelDelta=function(t){return arguments.length?(a="function"==typeof t?t:mw(+t),v):a},v.filter=function(t){return arguments.length?(r="function"==typeof t?t:mw(!!t),v):r},v.touchable=function(t){return arguments.length?(u="function"==typeof t?t:mw(!!t),v):u},v.extent=function(t){return arguments.length?(i="function"==typeof t?t:mw([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),v):i},v.scaleExtent=function(t){return arguments.length?(c[0]=+t[0],c[1]=+t[1],v):[c[0],c[1]]},v.translateExtent=function(t){return arguments.length?(f[0][0]=+t[0][0],f[1][0]=+t[1][0],f[0][1]=+t[0][1],f[1][1]=+t[1][1],v):[[f[0][0],f[0][1]],[f[1][0],f[1][1]]]},v.constrain=function(t){return arguments.length?(o=t,v):o},v.duration=function(t){return arguments.length?(s=+t,v):s},v.interpolate=function(t){return arguments.length?(l=t,v):l},v.on=function(){var t=h.on.apply(h,arguments);return t===h?v:t},v.clickDistance=function(t){return arguments.length?(g=(t=+t)*t,v):Math.sqrt(g)},v.tapDistance=function(t){return arguments.length?(y=+t,v):y},v},t.zoomIdentity=Mw,t.zoomTransform=Tw}));
diff --git a/third_party/d3/src/externs.js b/third_party/d3/src/externs.js
deleted file mode 100644
index 56f41b4c..0000000
--- a/third_party/d3/src/externs.js
+++ /dev/null
@@ -1,8079 +0,0 @@
-/**
- * @fileoverview Definitions for the D3.js library, based on the D3 API
- * reference at https://github.com/d3/d3/blob/master/API.md
- *
- * Some definitions were dumbed down, because JSCompiler has limited support for
- * function properties, overloads and tuples. A complete list of TypeScript
- * definitions is available at
- * https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/d3
- *
- * Usage examples can be found at http://blockbuilder.org/search#d3version=v4
- *
- * @externs
- */
-
-/**
- * @const
- * @suppress {checkTypes} Prevents a mysterious compiler error triggered by the
- *     `const` annotation:
- *     "ERROR - initializing variable"
- *     found: {Arc: None, Arc_: ..., ...}
- *     required: {active: ..., arc: ..., ...}
- *     var d3 = {};
- */
-var d3 = {};
-
-/**
- * @type {string}
- */
-d3.version;
-
-////////////////////////////////////////////////////////////////////////////////
-// Arrays
-// https://github.com/d3/d3-array
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-// Statistics
-
-/**
- * TODO(pallosp): Narrow down accessor's type when
- *     https://github.com/google/closure-compiler/issues/2052 is fixed.
- * @param {!Array} array
- * @param {?Function=} accessor
- */
-d3.min = function(array, accessor) {};
-
-/**
- * @param {!Array} array
- * @param {?Function=} accessor
- */
-d3.max = function(array, accessor) {};
-
-/**
- * @param {!Array} array
- * @param {?Function=} accessor
- */
-d3.extent = function(array, accessor) {};
-
-/**
- * @param {!Array} array
- * @param {?Function=} accessor
- * @return {number}
- */
-d3.sum = function(array, accessor) {};
-
-/**
- * @param {!Array} array
- * @param {?Function=} accessor
- * @return {number | undefined}
- */
-d3.mean = function(array, accessor) {};
-
-/**
- * @param {!Array} array
- * @param {?Function=} accessor
- * @return {number | undefined}
- */
-d3.median = function(array, accessor) {};
-
-/**
- * @param {!Array} array
- * @param {number} p
- * @param {?Function=} accessor
- * @return {number | undefined}
- */
-d3.quantile = function(array, p, accessor) {};
-
-/**
- * @param {!Array} array
- * @param {?Function=} accessor
- * @return {number | undefined}
- */
-d3.variance = function(array, accessor) {};
-
-/**
- * @param {!Array} array
- * @param {?Function=} accessor
- * @return {number | undefined}
- */
-d3.deviation = function(array, accessor) {};
-
-// Search
-
-/**
- * @param {!Array<T>} array
- * @param {function(T, T): number=} comparator
- * @return {number}
- * @template T
- */
-d3.scan = function(array, comparator) {};
-
-/**
- * @param {!Array<T>} array
- * @param {T} x
- * @param {number=} lo
- * @param {number=} hi
- * @return {number}
- * @template T
- */
-d3.bisectLeft = function(array, x, lo, hi) {};
-
-/**
- * @param {!Array<T>} array
- * @param {T} x
- * @param {number=} lo
- * @param {number=} hi
- * @return {number}
- * @template T
- */
-d3.bisect = function(array, x, lo, hi) {};
-
-/**
- * @param {!Array<T>} array
- * @param {T} x
- * @param {number=} lo
- * @param {number=} hi
- * @return {number}
- * @template T
- */
-d3.bisectRight = function(array, x, lo, hi) {};
-
-/**
- * @param {!Function} accessorOrComparator
- * @return {{
- *   left: function(!Array, ?, number=, number=): number,
- *   right: function(!Array, ?, number=, number=): number
- * }}
- */
-d3.bisector = function(accessorOrComparator) {};
-
-/**
- * @param {?} a
- * @param {?} b
- * @return {number}
- */
-d3.ascending = function(a, b) {};
-
-/**
- * @param {?} a
- * @param {?} b
- * @return {number}
- */
-d3.descending = function(a, b) {};
-
-// Transformations
-
-/**
- * @param {!Array<T>} a
- * @param {!Array<U>} b
- * @param {function(T, U)=} reducer
- * @return {!Array}
- * @template T, U
- */
-d3.cross = function(a, b, reducer) {};
-
-/**
- * @param {!Array<!Array<T>>} arrays
- * @return {!Array<T>}
- * @template T
- */
-d3.merge = function(arrays) {};
-
-/**
- * @param {!Array<T>} array
- * @param {function(T, T)=} reducer
- * @return {!Array<!Array>}
- * @template T
- */
-d3.pairs = function(array, reducer) {};
-
-/**
- * @param {!Object<K, V>} arrayOrMap
- * @param {!Array<K>} indexes
- * @return {!Array<V>}
- * @template K, V
- */
-d3.permute = function(arrayOrMap, indexes) {};
-
-/**
- * @param {!Array<T>} array
- * @param {number=} lo
- * @param {number=} hi
- * @return {!Array<T>}
- * @template T
- */
-d3.shuffle = function(array, lo, hi) {};
-
-/**
- * @param {number} start
- * @param {number} stop
- * @param {number} count
- * @return {!Array<number>}
- */
-d3.ticks = function(start, stop, count) {};
-
-/**
- * @param {number} start
- * @param {number} stop
- * @param {number} count
- * @return {number}
- */
-d3.tickIncrement = function(start, stop, count) {};
-
-/**
- * @param {number} start
- * @param {number} stop
- * @param {number} count
- * @return {number}
- */
-d3.tickStep = function(start, stop, count) {};
-
-/**
- * @param {number} startOrStop
- * @param {number=} stop
- * @param {number=} step
- * @return {!Array<number>}
- */
-d3.range = function(startOrStop, stop, step) {};
-
-/**
- * @param {!Array<!Array<T>>} matrix
- * @return {!Array<!Array<T>>}
- * @template T
- */
-d3.transpose = function(matrix) {};
-
-/**
- * @param {...!Array<T>} var_args
- * @return {!Array<!Array<T>>}
- * @template T
- */
-d3.zip = function(var_args) {};
-
-// Histograms
-
-/**
- * @return {!d3.Histogram}
- */
-d3.histogram = function() {};
-
-/**
- * @typedef {function(!Array<number>): !Array<!Array<number>>}
- */
-d3.Histogram;
-
-/**
- * @private {!d3.Histogram}
- */
-d3.Histogram_;
-
-/**
- * @param {function(T, number, !Array<T>): (number | !Date)=} value
- * @template T
- */
-d3.Histogram_.value = function(value) {};
-
-/**
- * @param {!Array<number | !Date> |
- *     function(!Array): !Array<number | !Date>=} domain
- */
-d3.Histogram_.domain = function(domain) {};
-
-/**
- * @param {number | !Array<number | !Date> | function(!Array, ?, ?)=}
- *     countOrThresholds
- */
-d3.Histogram_.thresholds = function(countOrThresholds) {};
-
-// Histogram Thresholds
-
-/**
- * @param {!Array<number>} values
- * @param {number} min
- * @param {number} max
- * @return {number}
- */
-d3.thresholdFreedmanDiaconis = function(values, min, max) {};
-
-/**
- * @param {!Array<number>} values
- * @param {number} min
- * @param {number} max
- * @return {number}
- */
-d3.thresholdScott = function(values, min, max) {};
-
-/**
- * @param {!Array<number>} values
- * @return {number}
- */
-d3.thresholdSturges = function(values) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Axes
-// https://github.com/d3/d3-axis
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- * @param {function(?): ?} scale
- * @return {!d3.Axis}
- */
-d3.axisTop = function(scale) {};
-
-/**
- * @param {function(?): ?} scale
- * @return {!d3.Axis}
- */
-d3.axisRight = function(scale) {};
-
-/**
- * @param {function(?): ?} scale
- * @return {!d3.Axis}
- */
-d3.axisBottom = function(scale) {};
-
-/**
- * @param {function(?): ?} scale
- * @return {!d3.Axis}
- */
-d3.axisLeft = function(scale) {};
-
-/**
- * @typedef {function(!(d3.selection | d3.transition))}
- */
-d3.Axis;
-
-/**
- * @private {!d3.Axis}
- */
-d3.Axis_;
-
-/**
- * @param {function(?): ?=} scale
- */
-d3.Axis_.scale = function(scale) {};
-
-/**
- * @param {?} countOrIntervalOrAny
- * @param {...?} var_args
- * @return {!d3.Axis}
- */
-d3.Axis_.ticks = function(countOrIntervalOrAny, var_args) {};
-
-/**
- * @param {!Array=} args
- */
-d3.Axis_.tickArguments = function(args) {};
-
-/**
- * @param {?Array=} values
- */
-d3.Axis_.tickValues = function(values) {};
-
-/**
- * @param {?function(?): string=} format
- */
-d3.Axis_.tickFormat = function(format) {};
-
-/**
- * @param {number=} size
- */
-d3.Axis_.tickSize = function(size) {};
-
-/**
- * @param {number=} size
- */
-d3.Axis_.tickSizeInner = function(size) {};
-
-/**
- * @param {number=} size
- */
-d3.Axis_.tickSizeOuter = function(size) {};
-
-/**
- * @param {number=} padding
- */
-d3.Axis_.tickPadding = function(padding) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Brushes
-// https://github.com/d3/d3-brush
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @return {!d3.Brush}
- */
-d3.brush = function() {};
-
-/**
- * @return {!d3.Brush}
- */
-d3.brushX = function() {};
-
-/**
- * @return {!d3.Brush}
- */
-d3.brushY = function() {};
-
-/**
- * @typedef {function(!d3.selection)}
- */
-d3.Brush;
-
-/**
- * @private {!d3.Brush}
- */
-d3.Brush_;
-
-/**
- * @param {!(d3.selection | d3.transition)} group
- * @param {!d3.BrushSelection |
- *     function(this:Element, T, number, !Array<T>): !d3.BrushSelection |
- *     null}
- *     selection
- * @return {void}
- * @template T
- */
-d3.Brush_.move = function(group, selection) {};
-
-/**
- * @param {!Array<!Array<number>> |
- *     function(this:Element, T, number, !Array<T>): !Array<!Array<number>>=}
- *     extent
- * @template T
- */
-d3.Brush_.extent = function(extent) {};
-
-/**
- * @param {function(this:Element, T, number, !Array<T>): boolean=} filter
- * @template T
- */
-d3.Brush_.filter = function(filter) {};
-
-/**
- * @param {number=} size
- */
-d3.Brush_.handleSize = function(size) {};
-
-/**
- * @param {string} typenames
- * @param {?function(this:Element, T, number, !Array<T>): void=} listener
- * @template T
- */
-d3.Brush_.on = function(typenames, listener) {};
-
-/**
- * @param {!Element} node
- * @return {?d3.BrushSelection}
- */
-d3.brushSelection = function(node) {};
-
-/**
- * @typedef {!Array<number> | !Array<!Array<number>>}
- */
-d3.BrushSelection;
-
-// Brush Events
-
-/**
- * @record
- */
-d3.BrushEvent = function() {};
-
-/**
- * @type {!d3.Brush}
- */
-d3.BrushEvent.prototype.target;
-
-/**
- * @type {string}
- */
-d3.BrushEvent.prototype.type;
-
-/**
- * @type {!d3.BrushSelection}
- */
-d3.BrushEvent.prototype.selection;
-
-/**
- * @type {!Event}
- */
-d3.BrushEvent.prototype.sourceEvent;
-
-////////////////////////////////////////////////////////////////////////////////
-// Chords
-// https://github.com/d3/d3-chord
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @record
- */
-d3.ChordGroup = function() {};
-
-/**
- * @type {number}
- */
-d3.ChordGroup.prototype.startAngle;
-
-/**
- * @type {number}
- */
-d3.ChordGroup.prototype.endAngle;
-
-/**
- * @type {number}
- */
-d3.ChordGroup.prototype.value;
-
-/**
- * @type {number}
- */
-d3.ChordGroup.prototype.index;
-
-/**
- * @record
- * @extends {d3.ChordGroup}
- */
-d3.ChordSubgroup = function() {};
-
-/**
- * @type {number}
- */
-d3.ChordSubgroup.prototype.subindex;
-
-/**
- * @record
- * @extends {IArrayLike<{source: !d3.ChordSubgroup, target: !d3.ChordSubgroup}>}
- */
-d3.ChordList = function() {};
-
-/**
- * @type {!Array<!d3.ChordGroup>}
- */
-d3.ChordList.prototype.groups;
-
-/**
- * @return {!d3.Chord}
- */
-d3.chord = function() {};
-
-/**
- * @typedef {function(!Array<!Array<number>>): !d3.ChordList}
- */
-d3.Chord;
-
-/**
- * @private {!d3.Chord}
- */
-d3.Chord_;
-
-/**
- * @param {number=} angle
- */
-d3.Chord_.padAngle = function(angle) {};
-
-/**
- * @param {?function(number, number): number=} compare
- */
-d3.Chord_.sortGroups = function(compare) {};
-
-/**
- * @param {?function(number, number): number=} compare
- */
-d3.Chord_.sortSubgroups = function(compare) {};
-
-/**
- * @param {?function(number, number): number=} compare
- */
-d3.Chord_.sortChords = function(compare) {};
-
-/**
- * @return {!d3.Ribbon}
- */
-d3.ribbon = function() {};
-
-/**
- * @typedef {function(...?)}
- */
-d3.Ribbon;
-
-/**
- * @private {!d3.Ribbon}
- */
-d3.Ribbon_;
-
-/**
- * @param {!Function=} source
- */
-d3.Ribbon_.source = function(source) {};
-
-/**
- * @param {!Function=} target
- */
-d3.Ribbon_.target = function(target) {};
-
-/**
- * @param {number | function(...?): number=} radius
- */
-d3.Ribbon_.radius = function(radius) {};
-
-/**
- * @param {number | function(...?): number=} angle
- */
-d3.Ribbon_.startAngle = function(angle) {};
-
-/**
- * @param {number | function(...?): number=} angle
- */
-d3.Ribbon_.endAngle = function(angle) {};
-
-/**
- * @param {?CanvasPathMethods=} context
- */
-d3.Ribbon_.context = function(context) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Collections
-// https://github.com/d3/d3-collection
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-// Objects
-
-/**
- * @param {!Object<?, ?>} object
- * @return {!Array<string>}
- */
-d3.keys = function(object) {};
-
-/**
- * @param {!Object<?, V>} object
- * @return {!Array<V>}
- * @template V
- */
-d3.values = function(object) {};
-
-/**
- * @param {!Object<K, V>} object
- * @return {!Array<!Object<K, V>>}
- * @template K, V
- */
-d3.entries = function(object) {};
-
-// Maps
-
-/**
- * @param {!(d3.map<V> | Object<?, V> | Array<V>)=} object
- * @param {function(V, number): (string | number | boolean)=} keyFunction
- * @return {!d3.map<V>}
- * @constructor
- * @template V
- */
-d3.map = function(object, keyFunction) {};
-
-/**
- * @param {string | number | boolean} key
- * @return {boolean}
- */
-d3.map.prototype.has = function(key) {};
-
-/**
- * @param {string | number | boolean} key
- * @return {V | undefined}
- */
-d3.map.prototype.get = function(key) {};
-
-/**
- * @param {string | number | boolean} key
- * @param {V} value
- * @return {!d3.map<V>}
- */
-d3.map.prototype.set = function(key, value) {};
-
-/**
- * @param {string | number | boolean} key
- * @return {boolean}
- */
-d3.map.prototype.remove = function(key) {};
-
-/**
- * @return {void}
- */
-d3.map.prototype.clear = function() {};
-
-/**
- * @return {!Array<string>}
- */
-d3.map.prototype.keys = function() {};
-
-/**
- * @return {!Array<V>}
- */
-d3.map.prototype.values = function() {};
-
-/**
- * @return {!Array<{key: string, value: V}>}
- */
-d3.map.prototype.entries = function() {};
-
-/**
- * @param {function(string, V)} callback
- * @return {void}
- */
-d3.map.prototype.each = function(callback) {};
-
-/**
- * @return {boolean}
- */
-d3.map.prototype.empty = function() {};
-
-/**
- * @return {number}
- */
-d3.map.prototype.size = function() {};
-
-// Sets
-
-/**
- * @param {!(Array | d3.set)=} arrayOrSet
- * @param {function(?, number): (string | number | boolean)=} mapper
- * @return {!d3.set}
- * @constructor
- */
-d3.set = function(arrayOrSet, mapper) {};
-
-/**
- * @param {string | number | boolean} value
- * @return {boolean}
- */
-d3.set.prototype.has = function(value) {};
-
-/**
- * @param {string | number | boolean} value
- * @return {!d3.set}
- */
-d3.set.prototype.add = function(value) {};
-
-/**
- * @param {string | number | boolean} value
- * @return {boolean}
- */
-d3.set.prototype.remove = function(value) {};
-
-/**
- * @return {void}
- */
-d3.set.prototype.clear = function() {};
-
-/**
- * @return {!Array<string>}
- */
-d3.set.prototype.values = function() {};
-
-/**
- * @param {function(string)} callback
- * @return {void}
- */
-d3.set.prototype.each = function(callback) {};
-
-/**
- * @return {boolean}
- */
-d3.set.prototype.empty = function() {};
-
-/**
- * @return {number}
- */
-d3.set.prototype.size = function() {};
-
-// Nests
-
-/**
- * @return {!d3.Nest}
- */
-d3.nest = function() {};
-
-/**
- * @interface
- * @template T, R
- */
-d3.Nest = function() {};
-
-/**
- * @param {function(T): ?} keyFunction
- * @return {!d3.Nest}
- */
-d3.Nest.prototype.key = function(keyFunction) {};
-
-/**
- * @param {function(string, string): number} comparator
- * @return {!d3.Nest}
- */
-d3.Nest.prototype.sortKeys = function(comparator) {};
-
-/**
- * @param {function(T, T): number} comparator
- * @return {!d3.Nest}
- */
-d3.Nest.prototype.sortValues = function(comparator) {};
-
-/**
- * @param {function(!Array<T>): R} rollupFunction
- * @return {!d3.Nest}
- */
-d3.Nest.prototype.rollup = function(rollupFunction) {};
-
-/**
- * @param {!Array<T>} array
- * @return {!d3.map<!Array<T>> | !d3.map<R>}
- */
-d3.Nest.prototype.map = function(array) {};
-
-/**
- * @param {!Array<T>} array
- * @return {!Object<string, !Array<T>> | !Object<string, R>}
- */
-d3.Nest.prototype.object = function(array) {};
-
-/**
- * @param {!Array<T>} array
- * @return {!Array<{key: string, values: !Array<T>}> |
- *          !Array<{key: string, value: R}>}
- */
-d3.Nest.prototype.entries = function(array) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Colors
-// https://github.com/d3/d3-color
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @param {string} specifier
- * @return {?d3.color}
- * @constructor
- */
-d3.color = function(specifier) {};
-
-/**
- * @type {number}
- */
-d3.color.prototype.opacity;
-
-/**
- * @return {!d3.rgb}
- */
-d3.color.prototype.rgb = function() {};
-
-/**
- * @param {number=} k
- * @return {!d3.color}
- */
-d3.color.prototype.brighter = function(k) {};
-
-/**
- * @param {number=} k
- * @return {!d3.color}
- */
-d3.color.prototype.darker = function(k) {};
-
-/**
- * @return {boolean}
- */
-d3.color.prototype.displayable = function() {};
-
-/**
- * @override
- * @return {string}
- */
-d3.color.prototype.toString = function() {};
-
-/**
- * @param {number | string | !d3.color} redOrSpecifierOrColor
- * @param {number=} green
- * @param {number=} blue
- * @param {number=} opacity
- * @return {!d3.rgb}
- * @constructor
- * @extends {d3.color}
- */
-d3.rgb = function(redOrSpecifierOrColor, green, blue, opacity) {};
-
-/**
- * @type {number}
- */
-d3.rgb.prototype.r;
-
-/**
- * @type {number}
- */
-d3.rgb.prototype.g;
-
-/**
- * @type {number}
- */
-d3.rgb.prototype.b;
-
-/**
- * @param {number | string | !d3.color} hueOrSpecifierOrColor
- * @param {number=} saturation
- * @param {number=} lightness
- * @param {number=} opacity
- * @return {!d3.hsl}
- * @constructor
- * @extends {d3.color}
- */
-d3.hsl = function(hueOrSpecifierOrColor, saturation, lightness,
-    opacity) {};
-
-/**
- * @type {number}
- */
-d3.hsl.prototype.h;
-
-/**
- * @type {number}
- */
-d3.hsl.prototype.s;
-
-/**
- * @type {number}
- */
-d3.hsl.prototype.l;
-
-/**
- * @param {number | string | !d3.color} lightnessOrSpecifierOrColor
- * @param {number=} a
- * @param {number=} b
- * @param {number=} opacity
- * @return {!d3.lab}
- * @constructor
- * @extends {d3.color}
- */
-d3.lab = function(lightnessOrSpecifierOrColor, a, b, opacity) {};
-
-/**
- * @type {number}
- */
-d3.lab.prototype.l;
-
-/**
- * @type {number}
- */
-d3.lab.prototype.a;
-
-/**
- * @type {number}
- */
-d3.lab.prototype.b;
-
-/**
- * @param {number} l
- * @param {number=} opacity
- * @return {!d3.lab}
- */
-d3.gray = function(l, opacity) {};
-
-/**
- * @param {number | string | !d3.color} hueOrSpecifierOrColor
- * @param {number=} chroma
- * @param {number=} luminance
- * @param {number=} opacity
- * @return {!d3.hcl}
- * @constructor
- * @extends {d3.color}
- */
-d3.hcl = function(hueOrSpecifierOrColor, chroma, luminance, opacity) {};
-
-/**
- * @type {number}
- */
-d3.hcl.prototype.h;
-
-/**
- * @type {number}
- */
-d3.hcl.prototype.c;
-
-/**
- * @type {number}
- */
-d3.hcl.prototype.l;
-
-/**
- * @param {number | string | !d3.color} luminanceOrSpecifierOrColor
- * @param {number=} chroma
- * @param {number=} hue
- * @param {number=} opacity
- * @return {!d3.hcl}
- */
-d3.lch = function(luminanceOrSpecifierOrColor, chroma, hue, opacity) {};
-
-/**
- * @param {number | string | !d3.color} hueOrSpecifierOrColor
- * @param {number=} saturation
- * @param {number=} lightness
- * @param {number=} opacity
- * @return {!d3.cubehelix}
- * @constructor
- * @extends {d3.color}
- */
-d3.cubehelix = function(hueOrSpecifierOrColor, saturation, lightness,
-    opacity) {};
-
-/**
- * @type {number}
- */
-d3.cubehelix.prototype.h;
-
-/**
- * @type {number}
- */
-d3.cubehelix.prototype.s;
-
-/**
- * @type {number}
- */
-d3.cubehelix.prototype.l;
-
-////////////////////////////////////////////////////////////////////////////////
-// Contours
-// https://github.com/d3/d3-contour
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- * @record
- * @extends {GeoJSON.MultiPolygon}
- */
-d3.ContourMultiPolygon = function() {};
-
-/**
- * @type {number}
- */
-d3.ContourMultiPolygon.prototype.value;
-
-// API reference
-
-/**
- * @return {!d3.Contours}
- */
-d3.contours = function() {};
-
-/**
- * @typedef {function(!Array<number>): !Array<!d3.ContourMultiPolygon>}
- */
-d3.Contours;
-
-/**
- * @private {!d3.Contours}
- */
-d3.Contours_;
-
-/**
- * @param {!Array<number>} values
- * @param {number} threshold
- * @return {!d3.ContourMultiPolygon}
- */
-d3.Contours_.contour = function(values, threshold) {};
-
-/**
- * @param {!Array<number>=} size
- * @return {?}
- */
-d3.Contours_.size = function(size) {};
-
-/**
- * @param {boolean=} smooth
- * @return {?}
- */
-d3.Contours_.smooth = function(smooth) {};
-
-/**
- * @param {!(number | Array<number> | Function)=} thresholds
- * @return {?}
- */
-d3.Contours_.thresholds = function(thresholds) {};
-
-/**
- * @return {!d3.ContourDensity}
- */
-d3.contourDensity = function() {};
-
-/**
- * @typedef {function(!Array): !Array<!d3.ContourMultiPolygon>}
- */
-d3.ContourDensity;
-
-/**
- * @private {!d3.ContourDensity}
- */
-d3.ContourDensity_;
-
-/**
- * @param {number | function(T, number, !Array<T>): number=} x
- * @return {?}
- * @template T
- */
-d3.ContourDensity_.x = function(x) {};
-
-/**
- * @param {number | function(T, number, !Array<T>): number=} y
- * @return {?}
- * @template T
- */
-d3.ContourDensity_.y = function(y) {};
-
-/**
- * @param {number | function(T, number, !Array<T>): number=} weight
- * @return {?}
- * @template T
- */
-d3.ContourDensity_.weight = function(weight) {};
-
-/**
- * @param {!Array<number>=} size
- * @return {?}
- */
-d3.ContourDensity_.size = function(size) {};
-
-/**
- * @param {number=} cellSize
- * @return {?}
- */
-d3.ContourDensity_.cellSize = function(cellSize) {};
-
-/**
- * @param {!(number | Array<number> | Function)=} thresholds
- * @return {?}
- */
-d3.ContourDensity_.thresholds = function(thresholds) {};
-
-/**
- * @param {number=} bandwidth
- * @return {?}
- */
-d3.ContourDensity_.bandwidth = function(bandwidth) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Dispatches
-// https://github.com/d3/d3-dispatch
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @param {...string} var_args
- * @return {!d3.dispatch}
- * @constructor
- */
-d3.dispatch = function(var_args) {};
-
-/**
- * @param {string} typenames
- * @param {?Function=} listener
- */
-d3.dispatch.prototype.on = function(typenames, listener) {};
-
-/**
- * @return {!d3.dispatch}
- */
-d3.dispatch.prototype.copy = function() {};
-
-/**
- * @param {string} type
- * @param {?Object=} that
- * @param {...?} var_args
- * @return {void}
- */
-d3.dispatch.prototype.call = function(type, that, var_args) {};
-
-/**
- * @param {string} type
- * @param {?Object=} that
- * @param {!(Arguments | Array<?>)=} args
- * @return {void}
- */
-d3.dispatch.prototype.apply = function(type, that, args) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Dragging
-// https://github.com/d3/d3-drag
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @return {!d3.Drag}
- */
-d3.drag = function() {};
-
-/**
- * @typedef {function(!d3.selection)}
- */
-d3.Drag;
-
-/**
- * @private {!d3.Drag}
- */
-d3.Drag_;
-
-/**
- * @param {!Element | function(this:Element, T, !Array<T>): !Element=}
- *     container
- * @template T
- */
-d3.Drag_.container = function(container) {};
-
-/**
- * @param {function(this:Element, T, !Array<T>): boolean=} filter
- * @template T
- */
-d3.Drag_.filter = function(filter) {};
-
-/**
- * @param {function(this:Element): boolean=} touchable
- * @return {!Function}
- */
-d3.Drag_.touchable = function(touchable) {};
-
-/**
- * @param {function(this:Element, T, !Array<T>)=} subject
- * @template T
- */
-d3.Drag_.subject = function(subject) {};
-
-/**
- * @param {number=} distance
- * @return {?} Distance (0 arguments) or this (1 argument).
- */
-d3.Drag_.clickDistance = function(distance) {};
-
-/**
- * @param {?function(this:Element, T, number, !Array<T>): void=}
- *     listener
- * @template T
- */
-d3.Drag_.on = function(typenames, listener) {};
-
-/**
- * @param {!Window} window
- * @return {void}
- */
-d3.dragDisable = function(window) {};
-
-/**
- * @param {!Window} window
- * @param {boolean=} noclick
- * @return {void}
- */
-d3.dragEnable = function(window, noclick) {};
-
-// Drag Events
-
-/**
- * @interface
- */
-d3.DragEvent = function() {};
-
-/**
- * @type {!d3.Drag}
- */
-d3.DragEvent.prototype.target;
-
-/**
- * @type {string}
- */
-d3.DragEvent.prototype.type;
-
-/**
- * @type {?}
- */
-d3.DragEvent.prototype.subject;
-
-/**
- * @type {number}
- */
-d3.DragEvent.prototype.x;
-
-/**
- * @type {number}
- */
-d3.DragEvent.prototype.y;
-
-/**
- * @type {number}
- */
-d3.DragEvent.prototype.dx;
-
-/**
- * @type {number}
- */
-d3.DragEvent.prototype.dy;
-
-/**
- * @type {number | string}
- */
-d3.DragEvent.prototype.identifier;
-
-/**
- * @type {number}
- */
-d3.DragEvent.prototype.active;
-
-/**
- * @type {!Event}
- */
-d3.DragEvent.prototype.sourceEvent;
-
-/**
- * @param {string} typenames
- * @param {?function(this:Element, ?, number, !IArrayLike<!Element>)=}
- *     listener
- */
-d3.DragEvent.prototype.on = function(typenames, listener) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Delimiter-Separated Values
-// https://github.com/d3/d3-dsv
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- * @constructor
- * @extends {Array}
- */
-d3.DsvParseResult = function() {};
-
-/**
- * @type {!Array<string>}
- */
-d3.DsvParseResult.prototype.columns;
-
-/**
- * @typedef {function(
- *             !Object<string, (string | undefined)>,
- *             number,
- *             !Array<string>
- *           ): ?}
- */
-d3.DsvRowConverter;
-
-// API Reference
-
-/**
- * @param {string} string
- * @param {!d3.DsvRowConverter=} rowConverter
- * @return {!d3.DsvParseResult}
- */
-d3.csvParse = function(string, rowConverter) {};
-
-/**
- * @param {string} string
- * @param {function(!Array<string>, number)=} rowMapper
- * @return {!Array}
- */
-d3.csvParseRows = function(string, rowMapper) {};
-
-/**
- * @param {!Array<!Object>} rows
- * @param {!Array<string>=} columnsToInclude
- * @return {string}
- */
-d3.csvFormat = function(rows, columnsToInclude) {};
-
-/**
- * @param {!Array<!Array>} rows
- * @return {string}
- */
-d3.csvFormatRows = function(rows) {};
-
-/**
- * @param {string} string
- * @param {!d3.DsvRowConverter=} rowConverter
- * @return {!d3.DsvParseResult}
- */
-d3.tsvParse = function(string, rowConverter) {};
-
-/**
- * @param {string} string
- * @param {function(!Array<string>, number)=} rowMapper
- * @return {!Array}
- */
-d3.tsvParseRows = function(string, rowMapper) {};
-
-/**
- * @param {!Array<!Object>} rows
- * @param {!Array<string>=} columnsToInclude
- * @return {string}
- */
-d3.tsvFormat = function(rows, columnsToInclude) {};
-
-/**
- * @param {!Array<!Array>} rows
- * @return {string}
- */
-d3.tsvFormatRows = function(rows) {};
-
-/**
- * @param {string} delimiter
- * @return {!d3.Dsv}
- */
-d3.dsvFormat = function(delimiter) {};
-
-/**
- * @interface
- */
-d3.Dsv = function() {};
-
-/**
- * @param {string} string
- * @param {!d3.DsvRowConverter=} rowConverter
- * @return {!d3.DsvParseResult}
- */
-d3.Dsv.prototype.parse = function(string, rowConverter) {};
-
-/**
- * @param {string} string
- * @param {function(!Array<string>, number)=} rowMapper
- * @return {!Array}
- */
-d3.Dsv.prototype.parseRows = function(string, rowMapper) {};
-
-/**
- * @param {!Array<!Object>} rows
- * @param {!Array<string>=} columns
- * @return {string}
- */
-d3.Dsv.prototype.format = function(rows, columns) {};
-
-/**
- * @param {!Array<!Array>} rows
- * @return {string}
- */
-d3.Dsv.prototype.formatRows = function(rows) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Easings
-// https://github.com/d3/d3-ease
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeLinear = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easePolyIn = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easePolyOut = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easePoly = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easePolyInOut = function(t) {};
-
-/**
- * This declaration is not completely correct. It disallows the call pattern
- * d3.easePolyIn.exponent(e1).exponent(e2) which is technially valid, but not
- * very useful in practice. The alternative would be a typedef like
- * d3.ElasticEasing, but it would degrade type checking, because JSCompiler
- * doesn't understand function properties.
- *
- * @param {number} e
- * @return {function(number): number}
- */
-d3.easePolyIn.exponent = function(e) {};
-
-/**
- * @param {number} e
- * @return {function(number): number}
- */
-d3.easePolyOut.exponent = function(e) {};
-
-/**
- * @param {number} e
- * @return {function(number): number}
- */
-d3.easePoly.exponent = function(e) {};
-
-/**
- * @param {number} e
- * @return {function(number): number}
- */
-d3.easePolyInOut.exponent = function(e) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeQuadIn = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeQuadOut = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeQuad = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeQuadInOut = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeCubicIn = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeCubicOut = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeCubic = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeCubicInOut = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeSinIn = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeSinOut = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeSin = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeSinInOut = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeExpIn = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeExpOut = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeExp = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeExpInOut = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeCircleIn = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeCircleOut = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeCircle = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeCircleInOut = function(t) {};
-
-/**
- * @type {!d3.ElasticEasing}
- */
-d3.easeElasticIn;
-
-/**
- * @type {!d3.ElasticEasing}
- */
-d3.easeElastic;
-
-/**
- * @type {!d3.ElasticEasing}
- */
-d3.easeElasticOut;
-
-/**
- * @type {!d3.ElasticEasing}
- */
-d3.easeElasticInOut;
-
-/**
- * @typedef {function(number): number}
- */
-d3.ElasticEasing;
-
-/**
- * @private {!d3.ElasticEasing}
- */
-d3.ElasticEasing_;
-
-/**
- * @param {number} a
- * @return {!d3.ElasticEasing}
- */
-d3.ElasticEasing_.amplitude = function(a) {};
-
-/**
- * @param {number} p
- * @return {!d3.ElasticEasing}
- */
-d3.ElasticEasing_.period = function(p) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeBackIn = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeBackOut = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeBack = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeBackInOut = function(t) {};
-
-/**
- * @param {number} s
- * @return {function(number): number}
- */
-d3.easeBackIn.overshoot = function(s) {};
-
-/**
- * @param {number} s
- * @return {function(number): number}
- */
-d3.easeBackOut.overshoot = function(s) {};
-
-/**
- * @param {number} s
- * @return {function(number): number}
- */
-d3.easeBack.overshoot = function(s) {};
-
-/**
- * @param {number} s
- * @return {function(number): number}
- */
-d3.easeBackInOut.overshoot = function(s) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeBounceIn = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeBounceOut = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeBounce = function(t) {};
-
-/**
- * @param {number} t
- * @return {number}
- */
-d3.easeBounceInOut = function(t) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Fetch
-// https://github.com/d3/d3-fetch
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- * @param {string} url
- * @param {!RequestInit=} init
- * @return {!Promise<!Blob>}
- */
-d3.blob = function(url, init) {};
-
-/**
- * @param {string} url
- * @param {!RequestInit=} init
- * @return {!Promise<!ArrayBuffer>}
- */
-d3.buffer = function(url, init) {};
-
-/**
- * @param {string} url
- * @param {?(RequestInit | d3.DsvRowConverter)=} initOrRowConverter
- * @param {?d3.DsvRowConverter=} rowConverter
- * @return {!Promise<!d3.DsvParseResult>}
- */
-d3.csv = function(url, initOrRowConverter, rowConverter) {};
-
-/**
- * @param {string} delimiter
- * @param {string} url
- * @param {?(RequestInit | d3.DsvRowConverter)=} initOrRowConverter
- * @param {?d3.DsvRowConverter=} rowConverter
- * @return {!Promise<!d3.DsvParseResult>}
- */
-d3.dsv = function(delimiter, url, initOrRowConverter, rowConverter) {};
-
-/**
- * @param {string} url
- * @param {?RequestInit=} init
- * @return {!Promise<!Document>}
- */
-d3.html = function(url, init) {};
-
-/**
- * @param {string} url
- * @param {?Object=} init
- * @return {!Promise<!HTMLImageElement>}
- */
-d3.image = function(url, init) {};
-
-/**
- * @param {string} url
- * @param {?RequestInit=} init
- * @return {!Promise<R>}
- * @template R
- */
-d3.json = function(url, init) {};
-
-/**
- * @param {string} url
- * @param {?RequestInit=} init
- * @return {!Promise<!Document>}
- */
-d3.svg = function(url, init) {};
-
-/**
- * @param {string} url
- * @param {?RequestInit=} init
- * @return {!Promise<string>}
- */
-d3.text = function(url, init) {};
-
-/**
- * @param {string} url
- * @param {?(RequestInit | d3.DsvRowConverter)=} initOrRowConverter
- * @param {?d3.DsvRowConverter=} rowConverter
- * @return {!Promise<!d3.DsvParseResult>}
- */
-d3.tsv = function(url, initOrRowConverter, rowConverter) {};
-
-/**
- * @param {string} url
- * @param {?RequestInit=} init
- * @return {!Promise<!Document>}
- */
-d3.xml = function(url, init) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Forces
-// https://github.com/d3/d3-force
-////////////////////////////////////////////////////////////////////////////////
-
-// Simulation
-
-/**
- * @param {!Array<!d3.ForceNode>=} nodes
- * @return {!d3.ForceSimulation}
- */
-d3.forceSimulation = function(nodes) {};
-
-/**
- * @interface
- */
-d3.ForceSimulation = function() {};
-
-/**
- * @return {!d3.ForceSimulation}
- */
-d3.ForceSimulation.prototype.restart = function() {};
-
-/**
- * @return {!d3.ForceSimulation}
- */
-d3.ForceSimulation.prototype.stop = function() {};
-
-/**
- * @return {void}
- */
-d3.ForceSimulation.prototype.tick = function() {};
-
-/**
- * @param {!Array<!d3.ForceNode>=} nodes
- */
-d3.ForceSimulation.prototype.nodes = function(nodes) {};
-
-/**
- * @param {number=} alpha
- */
-d3.ForceSimulation.prototype.alpha = function(alpha) {};
-
-/**
- * @param {number=} min
- */
-d3.ForceSimulation.prototype.alphaMin = function(min) {};
-
-/**
- * @param {number=} decay
- */
-d3.ForceSimulation.prototype.alphaDecay = function(decay) {};
-
-/**
- * @param {number=} target
- */
-d3.ForceSimulation.prototype.alphaTarget = function(target) {};
-
-/**
- * @param {number=} decay
- */
-d3.ForceSimulation.prototype.velocityDecay = function(decay) {};
-
-/**
- * @param {string} name
- * @param {!d3.Force=} force
- */
-d3.ForceSimulation.prototype.force = function(name, force) {};
-
-/**
- * @param {number} x
- * @param {number} y
- * @param {number=} radius
- * @return {!d3.ForceNode | undefined}
- */
-d3.ForceSimulation.prototype.find = function(x, y, radius) {};
-
-/**
- * @param {string} typenames
- * @param {?function(this:d3.ForceSimulation): void=} listener
- */
-d3.ForceSimulation.prototype.on = function(typenames, listener) {};
-
-/**
- * @record
- */
-d3.ForceNode = function() {};
-
-/**
- * @type {number | undefined}
- */
-d3.ForceNode.prototype.index;
-
-/**
- * @type {number | undefined}
- */
-d3.ForceNode.prototype.x;
-
-/**
- * @type {number | undefined}
- */
-d3.ForceNode.prototype.y;
-
-/**
- * @type {number | undefined}
- */
-d3.ForceNode.prototype.vx;
-
-/**
- * @type {number | undefined}
- */
-d3.ForceNode.prototype.vy;
-
-/**
- * @type {?number | undefined}
- */
-d3.ForceNode.prototype.fx;
-
-/**
- * @type {?number | undefined}
- */
-d3.ForceNode.prototype.fy;
-
-// Forces
-
-/**
- * @typedef {function(number): void}
- */
-d3.Force;
-
-/**
- * @type {!d3.Force}
- */
-d3.Force_;
-
-/**
- * @param {!Array<!d3.ForceNode>} nodes
- * @return {void}
- */
-d3.Force_.initialize = function(nodes) {};
-
-// Centering
-
-/**
- * @param {number=} x
- * @param {number=} y
- * @return {!d3.CenterForce}
- */
-d3.forceCenter = function(x, y) {};
-
-/**
- * @typedef {function(number): void}
- */
-d3.CenterForce;
-
-/**
- * @private {!d3.CenterForce}
- */
-d3.CenterForce_;
-
-/**
- * @param {!Array<!d3.ForceNode>} nodes
- * @return {void}
- */
-d3.CenterForce_.initialize = function(nodes) {};
-
-/**
- * @param {number=} x
- */
-d3.CenterForce_.x = function(x) {};
-
-/**
- * @param {number=} y
- */
-d3.CenterForce_.y = function(y) {};
-
-// Collision
-
-/**
- * @param {number=} radius
- * @return {!d3.CollideForce}
- */
-d3.forceCollide = function(radius) {};
-
-/**
- * @typedef {function(number): void}
- */
-d3.CollideForce;
-
-/**
- * @private {!d3.CollideForce}
- */
-d3.CollideForce_;
-
-/**
- * @param {!Array<!d3.ForceNode>} nodes
- * @return {void}
- */
-d3.CollideForce_.initialize = function(nodes) {};
-
-/**
- * @param {number |
- *     function(!d3.ForceNode, number, !Array<!d3.ForceNode>): number=}
- *     radius
- * @return {!Function} Radius accessor or this.
- */
-d3.CollideForce_.radius = function(radius) {};
-
-/**
- * @param {number=} strength
- */
-d3.CollideForce_.strength = function(strength) {};
-
-/**
- * @param {number=} iterations
- */
-d3.CollideForce_.iterations = function(iterations) {};
-
-// Links
-
-/**
- * @record
- */
-d3.ForceLink = function() {};
-
-/**
- * @type {!d3.ForceNode | string | number}
- */
-d3.ForceLink.prototype.source;
-
-/**
- * @type {!d3.ForceNode | string | number}
- */
-d3.ForceLink.prototype.target;
-
-/**
- * @type {number | undefined}
- */
-d3.ForceLink.prototype.index;
-
-/**
- * @param {!Array<!d3.ForceLink>=} links
- * @return {!d3.LinkForce}
- */
-d3.forceLink = function(links) {};
-
-/**
- * @typedef {function(number): void}
- */
-d3.LinkForce;
-
-/**
- * @private {!d3.LinkForce}
- */
-d3.LinkForce_;
-
-/**
- * @param {!Array<!d3.ForceNode>} nodes
- * @return {void}
- */
-d3.LinkForce_.initialize = function(nodes) {};
-
-/**
- * @param {!Array<!d3.ForceLink>=} links
- */
-d3.LinkForce_.links = function(links) {};
-
-/**
- * @param {function(!d3.ForceNode, number, !Array<!d3.ForceNode>): string=}
- *     id
- * @return {!Function} ID accessor or this.
- */
-d3.LinkForce_.id = function(id) {};
-
-/**
- * @param {number |
- *     function(!d3.ForceLink, number, !Array<!d3.ForceLink>): number=}
- *     distance
- * @return {!Function} Distance accessor or this.
- */
-d3.LinkForce_.distance = function(distance) {};
-
-/**
- * @param {number |
- *     function(!d3.ForceLink, number, !Array<!d3.ForceLink>): number=}
- *     strength
- * @return {!Function} Strength accessor or this.
- */
-d3.LinkForce_.strength = function(strength) {};
-
-/**
- * @param {number=} iterations
- */
-d3.LinkForce_.iterations = function(iterations) {};
-
-// Many-Body
-
-/**
- * @return {!d3.ManyBodyForce}
- */
-d3.forceManyBody = function() {};
-
-/**
- * @typedef {function(number): void}
- */
-d3.ManyBodyForce;
-
-/**
- * @private {!d3.ManyBodyForce}
- */
-d3.ManyBodyForce_;
-
-/**
- * @param {!Array<!d3.ForceNode>} nodes
- * @return {void}
- */
-d3.ManyBodyForce_.initialize = function(nodes) {};
-
-/**
- * @param {number |
- *     function(!d3.ForceNode, number, !Array<!d3.ForceNode>): number=}
- *     strength
- * @return {!Function} Strength accessor or this.
- */
-d3.ManyBodyForce_.strength = function(strength) {};
-
-/**
- * @param {number=} theta
- */
-d3.ManyBodyForce_.theta = function(theta) {};
-
-/**
- * @param {number=} distance
- */
-d3.ManyBodyForce_.distanceMin = function(distance) {};
-
-/**
- * @param {number=} distance
- */
-d3.ManyBodyForce_.distanceMax = function(distance) {};
-
-// Positioning
-
-/**
- * @return {!d3.XForce}
- */
-d3.forceX = function() {};
-
-/**
- * @typedef {function(number): void}
- */
-d3.XForce;
-
-/**
- * @private {!d3.XForce}
- */
-d3.XForce_;
-
-/**
- * @param {!Array<!d3.ForceNode>} nodes
- * @return {void}
- */
-d3.XForce_.initialize = function(nodes) {};
-
-/**
- * @param {number |
- *     function(!d3.ForceNode, number, !Array<!d3.ForceNode>): number=}
- *     strength
- * @return {!Function} Strength accessor or this.
- */
-d3.XForce_.strength = function(strength) {};
-
-/**
- * @param {number |
- *     function(!d3.ForceNode, number, !Array<!d3.ForceNode>): number=} x
- * @return {!Function} x accessor or this.
- */
-d3.XForce_.x = function(x) {};
-
-/**
- * @return {!d3.YForce}
- */
-d3.forceY = function() {};
-
-/**
- * @typedef {function(number): void}
- */
-d3.YForce;
-
-/**
- * @private {!d3.YForce}
- */
-d3.YForce_;
-
-/**
- * @param {!Array<!d3.ForceNode>} nodes
- * @return {void}
- */
-d3.YForce_.initialize = function(nodes) {};
-
-/**
- * @param {number |
- *     function(!d3.ForceNode, number, !Array<!d3.ForceNode>): number=}
- *     strength
- * @return {!Function} Strength accessor or this.
- */
-d3.YForce_.strength = function(strength) {};
-
-/**
- * @param {number |
- *     function(!d3.ForceNode, number, !Array<!d3.ForceNode>): number=} y
- * @return {!Function} y accessor or this.
- */
-d3.YForce_.y = function(y) {};
-
-/**
- * @param {number} radius
- * @param {number=} x
- * @param {number=} y
- * @return {!d3.RadialForce}
- */
-d3.forceRadial = function(radius, x, y) {};
-
-/**
- * @typedef {function(number): void}
- */
-d3.RadialForce;
-
-/**
- * @private {!d3.RadialForce}
- */
-d3.RadialForce_;
-
-/**
- * @param {!Array<!d3.ForceNode>} nodes
- * @return {void}
- */
-d3.RadialForce_.initialize = function(nodes) {};
-
-/**
- * @param {number |
- *     function(!d3.ForceNode, number, !Array<!d3.ForceNode>): number=}
- *     strength
- * @return {?} Strength accessor function or this.
- */
-d3.RadialForce_.strength = function(strength) {};
-
-/**
- * @param {number |
- *     function(!d3.ForceNode, number, !Array<!d3.ForceNode>): number=}
- *     radius
- * @return {?} Radius accessor function or this.
- */
-d3.RadialForce_.radius = function(radius) {};
-
-/**
- * @param {number=} x
- */
-d3.RadialForce_.x = function(x) {};
-
-/**
- * @param {number=} y
- */
-d3.RadialForce_.y = function(y) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Number Formats
-// https://github.com/d3/d3-format
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @param {string} specifier
- * @return {function(number): string}
- */
-d3.format = function(specifier) {};
-
-/**
- * @param {string} specifier
- * @param {number} value
- * @return {function(number): string}
- */
-d3.formatPrefix = function(specifier, value) {};
-
-/**
- * @param {string} specifier
- * @return {!d3.formatSpecifier}
- * @constructor
- */
-d3.formatSpecifier = function(specifier) {};
-
-/**
- * @type {string}
- */
-d3.formatSpecifier.prototype.fill;
-
-/**
- * @type {string}
- */
-d3.formatSpecifier.prototype.align;
-
-/**
- * @type {string}
- */
-d3.formatSpecifier.prototype.sign;
-
-/**
- * @type {string}
- */
-d3.formatSpecifier.prototype.symbol;
-
-/**
- * @type {boolean}
- */
-d3.formatSpecifier.prototype.zero;
-
-/**
- * @type {number | undefined}
- */
-d3.formatSpecifier.prototype.width;
-
-/**
- * @type {boolean}
- */
-d3.formatSpecifier.prototype.comma;
-
-/**
- * @type {number | undefined}
- */
-d3.formatSpecifier.prototype.precision;
-
-/**
- * @type {string}
- */
-d3.formatSpecifier.prototype.type;
-
-/**
- * @param {number} step
- * @return {number}
- */
-d3.precisionFixed = function(step) {};
-
-/**
- * @param {number} step
- * @param {number} value
- * @return {number}
- */
-d3.precisionPrefix = function(step, value) {};
-
-/**
- * @param {number} step
- * @param {number} max
- * @return {number}
- */
-d3.precisionRound = function(step, max) {};
-
-// Locales
-
-/**
- * @record
- */
-d3.FormatLocaleDefinition = function() {};
-
-/**
- * @type {string}
- */
-d3.FormatLocaleDefinition.prototype.decimal;
-
-/**
- * @type {string}
- */
-d3.FormatLocaleDefinition.prototype.thousands;
-
-/**
- * @type {!Array<number>}
- */
-d3.FormatLocaleDefinition.prototype.grouping;
-
-/**
- * @type {!Array<string>}
- */
-d3.FormatLocaleDefinition.prototype.currency;
-
-/**
- * @type {!Array<string> | undefined}
- */
-d3.FormatLocaleDefinition.prototype.numerals;
-
-/**
- * @type {string | undefined}
- */
-d3.FormatLocaleDefinition.prototype.percent;
-
-/**
- * @interface
- */
-d3.FormatLocale = function() {};
-
-/**
- * @param {string} specifier
- * @return {function(number): string}
- */
-d3.FormatLocale.prototype.format = function(specifier) {};
-
-/**
- * @param {string} specifier
- * @param {number} value
- * @return {function(number): string}
- */
-d3.FormatLocale.prototype.formatPrefix = function(specifier, value) {};
-
-/**
- * @param {!d3.FormatLocaleDefinition} definition
- * @return {!d3.FormatLocale}
- */
-d3.formatLocale = function(definition) {};
-
-/**
- * @param {!d3.FormatLocaleDefinition} definition
- * @return {!d3.FormatLocale}
- */
-d3.formatDefaultLocale = function(definition) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Geographies
-// https://github.com/d3/d3-geo
-////////////////////////////////////////////////////////////////////////////////
-
-// GeoJSON (http://geojson.org/geojson-spec.html)
-
-/** @record */
-var GeoJSON = function() {};
-
-/** @type {string} */
-GeoJSON.prototype.type;
-
-/** @type {?GeoJSON.NamedCRS | GeoJSON.LinkedCRS | undefined} */
-GeoJSON.prototype.crs;
-
-/** @type {?Array<number> | undefined} */
-GeoJSON.prototype.bbox;
-
-
-/** @record */
-GeoJSON.NamedCRS = function() {};
-
-/** @type {string} */
-GeoJSON.NamedCRS.prototype.type;
-
-/** @type {{name: string}} */
-GeoJSON.NamedCRS.prototype.properties;
-
-
-/** @record */
-GeoJSON.LinkedCRS = function() {};
-
-/** @type {string} */
-GeoJSON.LinkedCRS.prototype.type;
-
-/** @type {{href: string, type: (string | undefined)}} */
-GeoJSON.LinkedCRS.prototype.properties;
-
-
-/** @record @extends {GeoJSON} */
-GeoJSON.Geometry = function() {};
-
-
-/** @record @extends {GeoJSON.Geometry} */
-GeoJSON.Point = function() {};
-
-/** @type {!Array<number>} */
-GeoJSON.Point.prototype.coordinates;
-
-
-/** @record @extends {GeoJSON.Geometry} */
-GeoJSON.LineString = function() {};
-
-/** @type {!Array<!Array<number>>} */
-GeoJSON.LineString.prototype.coordinates;
-
-
-/** @record @extends {GeoJSON.Geometry} */
-GeoJSON.Polygon = function() {};
-
-/** @type {!Array<!Array<!Array<number>>>} */
-GeoJSON.Polygon.prototype.coordinates;
-
-
-/** @record @extends {GeoJSON.Geometry} */
-GeoJSON.MultiPoint = function() {};
-
-/** @type {!Array<!Array<number>>} */
-GeoJSON.MultiPoint.prototype.coordinates;
-
-
-/** @record @extends {GeoJSON.Geometry} */
-GeoJSON.MultiLineString = function() {};
-
-/** @type {!Array<!Array<!Array<number>>>} */
-GeoJSON.MultiLineString.prototype.coordinates;
-
-
-/** @record @extends {GeoJSON.Geometry} */
-GeoJSON.MultiPolygon = function() {};
-
-/** @type {!Array<!Array<!Array<!Array<number>>>>} */
-GeoJSON.MultiPolygon.prototype.coordinates;
-
-
-/** @record @extends {GeoJSON.Geometry} */
-GeoJSON.GeometryCollection = function() {};
-
-/** @type {!Array<!GeoJSON.Geometry>} */
-GeoJSON.GeometryCollection.prototype.geometries;
-
-
-/** @record @extends {GeoJSON} */
-GeoJSON.Feature = function() {};
-
-/** @type {?GeoJSON.Geometry} */
-GeoJSON.Feature.prototype.geometry;
-
-/** @type {?Object} */
-GeoJSON.Feature.prototype.properties;
-
-
-/** @record @extends {GeoJSON} */
-GeoJSON.FeatureCollection = function() {};
-
-/** @type {!Array<!GeoJSON.Feature>} */
-GeoJSON.FeatureCollection.prototype.features;
-
-// Spherical Math
-
-/**
- * [longitude in degrees, latitude in degrees]
- * @typedef {!Array<number>}
- */
-d3.LngLat;
-
-/**
- * @param {!GeoJSON.Feature} feature
- * @return {number}
- */
-d3.geoArea = function(feature) {};
-
-/**
- * @param {!GeoJSON.Feature} feature
- * @return {!Array<!d3.LngLat>}
- */
-d3.geoBounds = function(feature) {};
-
-/**
- * @param {!GeoJSON.Feature} feature
- * @return {!d3.LngLat}
- */
-d3.geoCentroid = function(feature) {};
-
-/**
- * @param {!d3.LngLat} a
- * @param {!d3.LngLat} b
- * @return {number}
- */
-d3.geoDistance = function(a, b) {};
-
-/**
- * @param {!GeoJSON.Feature} feature
- * @return {number}
- */
-d3.geoLength = function(feature) {};
-
-/**
- * @param {!d3.LngLat} a
- * @param {!d3.LngLat} b
- * @return {function(number): !d3.LngLat}
- */
-d3.geoInterpolate = function(a, b) {};
-
-/**
- * @param {!GeoJSON} object
- * @param {!d3.LngLat} point
- * @return {boolean}
- */
-d3.geoContains = function(object, point) {};
-
-/**
- * @param {!Array<number>} angles [yaw, pitch] or [yaw, pitch, roll]
- * @return {!d3.GeoRotation}
- */
-d3.geoRotation = function(angles) {};
-
-/**
- * @typedef {function(!d3.LngLat): !d3.LngLat}
- */
-d3.GeoRotation;
-
-/**
- * @private {!d3.GeoRotation}
- */
-d3.GeoRotation_;
-
-/**
- * @param {!d3.LngLat} point
- * @return {!d3.LngLat}
- */
-d3.GeoRotation_.invert = function(point) {};
-
-// Spherical Shapes
-
-/**
- * @return {!d3.GeoCircle}
- */
-d3.geoCircle = function() {};
-
-/**
- * @typedef {function(...?): !GeoJSON.Polygon}
- */
-d3.GeoCircle;
-
-/**
- * @private {!d3.GeoCircle}
- */
-d3.GeoCircle_;
-
-/**
- * @param {!d3.LngLat | function(): !d3.LngLat=} center
- */
-d3.GeoCircle_.center = function(center) {};
-
-/**
- * @param {number | function(): number=} radius
- */
-d3.GeoCircle_.radius = function(radius) {};
-
-/**
- * @param {number | function(): number=} angle
- */
-d3.GeoCircle_.precision = function(angle) {};
-
-/**
- * @return {!d3.GeoGraticule}
- */
-d3.geoGraticule = function() {};
-
-/**
- * @typedef {function(...?): !GeoJSON.MultiLineString}
- */
-d3.GeoGraticule;
-
-/**
- * @private {!d3.GeoGraticule}
- */
-d3.GeoGraticule_;
-
-/**
- * @return {!Array<!GeoJSON.LineString>}
- */
-d3.GeoGraticule_.lines = function() {};
-
-/**
- * @return {!GeoJSON.Polygon}
- */
-d3.GeoGraticule_.outline = function() {};
-
-/**
- * @param {!Array<!d3.LngLat>=} extent
- */
-d3.GeoGraticule_.extent = function(extent) {};
-
-/**
- * @param {!Array<!d3.LngLat>=} extent
- */
-d3.GeoGraticule_.extentMajor = function(extent) {};
-
-/**
- * @param {!Array<!d3.LngLat>=} extent
- */
-d3.GeoGraticule_.extentMinor = function(extent) {};
-
-/**
- * @param {!Array<number>=} step
- */
-d3.GeoGraticule_.step = function(step) {};
-
-/**
- * @param {!Array<number>=} step
- */
-d3.GeoGraticule_.stepMajor = function(step) {};
-
-/**
- * @param {!Array<number>=} step
- */
-d3.GeoGraticule_.stepMinor = function(step) {};
-
-/**
- * @param {number=} angle
- */
-d3.GeoGraticule_.precision = function(angle) {};
-
-/**
- * @return {!GeoJSON.MultiLineString}
- */
-d3.geoGraticule10 = function() {};
-
-// Paths
-
-/**
- * @param {?{stream: function(!d3.GeoStream): !d3.GeoStream}=} projection
- * @param {?d3.GeoPathContext=} context
- * @return {!d3.GeoPath}
- */
-d3.geoPath = function(projection, context) {};
-
-/**
- * @typedef {function(!GeoJSON, ...?): string}
- */
-d3.GeoPath;
-
-/**
- * @private {!d3.GeoPath}
- */
-d3.GeoPath_;
-
-/**
- * @param {!GeoJSON} object
- * @return {number}
- */
-d3.GeoPath_.area = function(object) {};
-
-/**
- * @param {!GeoJSON} object
- * @return {!Array<!Array<number>>}
- */
-d3.GeoPath_.bounds = function(object) {};
-
-/**
- * @param {!GeoJSON} object
- * @return {!Array<number>}
- */
-d3.GeoPath_.centroid = function(object) {};
-
-/**
- * @param {!GeoJSON} object
- * @return {number}
- */
-d3.GeoPath_.measure = function(object) {};
-
-/**
- * @param {?{stream: function(!d3.GeoStream): !d3.GeoStream}=} projection
- */
-d3.GeoPath_.projection = function(projection) {};
-
-/**
- * @param {?d3.GeoPathContext=} context
- */
-d3.GeoPath_.context = function(context) {};
-
-/**
- * @param {number | !Function=} radius
- */
-d3.GeoPath_.pointRadius = function(radius) {};
-
-/**
- * Subset of the CanvasRenderingContext2D interface.
- * @interface
- */
-d3.GeoPathContext = function() {};
-
-/**
- * @return {void}
- */
-d3.GeoPathContext.prototype.beginPath = function() {};
-
-/**
- * @param {number} x
- * @param {number} y
- * @return {void}
- */
-d3.GeoPathContext.prototype.moveTo = function(x, y) {};
-
-/**
- * @param {number} x
- * @param {number} y
- * @return {void}
- */
-d3.GeoPathContext.prototype.lineTo = function(x, y) {};
-
-/**
- * @param {number} x
- * @param {number} y
- * @param {number} radius
- * @param {number} startAngle
- * @param {number} endAngle
- * @return {void}
- */
-d3.GeoPathContext.prototype.arc =
-    function(x, y, radius, startAngle, endAngle) {};
-
-/**
- * @return {void}
- */
-d3.GeoPathContext.prototype.closePath = function() {};
-
-// Projections
-
-/**
- * @param {!d3.RawProjection} project
- * @return {!d3.GeoProjection}
- */
-d3.geoProjection = function(project) {};
-
-/**
- * @param {!Function} factory
- * @return {!Function}
- */
-d3.geoProjectionMutator = function(factory) {};
-
-/**
- * @typedef {function(!d3.LngLat): ?Array<number>}
- */
-d3.GeoProjection;
-
-/**
- * @private {!d3.GeoProjection}
- */
-d3.GeoProjection_;
-
-/**
- * @param {!Array<number>} point
- * @return {?d3.LngLat}
- */
-d3.GeoProjection_.invert = function(point) {};
-
-/**
- * @param {!d3.GeoStream} stream
- * @return {!d3.GeoStream}
- */
-d3.GeoProjection_.stream = function(stream) {};
-
-/**
- * @param {function(!d3.GeoStream): !d3.GeoStream=} preclip
- * @return {!Function}
- */
-d3.GeoProjection_.preclip = function(preclip) {};
-
-/**
- * @param {function(!d3.GeoStream): !d3.GeoStream=} postclip
- * @return {!Function}
- */
-d3.GeoProjection_.postclip = function(postclip) {};
-
-/**
- * @param {?number=} angle
- */
-d3.GeoProjection_.clipAngle = function(angle) {};
-
-/**
- * @param {?Array<!Array<number>>=} extent
- */
-d3.GeoProjection_.clipExtent = function(extent) {};
-
-/**
- * @param {number=} scale
- */
-d3.GeoProjection_.scale = function(scale) {};
-
-/**
- * @param {!Array<number>=} translate
- */
-d3.GeoProjection_.translate = function(translate) {};
-
-/**
- * @param {!d3.LngLat=} center
- */
-d3.GeoProjection_.center = function(center) {};
-
-/**
- * @param {!Array<number>=} angles
- */
-d3.GeoProjection_.rotate = function(angles) {};
-
-/**
- * @param {number=} precision
- */
-d3.GeoProjection_.precision = function(precision) {};
-
-/**
- * @param {!Array<!Array<number>>} extent
- * @param {!GeoJSON} object
- * @return {!d3.GeoProjection}
- */
-d3.GeoProjection_.fitExtent = function(extent, object) {};
-
-/**
- * @param {!Array<number>} size
- * @param {!GeoJSON} object
- * @return {!d3.GeoProjection}
- */
-d3.GeoProjection_.fitSize = function(size, object) {};
-
-/**
- * @param {number} width
- * @param {!GeoJSON} object
- * @return {!d3.GeoProjection}
- */
-d3.GeoProjection_.fitWidth = function(width, object) {};
-
-/**
- * @param {number} height
- * @param {!GeoJSON} object
- * @return {!d3.GeoProjection}
- */
-d3.GeoProjection_.fitHeight = function(height, object) {};
-
-/**
- * Only exists for conic projections.
- * @type {function(!Array<number>=) | undefined}
- */
-d3.GeoProjection_.parallels;
-
-/**
- * @return {!d3.GeoProjection}
- */
-d3.geoAlbers = function() {};
-
-/**
- * @return {!d3.GeoProjection}
- */
-d3.geoAlbersUsa = function() {};
-
-/**
- * @return {!d3.GeoProjection}
- */
-d3.geoAzimuthalEqualArea = function() {};
-
-/**
- * @return {!d3.GeoProjection}
- */
-d3.geoAzimuthalEquidistant = function() {};
-
-/**
- * @return {!d3.GeoProjection}
- */
-d3.geoConicConformal = function() {};
-
-/**
- * @return {!d3.GeoProjection}
- */
-d3.geoConicEqualArea = function() {};
-
-/**
- * @return {!d3.GeoProjection}
- */
-d3.geoConicEquidistant = function() {};
-
-/**
- * @return {!d3.GeoProjection}
- */
-d3.geoEquirectangular = function() {};
-
-/**
- * @return {!d3.GeoProjection}
- */
-d3.geoGnomonic = function() {};
-
-/**
- * @return {!d3.GeoProjection}
- */
-d3.geoMercator = function() {};
-
-/**
- * @return {!d3.GeoProjection}
- */
-d3.geoOrthographic = function() {};
-
-/**
- * @return {!d3.GeoProjection}
- */
-d3.geoStereographic = function() {};
-
-/**
- * @return {!d3.GeoProjection}
- */
-d3.geoEqualEarth = function() {};
-
-/**
- * @return {!d3.GeoProjection}
- */
-d3.geoTransverseMercator = function() {};
-
-/**
- * @return {!d3.GeoProjection}
- */
-d3.geoNaturalEarth1 = function() {};
-
-/**
- * @deprecated Use d3.geoIdentity's clipExtent instead.
- */
-d3.geoClipExtent = null;
-
-// Raw Projections
-
-/**
- * (longitude in radians, latitude in radians) => [x, y]
- * @typedef {function(number, number): !Array<number>}
- */
-d3.RawProjection;
-
-/**
- * @private {!d3.RawProjection}
- */
-d3.RawProjection_;
-
-/**
- * @param {number} x
- * @param {number} y
- * @return {!Array<number>}
- */
-d3.RawProjection_.invert = function(x, y) {};
-
-/**
- * @type {!d3.RawProjection}
- */
-d3.geoAzimuthalEqualAreaRaw;
-
-/**
- * @type {!d3.RawProjection}
- */
-d3.geoAzimuthalEquidistantRaw;
-
-/**
- * @param {number} phi0
- * @param {number} phi1
- * @return {!d3.RawProjection}
- */
-d3.geoConicConformalRaw = function(phi0, phi1) {};
-
-/**
- * @param {number} phi0
- * @param {number} phi1
- * @return {!d3.RawProjection}
- */
-d3.geoConicEqualAreaRaw = function(phi0, phi1) {};
-
-/**
- * @param {number} phi0
- * @param {number} phi1
- * @return {!d3.RawProjection}
- */
-d3.geoConicEquidistantRaw = function(phi0, phi1) {};
-
-/**
- * @type {!d3.RawProjection}
- */
-d3.geoEquirectangularRaw;
-
-/**
- * @type {!d3.RawProjection}
- */
-d3.geoGnomonicRaw;
-
-/**
- * @type {!d3.RawProjection}
- */
-d3.geoMercatorRaw;
-
-/**
- * @type {!d3.RawProjection}
- */
-d3.geoOrthographicRaw;
-
-/**
- * @type {!d3.RawProjection}
- */
-d3.geoStereographicRaw;
-
-/**
- * @type {!d3.RawProjection}
- */
-d3.geoEqualEarthRaw;
-
-/**
- * @type {!d3.RawProjection}
- */
-d3.geoTransverseMercatorRaw;
-
-/**
- * @type {!d3.RawProjection}
- */
-d3.geoNaturalEarth1Raw;
-
-// Projection Streams
-
-/**
- * @param {!GeoJSON} object
- * @param {!d3.GeoStream} stream
- * @return {void}
- */
-d3.geoStream = function(object, stream) {};
-
-/**
- * @record
- */
-d3.GeoStream = function() {};
-
-/**
- * @param {number} x
- * @param {number} y
- * @param {number=} z
- * @return {void}
- */
-d3.GeoStream.prototype.point = function(x, y, z) {};
-
-/**
- * @return {void}
- */
-d3.GeoStream.prototype.lineStart = function() {};
-
-/**
- * @return {void}
- */
-d3.GeoStream.prototype.lineEnd = function() {};
-
-/**
- * @return {void}
- */
-d3.GeoStream.prototype.polygonStart = function() {};
-
-/**
- * @return {void}
- */
-d3.GeoStream.prototype.polygonEnd = function() {};
-
-/**
- * @return {void}
- */
-d3.GeoStream.prototype.sphere = function() {};
-
-// Transforms
-
-/**
- * @record
- */
-d3.GeoStreamOverrides = function() {};
-
-/**
- * @type {undefined |
- *     function(this:d3.GeoStreamOverrides, number, number, number=): void}
- */
-d3.GeoStreamOverrides.prototype.point;
-
-/**
- * @type {undefined | function(this:d3.GeoStreamOverrides): void}
- */
-d3.GeoStreamOverrides.prototype.lineStart;
-
-/**
- * @type {undefined | function(this:d3.GeoStreamOverrides): void}
- */
-d3.GeoStreamOverrides.prototype.lineEnd;
-
-/**
- * @type {undefined | function(this:d3.GeoStreamOverrides): void}
- */
-d3.GeoStreamOverrides.prototype.polygonStart;
-
-/**
- * @type {undefined | function(this:d3.GeoStreamOverrides): void}
- */
-d3.GeoStreamOverrides.prototype.polygonEnd;
-
-/**
- * @type {undefined | function(this:d3.GeoStreamOverrides): void}
- */
-d3.GeoStreamOverrides.prototype.sphere;
-
-/**
- * @type {undefined | !d3.GeoStream}
- */
-d3.GeoStreamOverrides.prototype.stream;
-
-/**
- * @param {!d3.GeoStreamOverrides} methods
- * @return {{stream: function(!d3.GeoStream): !d3.GeoStream}}
- */
-d3.geoTransform = function(methods) {};
-
-/**
- * @return {!d3.GeoIdentity}
- */
-d3.geoIdentity = function() {};
-
-/**
- * @interface
- */
-d3.GeoIdentity = function() {};
-
-/**
- * @param {number=} scale
- */
-d3.GeoIdentity.prototype.scale = function(scale) {};
-
-/**
- * @param {!Array<number>=} translate
- */
-d3.GeoIdentity.prototype.translate = function(translate) {};
-
-/**
- * @param {boolean=} reflect
- */
-d3.GeoIdentity.prototype.reflectX = function(reflect) {};
-
-/**
- * @param {boolean=} reflect
- */
-d3.GeoIdentity.prototype.reflectY = function(reflect) {};
-
-/**
- * @param {?Array<!Array<number>>=} extent
- */
-d3.GeoIdentity.prototype.clipExtent = function(extent) {};
-
-/**
- * @param {!Array<number>} size
- * @param {!GeoJSON} object
- * @return {!d3.GeoIdentity}
- */
-d3.GeoIdentity.prototype.fitSize = function(size, object) {};
-
-/**
- * @param {!Array<!Array<number>>} extent
- * @param {!GeoJSON} object
- * @return {!d3.GeoIdentity}
- */
-d3.GeoIdentity.prototype.fitExtent = function(extent, object) {};
-
-/**
- * @param {!d3.GeoStream} stream
- * @return {!d3.GeoStream}
- */
-d3.GeoIdentity.prototype.stream = function(stream) {};
-
-// Clipping
-
-/**
- * @param {!d3.GeoStream} stream
- * @return {!d3.GeoStream}
- */
-d3.geoClipAntimeridian = function(stream) {};
-
-/**
- * @param {number} angle
- * @return {function(!d3.GeoStream): !d3.GeoStream}
- */
-d3.geoClipCircle = function(angle) {};
-
-/**
- * @param {number} x0
- * @param {number} y0
- * @param {number} x1
- * @param {number} y1
- * @return {function(!d3.GeoStream): !d3.GeoStream}
- */
-d3.geoClipRectangle = function(x0, y0, x1, y1) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Hierarchy
-// https://github.com/d3/d3-hierarchy
-////////////////////////////////////////////////////////////////////////////////
-
-// Hierarchy
-
-/**
- * @param {T} data
- * @param {function(T): ?Array<T>=} children
- * @return {!d3.hierarchy<T>}
- * @constructor
- * @template T
- */
-d3.hierarchy = function(data, children) {};
-
-/**
- * @type {T}
- */
-d3.hierarchy.prototype.data;
-
-/**
- * @type {number}
- */
-d3.hierarchy.prototype.depth;
-
-/**
- * @type {number}
- */
-d3.hierarchy.prototype.height;
-
-/**
- * @type {?d3.hierarchy}
- */
-d3.hierarchy.prototype.parent;
-
-/**
- * @type {!Array<!d3.hierarchy<T>> | undefined}
- */
-d3.hierarchy.prototype.children;
-
-/**
- * @type {number | undefined}
- */
-d3.hierarchy.prototype.value;
-
-/**
- * @return {!Array<!d3.hierarchy<T>>}
- */
-d3.hierarchy.prototype.ancestors = function() {};
-
-/**
- * @return {!Array<!d3.hierarchy<T>>}
- */
-d3.hierarchy.prototype.descendants = function() {};
-
-/**
- * @return {!Array<!d3.hierarchy<T>>}
- */
-d3.hierarchy.prototype.leaves = function() {};
-
-/**
- * @param {!d3.hierarchy} target
- * @return {!Array<!d3.hierarchy<T>>}
- */
-d3.hierarchy.prototype.path = function(target) {};
-
-/**
- * @return {!Array<{source: !d3.hierarchy<T>, target: !d3.hierarchy<T>}>}
- */
-d3.hierarchy.prototype.links = function() {};
-
-/**
- * @return {!d3.hierarchy}
- */
-d3.hierarchy.prototype.count = function() {};
-
-/**
- * @param {function(T): number} value
- * @return {!d3.hierarchy}
- */
-d3.hierarchy.prototype.sum = function(value) {};
-
-/**
- * @param {function(!d3.hierarchy<T>, !d3.hierarchy<T>): number} compare
- * @return {!d3.hierarchy}
- */
-d3.hierarchy.prototype.sort = function(compare) {};
-
-/**
- * @param {function(!d3.hierarchy<T>): void} callback
- */
-d3.hierarchy.prototype.each = function(callback) {};
-
-/**
- * @param {function(!d3.hierarchy<T>): void} callback
- */
-d3.hierarchy.prototype.eachAfter = function(callback) {};
-
-/**
- * @param {function(!d3.hierarchy<T>): void} callback
- */
-d3.hierarchy.prototype.eachBefore = function(callback) {};
-
-/**
- * @return {!d3.hierarchy<T>}
- */
-d3.hierarchy.prototype.copy = function() {};
-
-// Stratify
-
-/**
- * @return {!d3.Stratify}
- */
-d3.stratify = function() {};
-
-/**
- * @typedef {function(!Array): !d3.hierarchy}
- */
-d3.Stratify;
-
-/**
- * @private {!d3.Stratify}
- */
-d3.Stratify_;
-
-/**
- * @param {function(T, number, !Array<T>): ?(string | undefined)=} id
- * @template T
- */
-d3.Stratify_.id = function(id) {};
-
-/**
- * @param {function(T, number, !Array<T>): ?(string | undefined)=} parentId
- * @template T
- */
-d3.Stratify_.parentId = function(parentId) {};
-
-// Cluster
-
-/**
- * @return {!d3.Cluster}
- */
-d3.cluster = function() {};
-
-/**
- * @typedef {function(!d3.hierarchy)}
- */
-d3.Cluster;
-
-/**
- * @private {!d3.Cluster}
- */
-d3.Cluster_;
-
-/**
- * @param {!Array<number>=} size
- */
-d3.Cluster_.size = function(size) {};
-
-/**
- * @param {!Array<number>=} size
- */
-d3.Cluster_.nodeSize = function(size) {};
-
-/**
- * @param {function(?, ?): number=} separation
- */
-d3.Cluster_.separation = function(separation) {};
-
-// Tree
-
-/**
- * @return {!d3.Tree}
- */
-d3.tree = function() {};
-
-/**
- * @typedef {function(!d3.hierarchy)}
- */
-d3.Tree;
-
-/**
- * @private {!d3.Tree}
- */
-d3.Tree_;
-
-/**
- * @param {!Array<number>=} size
- */
-d3.Tree_.size = function(size) {};
-
-/**
- * @param {!Array<number>=} size
- */
-d3.Tree_.nodeSize = function(size) {};
-
-/**
- * @param {function(?, ?): number=} separation
- */
-d3.Tree_.separation = function(separation) {};
-
-// Treemap
-
-/**
- * @return {!d3.Treemap}
- */
-d3.treemap = function() {};
-
-/**
- * @typedef {function(!d3.hierarchy)}
- */
-d3.Treemap;
-
-/**
- * @private {!d3.Treemap}
- */
-d3.Treemap_;
-
-/**
- * @param {{node: !d3.hierarchy,
- *          x0: number,
- *          y0: number,
- *          x1: number,
- *          y1: number}=} tile
- */
-d3.Treemap_.tile = function(tile) {};
-
-/**
- * @param {!Array<number>=} size
- */
-d3.Treemap_.size = function(size) {};
-
-/**
- * @param {boolean=} round
- */
-d3.Treemap_.round = function(round) {};
-
-/**
- * @param {number | function(?): number=} padding
- */
-d3.Treemap_.padding = function(padding) {};
-
-/**
- * @param {number | function(?): number=} padding
- */
-d3.Treemap_.paddingInner = function(padding) {};
-
-/**
- * @param {number | function(?): number=} padding
- */
-d3.Treemap_.paddingOuter = function(padding) {};
-
-/**
- * @param {number | function(?): number=} padding
- */
-d3.Treemap_.paddingTop = function(padding) {};
-
-/**
- * @param {number | function(?): number=} padding
- */
-d3.Treemap_.paddingRight = function(padding) {};
-
-/**
- * @param {number | function(?): number=} padding
- */
-d3.Treemap_.paddingBottom = function(padding) {};
-
-/**
- * @param {number | function(?): number=} padding
- */
-d3.Treemap_.paddingLeft = function(padding) {};
-
-// Treemap Tiling
-
-/**
- * @param {!d3.hierarchy} node
- * @param {number} x0
- * @param {number} y0
- * @param {number} x1
- * @param {number} y1
- * @return {void}
- */
-d3.treemapBinary = function(node, x0, y0, x1, y1) {};
-
-/**
- * @param {!d3.hierarchy} node
- * @param {number} x0
- * @param {number} y0
- * @param {number} x1
- * @param {number} y1
- * @return {void}
- */
-d3.treemapDice = function(node, x0, y0, x1, y1) {};
-
-/**
- * @param {!d3.hierarchy} node
- * @param {number} x0
- * @param {number} y0
- * @param {number} x1
- * @param {number} y1
- * @return {void}
- */
-d3.treemapSlice = function(node, x0, y0, x1, y1) {};
-
-/**
- * @param {!d3.hierarchy} node
- * @param {number} x0
- * @param {number} y0
- * @param {number} x1
- * @param {number} y1
- * @return {void}
- */
-d3.treemapSliceDice = function(node, x0, y0, x1, y1) {};
-
-/**
- * @param {!d3.hierarchy} node
- * @param {number} x0
- * @param {number} y0
- * @param {number} x1
- * @param {number} y1
- * @return {void}
- */
-d3.treemapSquarify = function(node, x0, y0, x1, y1) {};
-
-/**
- * @param {number} ratio
- * @return {function(!d3.hierarchy, number, number, number, number): void}
- */
-d3.treemapSquarify.ratio = function(ratio) {};
-
-/**
- * @param {!d3.hierarchy} node
- * @param {number} x0
- * @param {number} y0
- * @param {number} x1
- * @param {number} y1
- * @return {void}
- */
-d3.treemapResquarify = function(node, x0, y0, x1, y1) {};
-
-/**
- * @param {number} ratio
- * @return {function(!d3.hierarchy, number, number, number, number)}
- */
-d3.treemapResquarify.ratio = function(ratio) {};
-
-// Partition
-
-/**
- * @return {!d3.Partition}
- */
-d3.partition = function() {};
-
-/**
- * @typedef {function(!d3.hierarchy)}
- */
-d3.Partition;
-
-/**
- * @private {!d3.Partition}
- */
-d3.Partition_;
-
-/**
- * @param {!Array<number>=} size
- */
-d3.Partition_.size = function(size) {};
-
-/**
- * @param {boolean=} round
- */
-d3.Partition_.round = function(round) {};
-
-/**
- * @param {number=} padding
- */
-d3.Partition_.padding = function(padding) {};
-
-// Pack
-
-/**
- * @return {!d3.Pack}
- */
-d3.pack = function() {};
-
-/**
- * @typedef {function(!d3.hierarchy)}
- */
-d3.Pack;
-
-/**
- * @private {!d3.Pack}
- */
-d3.Pack_;
-
-/**
- * @param {function(?): number=} radius
- */
-d3.Pack_.radius = function(radius) {};
-
-/**
- * @param {!Array<number>=} size
- */
-d3.Pack_.size = function(size) {};
-
-/**
- * @param {number | function(?): number=} padding
- */
-d3.Pack_.padding = function(padding) {};
-
-/**
- * @param {!Array<{r: number}>} circles
- * @return {!Array<{x: number, y: number, r: number}>}
- */
-d3.packSiblings = function(circles) {};
-
-/**
- * @param {!Array<{x: number, y: number, r: number}>} circles
- * @return {{x: number, y: number, r: number}}
- */
-d3.packEnclose = function(circles) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Interpolators
-// https://github.com/d3/d3-interpolate
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @param {T} a
- * @param {T} b
- * @return {function(number): T}
- * @template T
- */
-d3.interpolate = function(a, b) {};
-
-/**
- * @param {number} a
- * @param {number} b
- * @return {function(number): number}
- */
-d3.interpolateNumber = function(a, b) {};
-
-/**
- * @param {number} a
- * @param {number} b
- * @return {function(number): number}
- */
-d3.interpolateRound = function(a, b) {};
-
-/**
- * @param {string} a
- * @param {string} b
- * @return {function(number): string}
- */
-d3.interpolateString = function(a, b) {};
-
-/**
- * @param {number | !Date} a
- * @param {number | !Date} b
- * @return {function(number): !Date}
- */
-d3.interpolateDate = function(a, b) {};
-
-/**
- * @param {!Array<T>} a
- * @param {!Array<T>} b
- * @return {function(number): !Array<T>}
- * @template T
- */
-d3.interpolateArray = function(a, b) {};
-
-/**
- * @param {!Object} a
- * @param {!Object} b
- * @return {function(number): !Object}
- */
-d3.interpolateObject = function(a, b) {};
-
-/**
- * @param {string} a
- * @param {string} b
- * @return {function(number): string}
- */
-d3.interpolateTransformCss = function(a, b) {};
-
-/**
- * @param {string} a
- * @param {string} b
- * @return {function(number): string}
- */
-d3.interpolateTransformSvg = function(a, b) {};
-
-/**
- * @param {!Array<number>} a
- * @param {!Array<number>} b
- * @return {function(number): !Array<number>}
- */
-d3.interpolateZoom = function(a, b) {};
-
-/**
- * @param {!Array<T>} values
- * @return {function(number): T}
- * @template T
- */
-d3.interpolateDiscrete = function(values) {};
-
-// Sampling
-
-/**
- * @param {function(number): T} interpolator
- * @param {number} n
- * @return {!Array<T>}
- * @template T
- */
-d3.quantize = function(interpolator, n) {};
-
-// Color Spaces
-
-/**
- * @param {string | !d3.color} a
- * @param {string | !d3.color} b
- * @return {function(number): string}
- */
-d3.interpolateRgb = function(a, b) {};
-
-/**
- * @param {number} gamma
- * @return {function((string | !d3.color), (string | !d3.color)):
- *     function(number): string}
- */
-d3.interpolateRgb.gamma = function(gamma) {};
-
-/**
- * @param {!Array<string | !d3.color>} colors
- * @return {function(number): string}
- */
-d3.interpolateRgbBasis = function(colors) {};
-
-/**
- * @param {!Array<string | !d3.color>} colors
- * @return {function(number): string}
- */
-d3.interpolateRgbBasisClosed = function(colors) {};
-
-/**
- * @param {string | !d3.color} a
- * @param {string | !d3.color} b
- * @return {function(number): string}
- */
-d3.interpolateHsl = function(a, b) {};
-
-/**
- * @param {string | !d3.color} a
- * @param {string | !d3.color} b
- * @return {function(number): string}
- */
-d3.interpolateHslLong = function(a, b) {};
-
-/**
- * @param {string | !d3.color} a
- * @param {string | !d3.color} b
- * @return {function(number): string}
- */
-d3.interpolateLab = function(a, b) {};
-
-/**
- * @param {string | !d3.color} a
- * @param {string | !d3.color} b
- * @return {function(number): string}
- */
-d3.interpolateHcl = function(a, b) {};
-
-/**
- * @param {string | !d3.color} a
- * @param {string | !d3.color} b
- * @return {function(number): string}
- */
-d3.interpolateHclLong = function(a, b) {};
-
-/**
- * @param {string | !d3.color} a
- * @param {string | !d3.color} b
- * @return {function(number): string}
- */
-d3.interpolateCubehelix = function(a, b) {};
-
-/**
- * @param {number} gamma
- * @return {function((string | !d3.color), (string | !d3.color)):
- *     function(number): string}
- */
-d3.interpolateCubehelix.gamma = function(gamma) {};
-
-/**
- * @param {string | !d3.color} a
- * @param {string | !d3.color} b
- * @return {function(number): string}
- */
-d3.interpolateCubehelixLong = function(a, b) {};
-
-/**
- * @param {number} gamma
- * @return {function((string | !d3.color), (string | !d3.color)):
- *     function(number): string}
- */
-d3.interpolateCubehelixLong.gamma = function(gamma) {};
-
-/**
- * @param {number} a
- * @param {number} b
- * @return {function(number): number}
- */
-d3.interpolateHue = function(a, b) {};
-
-// Splines
-
-/**
- * @param {!Array<number>} values
- * @return {function(number): number}
- */
-d3.interpolateBasis = function(values) {};
-
-/**
- * @param {!Array<number>} values
- * @return {function(number): number}
- */
-d3.interpolateBasisClosed = function(values) {};
-
-// Piecewise
-
-/**
- * @param {function(T, T): function(number): T} interpolate
- * @param {!Array<T>} values
- * @return {function(number): T}
- * @template T
- */
-d3.piecewise = function(interpolate, values) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Paths
-// https://github.com/d3/d3-path
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @constructor
- * @return {!d3.path}
- */
-d3.path = function() {};
-
-/**
- * @param {number} x
- * @param {number} y
- * @return {void}
- */
-d3.path.prototype.moveTo = function(x, y) {};
-
-/**
- * @return {void}
- */
-d3.path.prototype.closePath = function() {};
-
-/**
- * @param {number} x
- * @param {number} y
- * @return {void}
- */
-d3.path.prototype.lineTo = function(x, y) {};
-
-/**
- * @param {number} cpx
- * @param {number} cpy
- * @param {number} x
- * @param {number} y
- * @return {void}
- */
-d3.path.prototype.quadraticCurveTo = function(cpx, cpy, x, y) {};
-
-/**
- * @param {number} cpx1
- * @param {number} cpy1
- * @param {number} cpx2
- * @param {number} cpy2
- * @param {number} x
- * @param {number} y
- * @return {void}
- */
-d3.path.prototype.bezierCurveTo = function(cpx1, cpy1, cpx2, cpy2, x, y) {};
-
-/**
- * @param {number} x1
- * @param {number} y1
- * @param {number} x2
- * @param {number} y2
- * @param {number} radius
- * @return {void}
- */
-d3.path.prototype.arcTo = function(x1, y1, x2, y2, radius) {};
-
-/**
- * @param {number} x
- * @param {number} y
- * @param {number} radius
- * @param {number} startAngle
- * @param {number} endAngle
- * @param {boolean=} anticlockwise
- * @return {void}
- */
-d3.path.prototype.arc = function(x, y, radius, startAngle, endAngle,
-    anticlockwise) {};
-
-/**
- * @param {number} x
- * @param {number} y
- * @param {number} w
- * @param {number} h
- * @return {void}
- */
-d3.path.prototype.rect = function(x, y, w, h) {};
-
-/**
- * @override
- * @return {string}
- */
-d3.path.prototype.toString = function() {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Polygons
-// https://github.com/d3/d3-polygon
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @param {!Array<!Array<number>>} polygon
- * @return {number}
- */
-d3.polygonArea = function(polygon) {};
-
-/**
- * @param {!Array<!Array<number>>} polygon
- * @return {!Array<number>}
- */
-d3.polygonCentroid = function(polygon) {};
-
-/**
- * @param {!Array<!Array<number>>} points
- * @return {?Array<!Array<number>>}
- */
-d3.polygonHull = function(points) {};
-
-/**
- * @param {!Array<!Array<number>>} polygon
- * @param {!Array<number>} point
- * @return {boolean}
- */
-d3.polygonContains = function(polygon, point) {};
-
-/**
- * @param {!Array<!Array<number>>} polygon
- * @return {number}
- */
-d3.polygonLength = function(polygon) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Quadtrees
-// https://github.com/d3/d3-quadtree
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @param {!Array<T>=} data
- * @param {function(T): number=} x
- * @param {function(T): number=} y
- * @constructor
- * @return {!d3.quadtree<T>}
- * @template T
- */
-d3.quadtree = function(data, x, y) {};
-
-/**
- * @param {function(T): number=} x
- */
-d3.quadtree.prototype.x = function(x) {};
-
-/**
- * @param {function(T): number=} y
- */
-d3.quadtree.prototype.y = function(y) {};
-
-/**
- * @param {!Array<!Array<number>>=} extent
- */
-d3.quadtree.prototype.extent = function(extent) {};
-
-/**
- * @param {number} x
- * @param {number} y
- * @return {!d3.quadtree<T>}
- */
-d3.quadtree.prototype.cover = function(x, y) {};
-
-/**
- * @param {T} datum
- * @return {!d3.quadtree<T>}
- */
-d3.quadtree.prototype.add = function(datum) {};
-
-/**
- * @param {!Array<T>} data
- * @return {!d3.quadtree<T>}
- */
-d3.quadtree.prototype.addAll = function(data) {};
-
-/**
- * @param {T} datum
- * @return {!d3.quadtree<T>}
- */
-d3.quadtree.prototype.remove = function(datum) {};
-
-/**
- * @param {!Array<T>} data
- * @return {!d3.quadtree<T>}
- */
-d3.quadtree.prototype.removeAll = function(data) {};
-
-/**
- * @return {!d3.quadtree<T>}
- */
-d3.quadtree.prototype.copy = function() {};
-
-/**
- * @return {!d3.QuadtreeNode | undefined}
- */
-d3.quadtree.prototype.root = function() {};
-
-/**
- * @return {!Array<T>}
- */
-d3.quadtree.prototype.data = function() {};
-
-/**
- * @return {number}
- */
-d3.quadtree.prototype.size = function() {};
-
-/**
- * @param {number} x
- * @param {number} y
- * @param {number=} radius
- * @return {T | undefined}
- */
-d3.quadtree.prototype.find = function(x, y, radius) {};
-
-/**
- * @param {function(!d3.QuadtreeNode, number, number, number, number):
- *     (boolean | undefined)} callback
- */
-d3.quadtree.prototype.visit = function(callback) {};
-
-/**
- * @param {function(!d3.QuadtreeNode, number, number, number, number): void}
- *     callback
- */
-d3.quadtree.prototype.visitAfter = function(callback) {};
-
-// Nodes
-
-/**
- * @record
- */
-d3.QuadtreeLeaf = function() {};
-
-/**
- * @type {?}
- */
-d3.QuadtreeLeaf.prototype.data;
-
-/**
- * @type {!d3.QuadtreeLeaf | undefined}
- */
-d3.QuadtreeLeaf.prototype.next;
-
-/**
- * JSCompiler doesn't support recursive typedefs, therefore we use Object
- * instead of (!d3.QuadtreeNode | !d3.QuadtreeLeaf) for child nodes.
- * @typedef {!d3.QuadtreeLeaf | !Array<!Object | undefined>}
- */
-d3.QuadtreeNode;
-
-////////////////////////////////////////////////////////////////////////////////
-// Random Numbers
-// https://github.com/d3/d3-random
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @param {number=} minOrMax
- * @param {number=} max
- * @return {function(): number}
- */
-d3.randomUniform = function(minOrMax, max) {};
-
-/**
- * @param {function(): number} source
- * @return {function(number=, number=): function(): number}
- */
-d3.randomUniform.source = function(source) {};
-
-/**
- * @param {number=} mu
- * @param {number=} sigma
- * @return {function(): number}
- */
-d3.randomNormal = function(mu, sigma) {};
-
-/**
- * @param {function(): number} source
- * @return {function(number=, number=): function(): number}
- */
-d3.randomNormal.source = function(source) {};
-
-/**
- * @param {number=} mu
- * @param {number=} sigma
- * @return {function(): number}
- */
-d3.randomLogNormal = function(mu, sigma) {};
-
-/**
- * @param {function(): number} source
- * @return {function(number=, number=): function(): number}
- */
-d3.randomLogNormal.source = function(source) {};
-
-/**
- * @param {number} n
- * @return {function(): number}
- */
-d3.randomBates = function(n) {};
-
-/**
- * @param {function(): number} source
- * @return {function(number): function(): number}
- */
-d3.randomBates.source = function(source) {};
-
-/**
- * @param {number} n
- * @return {function(): number}
- */
-d3.randomIrwinHall = function(n) {};
-
-/**
- * @param {function(): number} source
- * @return {function(number): function(): number}
- */
-d3.randomIrwinHall.source = function(source) {};
-
-/**
- * @param {number} lambda
- * @return {function(): number}
- */
-d3.randomExponential = function(lambda) {};
-
-/**
- * @param {function(): number} source
- * @return {function(number): function(): number}
- */
-d3.randomExponential.source = function(source) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Scales
-// https://github.com/d3/d3-scale
-////////////////////////////////////////////////////////////////////////////////
-
-// Linear Scales
-
-/**
- * @return {!d3.LinearScale}
- */
-d3.scaleLinear = function() {};
-
-/**
- * Besides numbers, continuous scales also support RGB string ranges.
- * @typedef {function(number): ?}
- */
-d3.LinearScale;
-
-/**
- * @private {!d3.LinearScale}
- */
-d3.LinearScale_;
-
-/**
- * @param {number} value
- * @return {number}
- */
-d3.LinearScale_.invert = function(value) {};
-
-/**
- * @param {!Array<number>=} domain
- */
-d3.LinearScale_.domain = function(domain) {};
-
-/**
- * @param {!(Array<number> | Array<string>)=} range
- */
-d3.LinearScale_.range = function(range) {};
-
-/**
- * @param {!Array<number>=} range
- */
-d3.LinearScale_.rangeRound = function(range) {};
-
-/**
- * @param {boolean=} clamp
- */
-d3.LinearScale_.clamp = function(clamp) {};
-
-/**
- * @param {function(?, ?): function(number)=} interpolate
- */
-d3.LinearScale_.interpolate = function(interpolate) {};
-
-/**
- * @param {number=} count
- * @return {!Array<number>}
- */
-d3.LinearScale_.ticks = function(count) {};
-
-/**
- * @param {number=} count
- * @param {string=} specifier
- * @return {function(number): string}
- */
-d3.LinearScale_.tickFormat = function(count, specifier) {};
-
-/**
- * @param {number=} count
- * @return {!d3.LinearScale}
- */
-d3.LinearScale_.nice = function(count) {};
-
-/**
- * @return {!d3.LinearScale}
- */
-d3.LinearScale_.copy = function() {};
-
-// Power Scales
-
-/**
- * @return {!d3.PowScale}
- */
-d3.scalePow = function() {};
-
-/**
- * @typedef {function(number): ?}
- */
-d3.PowScale;
-
-/**
- * @private {!d3.PowScale}
- */
-d3.PowScale_;
-
-/**
- * @param {number} value
- * @return {number}
- */
-d3.PowScale_.invert = function(value) {};
-
-/**
- * @param {number=} exponent
- */
-d3.PowScale_.exponent = function(exponent) {};
-
-/**
- * @param {!Array<number>=} domain
- */
-d3.PowScale_.domain = function(domain) {};
-
-/**
- * @param {!(Array<number> | Array<string>)=} range
- */
-d3.PowScale_.range = function(range) {};
-
-/**
- * @param {!Array<number>=} range
- */
-d3.PowScale_.rangeRound = function(range) {};
-
-/**
- * @param {boolean=} clamp
- */
-d3.PowScale_.clamp = function(clamp) {};
-
-/**
- * @param {function(?, ?): function(number)=} interpolate
- */
-d3.PowScale_.interpolate = function(interpolate) {};
-
-/**
- * @param {number=} count
- * @return {!Array<number>}
- */
-d3.PowScale_.ticks = function(count) {};
-
-/**
- * @param {number=} count
- * @param {string=} specifier
- * @return {function(number): string}
- */
-d3.PowScale_.tickFormat = function(count, specifier) {};
-
-/**
- * @param {number=} count
- * @return {!d3.PowScale}
- */
-d3.PowScale_.nice = function(count) {};
-
-/**
- * @return {!d3.PowScale}
- */
-d3.PowScale_.copy = function() {};
-
-/**
- * @return {!d3.PowScale}
- */
-d3.scaleSqrt = function() {};
-
-// Log Scales
-
-/**
- * @return {!d3.LogScale}
- */
-d3.scaleLog = function() {};
-
-/**
- * @typedef {function(number): ?}
- */
-d3.LogScale;
-
-/**
- * @private {!d3.LogScale}
- */
-d3.LogScale_;
-
-/**
- * @param {number} value
- * @return {number}
- */
-d3.LogScale_.invert = function(value) {};
-
-/**
- * @param {number=} base
- */
-d3.LogScale_.base = function(base) {};
-
-/**
- * @param {!Array<number>=} domain
- */
-d3.LogScale_.domain = function(domain) {};
-
-/**
- * @param {!(Array<number> | Array<string>)=} range
- */
-d3.LogScale_.range = function(range) {};
-
-/**
- * @param {!Array<number>=} range
- */
-d3.LogScale_.rangeRound = function(range) {};
-
-/**
- * @param {boolean=} clamp
- */
-d3.LogScale_.clamp = function(clamp) {};
-
-/**
- * @param {function(?, ?): function(number)=} interpolate
- */
-d3.LogScale_.interpolate = function(interpolate) {};
-
-/**
- * @param {number=} count
- * @return {!Array<number>}
- */
-d3.LogScale_.ticks = function(count) {};
-
-/**
- * @param {number=} count
- * @param {string=} specifier
- * @return {function(number): string}
- */
-d3.LogScale_.tickFormat = function(count, specifier) {};
-
-/**
- * @param {number=} count
- * @return {!d3.LogScale}
- */
-d3.LogScale_.nice = function(count) {};
-
-/**
- * @return {!d3.LogScale}
- */
-d3.LogScale_.copy = function() {};
-
-// Identity Scales
-
-/**
- * @return {!d3.IdentityScale}
- */
-d3.scaleIdentity = function() {};
-
-/**
- * @typedef {function(number): number}
- */
-d3.IdentityScale;
-
-/**
- * @private {!d3.IdentityScale}
- */
-d3.IdentityScale_;
-
-/**
- * @param {number} value
- * @return {number}
- */
-d3.IdentityScale_.invert = function(value) {};
-
-/**
- * @param {!Array<number>=} domain
- */
-d3.IdentityScale_.domain = function(domain) {};
-
-/**
- * @param {!Array<number>=} range
- */
-d3.IdentityScale_.range = function(range) {};
-
-/**
- * @param {number=} count
- * @return {!Array<number>}
- */
-d3.IdentityScale_.ticks = function(count) {};
-
-/**
- * @param {number=} count
- * @param {string=} specifier
- * @return {function(number): string}
- */
-d3.IdentityScale_.tickFormat = function(count, specifier) {};
-
-/**
- * @param {number=} count
- * @return {!d3.IdentityScale}
- */
-d3.IdentityScale_.nice = function(count) {};
-
-/**
- * @return {!d3.IdentityScale}
- */
-d3.IdentityScale_.copy = function() {};
-
-// Time Scales
-
-/**
- * @return {!d3.TimeScale}
- */
-d3.scaleTime = function() {};
-
-/**
- * @typedef {function((number | !Date)): ?}
- */
-d3.TimeScale;
-
-/**
- * @private {!d3.TimeScale}
- */
-d3.TimeScale_;
-
-/**
- * @param {number} value
- * @return {!Date}
- */
-d3.TimeScale_.invert = function(value) {};
-
-/**
- * @param {!Array<!Date>=} domain
- */
-d3.TimeScale_.domain = function(domain) {};
-
-/**
- * @param {!(Array<number> | Array<string>)=} range
- */
-d3.TimeScale_.range = function(range) {};
-
-/**
- * @param {!Array<number>=} range
- */
-d3.TimeScale_.rangeRound = function(range) {};
-
-/**
- * @param {boolean=} clamp
- */
-d3.TimeScale_.clamp = function(clamp) {};
-
-/**
- * @param {function(?, ?): function(number)=} interpolate
- */
-d3.TimeScale_.interpolate = function(interpolate) {};
-
-/**
- * @param {number | ?d3.Interval=} countOrInterval
- * @return {!Array<!Date>}
- */
-d3.TimeScale_.ticks = function(countOrInterval) {};
-
-/**
- * @param {?number | d3.Interval=} countOrInterval
- * @param {string=} specifier
- * @return {function(!Date): string}
- */
-d3.TimeScale_.tickFormat = function(countOrInterval, specifier) {};
-
-/**
- * @param {?number | d3.Interval=} countOrInterval
- * @param {number=} step
- */
-d3.TimeScale_.nice = function(countOrInterval, step) {};
-
-/**
- * @return {!d3.TimeScale}
- */
-d3.TimeScale_.copy = function() {};
-
-/**
- * @return {!d3.TimeScale}
- */
-d3.scaleUtc = function() {};
-
-// Sequential Scales
-
-/**
- * @param {function(number): ?} interpolator
- * @return {!d3.SequentialScale}
- */
-d3.scaleSequential = function(interpolator) {};
-
-/**
- * @typedef {function(number): ?}
- */
-d3.SequentialScale;
-
-/**
- * @private {!d3.SequentialScale}
- */
-d3.SequentialScale_;
-
-/**
- * @param {!Array<number>=} domain
- */
-d3.SequentialScale_.domain = function(domain) {};
-
-/**
- * @param {boolean=} clamp
- */
-d3.SequentialScale_.clamp = function(clamp) {};
-
-/**
- * @param {function(number)=} interpolator
- */
-d3.SequentialScale_.interpolator = function(interpolator) {};
-
-/**
- * @return {!d3.SequentialScale}
- */
-d3.SequentialScale_.copy = function() {};
-
-// Diverging scales
-
-/**
- * @param {?} interpolator
- * @return {!d3.DivergingScale}
- */
-d3.scaleDiverging = function(interpolator) {};
-
-/**
- * @typedef {function(number): ?}
- */
-d3.DivergingScale;
-
-/**
- * @private {!d3.DivergingScale}
- */
-d3.DivergingScale_;
-
-/**
- * @param {!Array<number>=} domain Exactly 3 values
- * @return {?}
- */
-d3.DivergingScale_.domain = function(domain) {};
-
-/**
- * @param {boolean=} clamp
- * @return {?}
- */
-d3.DivergingScale_.clamp = function(clamp) {};
-
-/**
- * @param {!Function=} interpolator
- * @return {?}
- */
-d3.DivergingScale_.interpolator = function(interpolator) {};
-
-/**
- * @return {!d3.DivergingScale}
- */
-d3.DivergingScale_.copy = function() {};
-
-// Quantize Scales
-
-/**
- * @return {!d3.QuantizeScale}
- */
-d3.scaleQuantize = function() {};
-
-/**
- * @typedef {function(number): ?}
- */
-d3.QuantizeScale;
-
-/**
- * @private {!d3.QuantizeScale}
- */
-d3.QuantizeScale_;
-
-/**
- * @param {?} value
- * @return {!Array<number>}
- */
-d3.QuantizeScale_.invertExtent = function(value) {};
-
-/**
- * @param {!Array<number>=} domain
- */
-d3.QuantizeScale_.domain = function(domain) {};
-
-/**
- * @param {!Array=} range
- */
-d3.QuantizeScale_.range = function(range) {};
-
-/**
- * @param {number=} count
- * @return {!Array<number>}
- */
-d3.QuantizeScale_.ticks = function(count) {};
-
-/**
- * @param {number=} count
- * @param {string=} specifier
- * @return {function(number): string}
- */
-d3.QuantizeScale_.tickFormat = function(count, specifier) {};
-
-/**
- * @param {number=} count
- * @return {!d3.QuantizeScale}
- */
-d3.QuantizeScale_.nice = function(count) {};
-
-/**
- * @return {!d3.QuantizeScale}
- */
-d3.QuantizeScale_.copy = function() {};
-
-// Quantile Scales
-
-/**
- * @return {!d3.QuantileScale}
- */
-d3.scaleQuantile = function() {};
-
-/**
- * @typedef {function(number): ?}
- */
-d3.QuantileScale;
-
-/**
- * @private {!d3.QuantileScale}
- */
-d3.QuantileScale_;
-
-/**
- * @param {?} value
- * @return {!Array<number>}
- */
-d3.QuantileScale_.invertExtent = function(value) {};
-
-/**
- * @param {!Array<number>=} domain
- */
-d3.QuantileScale_.domain = function(domain) {};
-
-/**
- * @param {!Array=} range
- */
-d3.QuantileScale_.range = function(range) {};
-
-/**
- * @return {!Array<number>}
- */
-d3.QuantileScale_.quantiles = function() {};
-
-/**
- * @return {!d3.QuantileScale}
- */
-d3.QuantileScale_.copy = function() {};
-
-// Threshold Scales
-
-/**
- * @return {!d3.ThresholdScale}
- */
-d3.scaleThreshold = function() {};
-
-/**
- * @typedef {function((number | string)): ?}
- */
-d3.ThresholdScale;
-
-/**
- * @private {!d3.ThresholdScale}
- */
-d3.ThresholdScale_;
-
-/**
- * @param {?} value
- * @return {!Array}
- */
-d3.ThresholdScale_.invertExtent = function(value) {};
-
-/**
- * @param {!Array=} domain
- */
-d3.ThresholdScale_.domain = function(domain) {};
-
-/**
- * @param {!Array=} range
- */
-d3.ThresholdScale_.range = function(range) {};
-
-/**
- * @return {!d3.ThresholdScale}
- */
-d3.ThresholdScale_.copy = function() {};
-
-// Ordinal Scales
-
-/**
- * @param {!Array<?>=} range
- * @return {!d3.OrdinalScale}
- */
-d3.scaleOrdinal = function(range) {};
-
-/**
- * @typedef {function((string | number)): ?}
- */
-d3.OrdinalScale;
-
-/**
- * @private {!d3.OrdinalScale}
- */
-d3.OrdinalScale_;
-
-/**
- * @param {!(Array<string> | Array<number>)=} domain
- */
-d3.OrdinalScale_.domain = function(domain) {};
-
-/**
- * @param {!Array=} range
- */
-d3.OrdinalScale_.range = function(range) {};
-
-/**
- * @param {?=} value
- */
-d3.OrdinalScale_.unknown = function(value) {};
-
-/**
- * @return {!d3.OrdinalScale}
- */
-d3.OrdinalScale_.copy = function() {};
-
-/**
- * @type {{name: string}}
- */
-d3.scaleImplicit;
-
-// Band Scales
-
-/**
- * @return {!d3.BandScale}
- */
-d3.scaleBand = function() {};
-
-/**
- * @typedef {function(string): number}
- */
-d3.BandScale;
-
-/**
- * @private {!d3.BandScale}
- */
-d3.BandScale_;
-
-/**
- * @param {!(Array<string> | Array<number>)=} domain
- */
-d3.BandScale_.domain = function(domain) {};
-
-/**
- * @param {!Array<number>=} range
- */
-d3.BandScale_.range = function(range) {};
-
-/**
- * @param {!Array<number>=} range
- */
-d3.BandScale_.rangeRound = function(range) {};
-
-/**
- * @param {boolean=} round
- */
-d3.BandScale_.round = function(round) {};
-
-/**
- * @param {number=} padding
- */
-d3.BandScale_.paddingInner = function(padding) {};
-
-/**
- * @param {number=} padding
- */
-d3.BandScale_.paddingOuter = function(padding) {};
-
-/**
- * @param {number=} padding
- */
-d3.BandScale_.padding = function(padding) {};
-
-/**
- * @param {number=} align
- */
-d3.BandScale_.align = function(align) {};
-
-/**
- * @return {number}
- */
-d3.BandScale_.bandwidth = function() {};
-
-/**
- * @return {number}
- */
-d3.BandScale_.step = function() {};
-
-/**
- * @return {!d3.BandScale}
- */
-d3.BandScale_.copy = function() {};
-
-// Point Scales
-
-/**
- * @return {!d3.PointScale}
- */
-d3.scalePoint = function() {};
-
-/**
- * @typedef {function(string): number}
- */
-d3.PointScale;
-
-/**
- * @private {!d3.PointScale}
- */
-d3.PointScale_;
-
-/**
- * @param {!(Array<string> | Array<number>)=} domain
- */
-d3.PointScale_.domain = function(domain) {};
-
-/**
- * @param {!Array<number>=} range
- */
-d3.PointScale_.range = function(range) {};
-
-/**
- * @param {!Array<number>=} range
- */
-d3.PointScale_.rangeRound = function(range) {};
-
-/**
- * @param {boolean=} round
- */
-d3.PointScale_.round = function(round) {};
-
-/**
- * @param {number=} padding
- */
-d3.PointScale_.padding = function(padding) {};
-
-/**
- * @param {number=} align
- */
-d3.PointScale_.align = function(align) {};
-
-/**
- * @return {number}
- */
-d3.PointScale_.bandwidth = function() {};
-
-/**
- * @return {number}
- */
-d3.PointScale_.step = function() {};
-
-/**
- * @return {!d3.PointScale}
- */
-d3.PointScale_.copy = function() {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Sequential, diverging and categorical color scales.
-// https://github.com/d3/d3-scale-chromatic
-////////////////////////////////////////////////////////////////////////////////
-
-// Categorical
-
-/**
- * @const {!Array<string>}
- */
-d3.schemeCategory10;
-
-/**
- * @const {!Array<string>}
- */
-d3.schemeCategory20;
-
-/**
- * @const {!Array<string>}
- */
-d3.schemeCategory20b;
-
-/**
- * @const {!Array<string>}
- */
-d3.schemeCategory20c;
-
-/**
- * @const {!Array<string>}
- */
-d3.schemeAccent;
-
-/**
- * @const {!Array<string>}
- */
-d3.schemeDark2;
-
-/**
- * @const {!Array<string>}
- */
-d3.schemePaired;
-
-/**
- * @const {!Array<string>}
- */
-d3.schemePastel1;
-
-/**
- * @const {!Array<string>}
- */
-d3.schemePastel2;
-
-/**
- * @const {!Array<string>}
- */
-d3.schemeSet1;
-
-/**
- * @const {!Array<string>}
- */
-d3.schemeSet2;
-
-/**
- * @const {!Array<string>}
- */
-d3.schemeSet3;
-
-// Diverging
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateBrBG = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeBrBG;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolatePRGn = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemePRGn;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolatePiYG = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemePiYG;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolatePuOr = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemePuOr;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateRdBu = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeRdBu;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateRdGy = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeRdGy;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateRdYlBu = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeRdYlBu;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateRdYlGn = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeRdYlGn;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateSpectral = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeSpectral;
-
-// Sequential
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateBlues = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeBlues;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateGreens = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeGreens;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateGreys = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeGreys;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateOranges = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeOranges;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolatePurples = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemePurples;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateReds = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeReds;
-
-// Sequential (Multi-Hue)
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateViridis = function(t) {};
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateInferno = function(t) {};
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateMagma = function(t) {};
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolatePlasma = function(t) {};
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateWarm = function(t) {};
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateCool = function(t) {};
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateCubehelixDefault = function(t) {};
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateBuGn = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeBuGn;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateBuPu = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeBuPu;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateGnBu = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeGnBu;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateOrRd = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeOrRd;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolatePuBuGn = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemePuBuGn;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolatePuBu = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemePuBu;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolatePuRd = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemePuRd;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateRdPu = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeRdPu;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateYlGnBu = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeYlGnBu;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateYlGn = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeYlGn;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateYlOrBr = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeYlOrBr;
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateYlOrRd = function(t) {};
-
-/**
- * @const {!Array<!Array<string>>}
- */
-d3.schemeYlOrRd;
-
-// Cyclical
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateRainbow = function(t) {};
-
-/**
- * @param {number} t 0..1
- * @return {string}
- */
-d3.interpolateSinebow = function(t) {};
-////////////////////////////////////////////////////////////////////////////////
-// Selections
-// https://github.com/d3/d3-selection
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-// Selecting Elements
-
-// According to https://github.com/d3/d3-selection/issues/103 d3.selection has
-// limited support for non-element item types. Although the following examples
-// work
-//
-//   var s = d3.select(window).on('resize', function() { ... });
-//   var s = d3.select('p').append(() => document.createTextNode('foo'));
-//
-// most method calls such as s.attr('foo') or s.select('p') throw an Error.
-//
-// The declarations below try to stay on the safe side, therefore they only
-// accept elements. To select a text node or a window, cast it first to {?}.
-
-/**
- * @return {!d3.selection}
- * @constructor
- */
-d3.selection = function() {};
-
-/**
- * @param {?string | Element | Window} selector
- *     WARNING: d3.select(window) doesn't return a fully functional selection.
- *     Registering event listeners with on() and setting properties with
- *     property() work, but most methods throw an Error or silently fail.
- * @return {!d3.selection}
- */
-d3.select = function(selector) {};
-
-/**
- * @param {?string | Array<!Element> | NodeList<!Element>} selector
- * @return {!d3.selection}
- */
-d3.selectAll = function(selector) {};
-
-/**
- * @param {?string | function(this:Element): ?Element} selector
- * @return {!d3.selection}
- */
-d3.selection.prototype.select = function(selector) {};
-
-/**
- * @param {?string | function(this:Element): !IArrayLike<!Element>} selector
- * @return {!d3.selection}
- */
-d3.selection.prototype.selectAll = function(selector) {};
-
-/**
- * @param {string |
- *     function(this:Element, ?, number, !IArrayLike<!Element>): boolean} filter
- * @return {!d3.selection}
- */
-d3.selection.prototype.filter = function(filter) {};
-
-/**
- * @param {!d3.selection} other
- * @return {!d3.selection}
- */
-d3.selection.prototype.merge = function(other) {};
-
-/**
- * @param {string} selector
- * @return {function(this:Element): boolean}
- */
-d3.matcher = function(selector) {};
-
-/**
- * @param {string} selector
- * @return {function(this:Element): ?Element}
- */
-d3.selector = function(selector) {};
-
-/**
- * @param {string} selector
- * @return {function(this:Element): !IArrayLike<!Element>}
- */
-d3.selectorAll = function(selector) {};
-
-/**
- * @param {!(Node | Document | Window)} node
- * @return {!Window}
- */
-d3.window = function(node) {};
-
-/**
- * @param {!Element} node
- * @param {string} name
- * @return {string}
- */
-d3.style = function(node, name) {};
-
-// Modifying Elements
-
-/**
- * @param {string} name
- * @param {?string | number | boolean | d3.local |
- *     function(this:Element, ?, number, !IArrayLike<!Element>):
- *         ?(string | number | boolean)=} value
- */
-d3.selection.prototype.attr = function(name, value) {};
-
-/**
- * @param {string} names Space separated CSS class names.
- * @param {boolean |
- *     function(this:Element, ?, number, !IArrayLike<!Element>): boolean=}
- *     value
- */
-d3.selection.prototype.classed = function(names, value) {};
-
-/**
- * @param {string} name
- * @param {?string | number |
- *    function(this:Element, ?, number, !IArrayLike<!Element>):
- *        ?(string | number)=} value
- * @param {?string=} priority
- * @return {?} Style value (1 argument) or this (2+ arguments)
- */
-d3.selection.prototype.style = function(name, value, priority) {};
-
-/**
- * @param {string | !d3.local} name
- * @param {* | function(this:Element, ?, number, !IArrayLike<!Element>)=}
- *     value
- */
-d3.selection.prototype.property = function(name, value) {};
-
-/**
- * @param {?string |
- *     function(this:Element, ?, number, !IArrayLike<!Element>): ?string=}
- *     value
- */
-d3.selection.prototype.text = function(value) {};
-
-/**
- * @param {?string |
- *     function(this:Element, ?, number, !IArrayLike<!Element>): ?string=}
- *     value
- */
-d3.selection.prototype.html = function(value) {};
-
-/**
- * @param {string |
- *     function(this:Element, ?, number, !IArrayLike<!Element>): !Element} type
- * @return {!d3.selection}
- */
-d3.selection.prototype.append = function(type) {};
-
-/**
- * @param {string |
- *     function(this:Element, ?, number, !IArrayLike<!Element>): !Element} type
- * @param {?string |
- *     function(this:Element, ?, number, !IArrayLike<!Element>): ?Element=}
- *     before
- * @return {!d3.selection}
- */
-d3.selection.prototype.insert = function(type, before) {};
-
-/**
- * @return {!d3.selection}
- */
-d3.selection.prototype.remove = function() {};
-
-/**
- * @param {boolean=} deep
- * @return {!d3.selection}
- */
-d3.selection.prototype.clone = function(deep) {};
-
-/**
- * @param {function(?, ?): number} compare
- * @return {!d3.selection}
- */
-d3.selection.prototype.sort = function(compare) {};
-
-/**
- * @return {!d3.selection}
- */
-d3.selection.prototype.order = function() {};
-
-/**
- * @return {!d3.selection}
- */
-d3.selection.prototype.raise = function() {};
-
-/**
- * @return {!d3.selection}
- */
-d3.selection.prototype.lower = function() {};
-
-/**
- * @param {string} name
- * @return {!d3.selection}
- */
-d3.create = function(name) {};
-
-/**
- * @param {string} name
- * @return {function(this:Element): !Element}
- */
-d3.creator = function(name) {};
-
-// Joining Data
-
-/**
- * @param {!Array |
- *     function(this:Element, ?, number, !IArrayLike<!Element>): !Array=}
- *     data
- * @param {function(this:Element, ?, number, !IArrayLike)=} key
- */
-d3.selection.prototype.data = function(data, key) {};
-
-/**
- * @return {!d3.selection}
- */
-d3.selection.prototype.enter = function() {};
-
-/**
- * @return {!d3.selection}
- */
-d3.selection.prototype.exit = function() {};
-
-/**
- * @param {* | function(this:Element, ?, number, !IArrayLike<!Element>)=}
- *     value
- * @return {?}
- */
-d3.selection.prototype.datum = function(value) {};
-
-// Handling Events
-
-/**
- * @param {string} typenames
- * @param {?function(this:Element, ?, number, !IArrayLike<!Element>)=}
- *     listener
- * @param {boolean=} capture
- * @return {?} d3.selection (2+ arguments), listener function (1 argument) or
- *     undefined (1 argument).
- */
-d3.selection.prototype.on = function(typenames, listener, capture) {};
-
-/**
- * @record
- */
-d3.EventParameters = function() {};
-
-/**
- * @type {boolean | undefined}
- */
-d3.EventParameters.prototype.bubbles;
-
-/**
- * @type {boolean | undefined}
- */
-d3.EventParameters.prototype.cancelable;
-
-/**
- * @type {*}
- */
-d3.EventParameters.prototype.detail;
-
-/**
- * @param {string} type
- * @param {!d3.EventParameters |
- *     function(this:Element, ?, number, !NodeList<!Element>):
- *         !d3.EventParameters=} parameters
- */
-d3.selection.prototype.dispatch = function(type, parameters) {};
-
-/**
- * @type {?Event |
- *     {type: string, target: ?, sourceEvent: ?{type: string, target: ?}}}
- */
-d3.event;
-
-/**
- * @param {{type: string, target: ?}} event
- * @param {function(this:T, ...?): R} listener
- * @param {T=} that
- * @param {?Array | Arguments=} args
- * @return {R}
- * @template T, R
- */
-d3.customEvent = function(event, listener, that, args) {};
-
-/**
- * @param {!Element} container
- * @param {!Event} event Mouse, touch or gesture event with clientX and clientY
- *     properties.
- * @return {!Array<number>}
- */
-d3.clientPoint = function(container, event) {};
-
-/**
- * @param {!Element} container
- * @return {!Array<number>}
- */
-d3.mouse = function(container) {};
-
-/**
- * @param {!Element} container
- * @param {!TouchList | string} touchesOrIdentifier
- * @param {string=} identifier
- * @return {?Array<!Array<number>>}
- */
-d3.touch = function(container, touchesOrIdentifier, identifier) {};
-
-/**
- * @param {!Element} container
- * @param {!TouchList=} touches
- * @return {!Array<!Array<number>>}
- */
-d3.touches = function(container, touches) {};
-
-// Control Flow
-
-/**
- * @param {function(this:Element, ?, number, !IArrayLike<!Element>)} callback
- * @return {!d3.selection}
- */
-d3.selection.prototype.each = function(callback) {};
-
-/**
- * @param {!Function} callback
- * @param {...?} var_args
- */
-d3.selection.prototype.call = function(callback, var_args) {};
-
-/**
- * @return {boolean}
- */
-d3.selection.prototype.empty = function() {};
-
-/**
- * @return {!Array<!Element>}
- */
-d3.selection.prototype.nodes = function() {};
-
-/**
- * @return {?Element}
- */
-d3.selection.prototype.node = function() {};
-
-/**
- * @return {number}
- */
-d3.selection.prototype.size = function() {};
-
-// Local Variables
-
-/**
- * @return {!d3.local}
- * @constructor
- * @template T
- */
-d3.local = function() {};
-
-/**
- * @param {!Element} node
- * @param {T} value
- * @return {!Element}
- */
-d3.local.prototype.set = function(node, value) {};
-
-/**
- * @param {!Element} node
- * @return {T | undefined} value
- */
-d3.local.prototype.get = function(node) {};
-
-/**
- * @param {!Element} node
- * @return {boolean}
- */
-d3.local.prototype.remove = function(node) {};
-
-/**
- * @override
- * @return {string}
- */
-d3.local.prototype.toString = function() {};
-
-// Namespaces
-
-/**
- * @param {string} name
- * @return {{local: string, space: string} | string}
- */
-d3.namespace = function(name) {};
-
-/**
- * @type {{
- *   svg: string,
- *   xhtml: string,
- *   xlink: string,
- *   xml: string,
- *   xmlns: string
- * }}
- */
-d3.namespaces;
-
-////////////////////////////////////////////////////////////////////////////////
-// Shapes
-// https://github.com/d3/d3-shape
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-// Arcs
-
-/**
- * @return {!d3.Arc}
- */
-d3.arc = function() {};
-
-/**
- * @typedef {function(...?)}
- */
-d3.Arc;
-
-/**
- * @private {!d3.Arc}
- */
-d3.Arc_;
-
-/**
- * @param {...?} var_args
- * @return {!Array<number>}
- */
-d3.Arc_.centroid = function(var_args) {};
-
-/**
- * @param {number | function(...?): number=} radius
- */
-d3.Arc_.innerRadius = function(radius) {};
-
-/**
- * @param {number | function(...?): number=} radius
- */
-d3.Arc_.outerRadius = function(radius) {};
-
-/**
- * @param {number | function(...?): number=} radius
- */
-d3.Arc_.cornerRadius = function(radius) {};
-
-/**
- * @param {number | function(...?): number=} angle
- */
-d3.Arc_.startAngle = function(angle) {};
-
-/**
- * @param {number | function(...?): number=} angle
- */
-d3.Arc_.endAngle = function(angle) {};
-
-/**
- * @param {number | function(...?): number=} angle
- */
-d3.Arc_.padAngle = function(angle) {};
-
-/**
- * @param {number | function(...?): number=} radius
- */
-d3.Arc_.padRadius = function(radius) {};
-
-/**
- * @param {?CanvasPathMethods=} context
- */
-d3.Arc_.context = function(context) {};
-
-// Pies
-
-/**
- * @return {!d3.Pie}
- */
-d3.pie = function() {};
-
-/**
- * @typedef {function(!Array, ...?): !Array<{
- *   data: ?,
- *   value: number,
- *   index: number,
- *   startAngle: number,
- *   endAngle: number,
- *   padAngle: number
- * }>}
- */
-d3.Pie;
-
-/**
- * @private {!d3.Pie}
- */
-d3.Pie_;
-
-/**
- * @param {number | function(T, number, !Array<T>): number=} value
- * @template T
- */
-d3.Pie_.value = function(value) {};
-
-/**
- * @param {?function(?, ?): number=} compare
- */
-d3.Pie_.sort = function(compare) {};
-
-/**
- * @param {?function(?, ?): number=} compare
- */
-d3.Pie_.sortValues = function(compare) {};
-
-/**
- * @param {number | function(!Array, ...?): number=} angle
- */
-d3.Pie_.startAngle = function(angle) {};
-
-/**
- * @param {number | function(!Array, ...?): number=} angle
- */
-d3.Pie_.endAngle = function(angle) {};
-
-/**
- * @param {number | function(!Array, ...?): number=} angle
- */
-d3.Pie_.padAngle = function(angle) {};
-
-// Lines
-
-/**
- * @return {!d3.Line}
- */
-d3.line = function() {};
-
-/**
- * @typedef {function(!Array)}
- */
-d3.Line;
-
-/**
- * @private {!d3.Line}
- */
-d3.Line_;
-
-/**
- * @param {number | function(T, number, !Array<T>): number=} x
- * @template T
- */
-d3.Line_.x = function(x) {};
-
-/**
- * @param {number | function(T, number, !Array<T>): number=} y
- * @template T
- */
-d3.Line_.y = function(y) {};
-
-/**
- * @param {boolean | function(T, number, !Array<T>): boolean=} defined
- * @template T
- */
-d3.Line_.defined = function(defined) {};
-
-/**
- * @param {function(!CanvasPathMethods): !d3.Curve=} curve
- */
-d3.Line_.curve = function(curve) {};
-
-/**
- * @param {?CanvasPathMethods=} context
- */
-d3.Line_.context = function(context) {};
-
-/**
- * @return {!d3.RadialLine}
- * @deprecated Use d3.lineRadial
- */
-d3.radialLine = function() {};
-
-/**
- * @return {!d3.RadialLine}
- */
-d3.lineRadial = function() {};
-
-/**
- * @typedef {function(!Array)}
- */
-d3.RadialLine;
-
-/**
- * @private {!d3.RadialLine}
- */
-d3.RadialLine_;
-
-/**
- * @param {number | function(T, number, !Array<T>): number=} angle
- * @template T
- */
-d3.RadialLine_.angle = function(angle) {};
-
-/**
- * @param {number | function(T, number, !Array<T>): number=} radius
- * @template T
- */
-d3.RadialLine_.radius = function(radius) {};
-
-/**
- * @param {boolean | function(T, number, !Array<T>): boolean=} defined
- * @template T
- */
-d3.RadialLine_.defined = function(defined) {};
-
-/**
- * @param {function(!CanvasPathMethods): !d3.Curve=} curve
- */
-d3.RadialLine_.curve = function(curve) {};
-
-/**
- * @param {?CanvasPathMethods=} context
- */
-d3.RadialLine_.context = function(context) {};
-
-// Areas
-
-/**
- * @return {!d3.Area}
- */
-d3.area = function() {};
-
-/**
- * @typedef {function(!Array)}
- */
-d3.Area;
-
-/**
- * @private {!d3.Area}
- */
-d3.Area_;
-
-/**
- * @param {number | function(T, number, !Array<T>): number=} x
- * @template T
- */
-d3.Area_.x = function(x) {};
-
-/**
- * @param {number | function(T, number, !Array<T>): number=} x
- * @template T
- */
-d3.Area_.x0 = function(x) {};
-
-/**
- * @param {number | function(T, number, !Array<T>): number=} x
- * @template T
- */
-d3.Area_.x1 = function(x) {};
-
-/**
- * @param {number | function(T, number, !Array<T>): number=} y
- * @template T
- */
-d3.Area_.y = function(y) {};
-
-/**
- * @param {number | function(T, number, !Array<T>): number=} y
- * @template T
- */
-d3.Area_.y0 = function(y) {};
-
-/**
- * @param {number | function(T, number, !Array<T>): number=} y
- * @template T
- */
-d3.Area_.y1 = function(y) {};
-
-/**
- * @param {boolean | function(T, number, !Array<T>): boolean=} defined
- * @template T
- */
-d3.Area_.defined = function(defined) {};
-
-/**
- * @param {function(!CanvasPathMethods): !d3.Curve2d=} curve
- */
-d3.Area_.curve = function(curve) {};
-
-/**
- * @param {?CanvasPathMethods=} context
- */
-d3.Area_.context = function(context) {};
-
-/**
- * @return {!d3.Line}
- */
-d3.Area_.lineX0 = function() {};
-
-/**
- * @return {!d3.Line}
- */
-d3.Area_.lineY0 = function() {};
-
-/**
- * @return {!d3.Line}
- */
-d3.Area_.lineX1 = function() {};
-
-/**
- * @return {!d3.Line}
- */
-d3.Area_.lineY1 = function() {};
-
-/**
- * @return {!d3.RadialArea}
- */
-d3.areaRadial = function() {};
-
-/**
- * @return {!d3.RadialArea}
- * @deprecated Use d3.areaRadial
- */
-d3.radialArea = function() {};
-
-/**
- * @typedef {function(!Array)}
- */
-d3.RadialArea;
-
-/**
- * @private {!d3.RadialArea}
- */
-d3.RadialArea_;
-
-/**
- * @param {number | function(!Array, ...?): number=} angle
- */
-d3.RadialArea_.angle = function(angle) {};
-
-/**
- * @param {number | function(!Array, ...?): number=} angle
- */
-d3.RadialArea_.startAngle = function(angle) {};
-
-/**
- * @param {number | function(!Array, ...?): number=} angle
- */
-d3.RadialArea_.endAngle = function(angle) {};
-
-/**
- * @param {number | function(!Array, ...?): number=} radius
- */
-d3.RadialArea_.radius = function(radius) {};
-
-/**
- * @param {number | function(!Array, ...?): number=} radius
- */
-d3.RadialArea_.innerRadius = function(radius) {};
-
-/**
- * @param {number | function(!Array, ...?): number=} radius
- */
-d3.RadialArea_.outerRadius = function(radius) {};
-
-/**
- * @param {boolean | function(T, number, !Array<T>): boolean=} defined
- * @template T
- */
-d3.RadialArea_.defined = function(defined) {};
-
-/**
- * @param {function(!CanvasPathMethods): !d3.Curve2d=} curve
- */
-d3.RadialArea_.curve = function(curve) {};
-
-/**
- * @param {?CanvasPathMethods=} context
- */
-d3.RadialArea_.context = function(context) {};
-
-/**
- * @return {!d3.RadialLine}
- */
-d3.RadialArea_.lineStartAngle = function() {};
-
-/**
- * @return {!d3.RadialLine}
- */
-d3.RadialArea_.lineInnerRadius = function() {};
-
-/**
- * @return {!d3.RadialLine}
- */
-d3.RadialArea_.lineEndAngle = function() {};
-
-/**
- * @return {!d3.RadialLine}
- */
-d3.RadialArea_.lineOuterRadius = function() {};
-
-// Curves
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveBasis = function(context) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveBasisClosed = function(context) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveBasisOpen = function(context) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve}
- */
-d3.curveBundle = function(context) {};
-
-/**
- * @param {number} beta
- * @return {function(!CanvasPathMethods): !d3.Curve}
- */
-d3.curveBundle.beta = function(beta) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveCardinal = function(context) {};
-
-/**
- * @param {number} tension
- * @return {function(!CanvasPathMethods): !d3.Curve2d}
- */
-d3.curveCardinal.tension = function(tension) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveCardinalClosed = function(context) {};
-
-/**
- * @param {number} tension
- * @return {function(!Object): !d3.Curve2d}
- */
-d3.curveCardinalClosed.tension = function(tension) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveCardinalOpen = function(context) {};
-
-/**
- * @param {number} tension
- * @return {function(!CanvasPathMethods): !d3.Curve2d}
- */
-d3.curveCardinalOpen.tension = function(tension) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveCatmullRom = function(context) {};
-
-/**
- * @param {number} alpha
- * @return {function(!CanvasPathMethods): !d3.Curve2d}
- */
-d3.curveCatmullRom.alpha = function(alpha) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveCatmullRomClosed = function(context) {};
-
-/**
- * @param {number} alpha
- * @return {function(!Object): !d3.Curve2d}
- */
-d3.curveCatmullRomClosed.alpha = function(alpha) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveCatmullRomOpen = function(context) {};
-
-/**
- * @param {number} alpha
- * @return {function(!CanvasPathMethods): !d3.Curve2d}
- */
-d3.curveCatmullRomOpen.alpha = function(alpha) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveLinear = function(context) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveLinearClosed = function(context) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveMonotoneX = function(context) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveMonotoneY = function(context) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveNatural = function(context) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveStep = function(context) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveStepAfter = function(context) {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @return {!d3.Curve2d}
- */
-d3.curveStepBefore = function(context) {};
-
-// Custom Curves
-
-/**
- * @interface
- */
-d3.Curve = function() {};
-
-/**
- * @return {void}
- */
-d3.Curve.prototype.lineStart = function() {};
-
-/**
- * @return {void}
- */
-d3.Curve.prototype.lineEnd = function() {};
-
-/**
- * @param {number} x
- * @param {number} y
- * @return {void}
- */
-d3.Curve.prototype.point = function(x, y) {};
-
-/**
- * @interface
- * @extends {d3.Curve}
- */
-d3.Curve2d = function() {};
-
-/**
- * @return {void}
- */
-d3.Curve2d.prototype.areaStart = function() {};
-
-/**
- * @return {void}
- */
-d3.Curve2d.prototype.areaEnd = function() {};
-
-// Links
-
-/**
- * @return {!d3.LinkShape}
- */
-d3.linkHorizontal = function() {};
-
-/**
- * @return {!d3.LinkShape}
- */
-d3.linkVertical = function() {};
-
-/**
- * @typedef {function(...?)}
- */
-d3.LinkShape;
-
-/**
- * @private {!d3.LinkShape}
- */
-d3.LinkShape_;
-
-/**
- * @param {!Function=} source
- * @return {!Function} Source accessor (0 arguments) or this (1 argument).
- */
-d3.LinkShape_.source = function(source) {};
-
-/**
- * @param {!Function=} target
- * @return {!Function} Target accessor (0 arguments) or this (1 argument).
- */
-d3.LinkShape_.target = function(target) {};
-
-/**
- * @param {!Function=} x
- * @return {!Function} x-accessor (0 arguments) or this (1 argument).
- */
-d3.LinkShape_.x = function(x) {};
-
-/**
- * @param {!Function=} y
- * @return {!Function} y-accessor (0 arguments) or this (1 argument).
- */
-d3.LinkShape_.y = function(y) {};
-
-/**
- * @param {?CanvasPathMethods=} context
- * @return {?} Context (0 arguments) or this (1 argument).
- */
-d3.LinkShape_.context = function(context) {};
-
-/**
- * @return {!d3.RadialLink}
- */
-d3.linkRadial = function() {};
-
-/**
- * @typedef {function(...?)}
- */
-d3.RadialLink;
-
-/**
- * @private {!d3.RadialLink}
- */
-d3.RadialLink_;
-
-/**
- * @param {!Function=} source
- * @return {!Function} Source accessor (0 arguments) or this (1 argument).
- */
-d3.RadialLink_.source = function(source) {};
-
-/**
- * @param {!Function=} target
- * @return {!Function} Target accessor (0 arguments) or this (1 argument).
- */
-d3.RadialLink_.target = function(target) {};
-
-/**
- * @param {!Function=} angle
- * @return {!Function} Angle accessor (0 arguments) or this (1 argument).
- */
-d3.RadialLink_.angle = function(angle) {};
-
-/**
- * @param {!Function=} radius
- * @return {!Function} Radius accessor (0 arguments) or this (1 argument).
- */
-d3.RadialLink_.radius = function(radius) {};
-
-/**
- * @param {?CanvasPathMethods=} context
- * @return {?} Context (0 arguments) or this (1 argument).
- */
-d3.RadialLink_.context = function(context) {};
-
-// Symbols
-
-/**
- * @return {!d3.Symbol}
- */
-d3.symbol = function() {};
-
-/**
- * @typedef {function(...?)}
- */
-d3.Symbol;
-
-/**
- * @private {!d3.Symbol}
- */
-d3.Symbol_;
-
-/**
- * @param {!d3.SymbolType | function(...?): !d3.SymbolType=} type
- */
-d3.Symbol_.type = function(type) {};
-
-/**
- * @param {number | function(...?): number=} size
- */
-d3.Symbol_.size = function(size) {};
-
-/**
- * @param {?CanvasPathMethods=} context
- */
-d3.Symbol_.context = function(context) {};
-
-/**
- * @type {!Array<!d3.SymbolType>}
- */
-d3.symbols;
-
-/**
- * @type {!d3.SymbolType}
- */
-d3.symbolCircle;
-
-/**
- * @type {!d3.SymbolType}
- */
-d3.symbolCross;
-
-/**
- * @type {!d3.SymbolType}
- */
-d3.symbolDiamond;
-
-/**
- * @type {!d3.SymbolType}
- */
-d3.symbolSquare;
-
-/**
- * @type {!d3.SymbolType}
- */
-d3.symbolStar;
-
-/**
- * @type {!d3.SymbolType}
- */
-d3.symbolTriangle;
-
-/**
- * @type {!d3.SymbolType}
- */
-d3.symbolWye;
-
-/**
- * @param {number} angle
- * @param {number} radius
- * @return {!Array<number>}
- */
-d3.pointRadial = function(angle, radius) {};
-
-// Custom Symbol Types
-
-/**
- * @interface
- */
-d3.SymbolType = function() {};
-
-/**
- * @param {!CanvasPathMethods} context
- * @param {number} size
- */
-d3.SymbolType.prototype.draw = function(context, size) {};
-
-// Stacks
-
-/**
- * @constructor
- * @extends {Array<number>}
- */
-d3.SeriesPoint = function() {};
-
-/**
- * @type {number}
- */
-d3.SeriesPoint.prototype.index;
-
-/**
- * @type {?}
- */
-d3.SeriesPoint.prototype.data;
-
-/**
- * @constructor
- * @extends {Array<!d3.SeriesPoint>}
- */
-d3.Series = function() {};
-
-/**
- * @type {?}
- */
-d3.Series.prototype.key;
-
-/**
- * @return {!d3.Stack}
- */
-d3.stack = function() {};
-
-/**
- * @typedef {function(!Array, ...?): !Array<!d3.Series>}
- */
-d3.Stack;
-
-/**
- * @private {!d3.Stack}
- */
-d3.Stack_;
-
-/**
- * @param {!Array | function(!Array, ...?): !Array=} keys
- */
-d3.Stack_.keys = function(keys) {};
-
-/**
- * @param {number | function(?, ?, number, !Array): number=} value
- */
-d3.Stack_.value = function(value) {};
-
-/**
- * @param {?Array<number> | function(!d3.Series): !Array<number>=} order
- */
-d3.Stack_.order = function(order) {};
-
-/**
- * @param {?function(!d3.Series, !Array<number>): void=} offset
- */
-d3.Stack_.offset = function(offset) {};
-
-// Stack Orders
-
-/**
- * @param {!d3.Series} series
- * @return {!Array<number>}
- */
-d3.stackOrderAscending = function(series) {};
-
-/**
- * @param {!d3.Series} series
- * @return {!Array<number>}
- */
-d3.stackOrderDescending = function(series) {};
-
-/**
- * @param {!d3.Series} series
- * @return {!Array<number>}
- */
-d3.stackOrderInsideOut = function(series) {};
-
-/**
- * @param {!d3.Series} series
- * @return {!Array<number>}
- */
-d3.stackOrderNone = function(series) {};
-
-/**
- * @param {!d3.Series} series
- * @return {!Array<number>}
- */
-d3.stackOrderReverse = function(series) {};
-
-// Stack Offsets
-
-/**
- * @param {!d3.Series} series
- * @param {!Array<number>} order
- * @return {void}
- */
-d3.stackOffsetExpand = function(series, order) {};
-
-/**
- * @param {!d3.Series} series
- * @param {!Array<number>} order
- * @return {void}
- */
-d3.stackOffsetDiverging = function(series, order) {};
-
-/**
- * @param {!d3.Series} series
- * @param {!Array<number>} order
- * @return {void}
- */
-d3.stackOffsetNone = function(series, order) {};
-
-/**
- * @param {!d3.Series} series
- * @param {!Array<number>} order
- * @return {void}
- */
-d3.stackOffsetSilhouette = function(series, order) {};
-
-/**
- * @param {!d3.Series} series
- * @param {!Array<number>} order
- * @return {void}
- */
-d3.stackOffsetWiggle = function(series, order) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Time Formats
-// https://github.com/d3/d3-time-format
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @param {string} specifier
- * @return {function((!Date | number)): string}
- */
-d3.timeFormat = function(specifier) {};
-
-/**
- * @param {string} specifier
- * @return {function(string): ?Date}
- */
-d3.timeParse = function(specifier) {};
-
-/**
- * @param {string} specifier
- * @return {function((!Date | number)): string}
- */
-d3.utcFormat = function(specifier) {};
-
-/**
- * @param {string} specifier
- * @return {function(string): ?Date}
- */
-d3.utcParse = function(specifier) {};
-
-/**
- * @type {function((!Date | number)): string}
- */
-d3.isoFormat;
-
-/**
- * @type {function(string): ?Date}
- */
-d3.isoParse;
-
-// Locales
-
-/**
- * @record
- */
-d3.TimeLocaleDefinition = function() {};
-
-/**
- * @type {string}
- */
-d3.TimeLocaleDefinition.prototype.dateTime;
-
-/**
- * @type {string}
- */
-d3.TimeLocaleDefinition.prototype.date;
-
-/**
- * @type {string}
- */
-d3.TimeLocaleDefinition.prototype.time;
-
-/**
- * @type {!Array<string>}
- */
-d3.TimeLocaleDefinition.prototype.periods;
-
-/**
- * @type {!Array<string>}
- */
-d3.TimeLocaleDefinition.prototype.days;
-
-/**
- * @type {!Array<string>}
- */
-d3.TimeLocaleDefinition.prototype.shortDays;
-
-/**
- * @type {!Array<string>}
- */
-d3.TimeLocaleDefinition.prototype.months;
-
-/**
- * @type {!Array<string>}
- */
-d3.TimeLocaleDefinition.prototype.shortMonths;
-
-/**
- * @interface
- */
-d3.TimeLocale = function() {};
-
-/**
- * @param {string} specifier
- * @return {function((!Date | number)): string}
- */
-d3.TimeLocale.prototype.format = function(specifier) {};
-
-/**
- * @param {string} specifier
- * @return {function(string): ?Date}
- */
-d3.TimeLocale.prototype.parse = function(specifier) {};
-
-/**
- * @param {string} specifier
- * @return {function((!Date | number)): string}
- */
-d3.TimeLocale.prototype.utcFormat = function(specifier) {};
-
-/**
- * @param {string} specifier
- * @return {function(string): ?Date}
- */
-d3.TimeLocale.prototype.utcParse = function(specifier) {};
-
-/**
- * @param {!d3.TimeLocaleDefinition} definition
- * @return {!d3.TimeLocale}
- */
-d3.timeFormatLocale = function(definition) {};
-
-/**
- * @param {!d3.TimeLocaleDefinition} definition
- * @return {!d3.TimeLocale}
- */
-d3.timeFormatDefaultLocale = function(definition) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Time Intervals
-// https://github.com/d3/d3-time
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @typedef {function((!Date | number)): !Date}
- */
-d3.Interval;
-
-/**
- * @private {!d3.Interval}
- */
-d3.Interval_;
-
-/**
- * @param {!Date | number} date
- * @return {!Date}
- */
-d3.Interval_.floor = function(date) {};
-
-/**
- * @param {!Date | number} date
- * @return {!Date}
- */
-d3.Interval_.round = function(date) {};
-
-/**
- * @param {!Date | number} date
- * @return {!Date}
- */
-d3.Interval_.ceil = function(date) {};
-
-/**
- * @param {!Date | number} date
- * @param {number} step
- * @return {!Date}
- */
-d3.Interval_.offset = function(date, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.Interval_.range = function(start, stop, step) {};
-
-/**
- * @param {function(!Date): boolean} test
- * @return {!d3.Interval}
- */
-d3.Interval_.filter = function(test) {};
-
-/**
- * @param {number} step
- * @return {!d3.Interval}
- */
-d3.Interval_.every = function(step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} end
- * @return {number}
- */
-d3.Interval_.count = function(start, end) {};
-
-/**
- * @param {function(!Date): void} floor
- * @param {function(!Date, number): void} offset
- * @param {function(!Date, !Date): number=} count
- * @param {function(!Date): number=} field
- * @return {!d3.Interval}
- */
-d3.timeInterval = function(floor, offset, count, field) {};
-
-// Intervals
-
-/**
- * @type {!d3.Interval}
- */
-d3.timeMillisecond;
-
-/**
- * @type {!d3.Interval}
- */
-d3.timeSecond;
-
-/**
- * @type {!d3.Interval}
- */
-d3.timeMinute;
-
-/**
- * @type {!d3.Interval}
- */
-d3.timeHour;
-
-/**
- * @type {!d3.Interval}
- */
-d3.timeDay;
-
-/**
- * @type {!d3.Interval}
- */
-d3.timeWeek;
-
-/**
- * @type {!d3.Interval}
- */
-d3.timeSunday;
-
-/**
- * @type {!d3.Interval}
- */
-d3.timeMonday;
-
-/**
- * @type {!d3.Interval}
- */
-d3.timeTuesday;
-
-/**
- * @type {!d3.Interval}
- */
-d3.timeWednesday;
-
-/**
- * @type {!d3.Interval}
- */
-d3.timeThursday;
-
-/**
- * @type {!d3.Interval}
- */
-d3.timeFriday;
-
-/**
- * @type {!d3.Interval}
- */
-d3.timeSaturday;
-
-/**
- * @type {!d3.Interval}
- */
-d3.timeMonth;
-
-/**
- * @type {!d3.Interval}
- */
-d3.timeYear;
-
-/**
- * @type {!d3.Interval}
- */
-d3.utcMillisecond;
-
-/**
- * @type {!d3.Interval}
- */
-d3.utcSecond;
-
-/**
- * @type {!d3.Interval}
- */
-d3.utcMinute;
-
-/**
- * @type {!d3.Interval}
- */
-d3.utcHour;
-
-/**
- * @type {!d3.Interval}
- */
-d3.utcDay;
-
-/**
- * @type {!d3.Interval}
- */
-d3.utcWeek;
-
-/**
- * @type {!d3.Interval}
- */
-d3.utcSunday;
-
-/**
- * @type {!d3.Interval}
- */
-d3.utcMonday;
-
-/**
- * @type {!d3.Interval}
- */
-d3.utcTuesday;
-
-/**
- * @type {!d3.Interval}
- */
-d3.utcWednesday;
-
-/**
- * @type {!d3.Interval}
- */
-d3.utcThursday;
-
-/**
- * @type {!d3.Interval}
- */
-d3.utcFriday;
-
-/**
- * @type {!d3.Interval}
- */
-d3.utcSaturday;
-
-/**
- * @type {!d3.Interval}
- */
-d3.utcMonth;
-
-/**
- * @type {!d3.Interval}
- */
-d3.utcYear;
-
-// Ranges
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.timeMilliseconds = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.timeSeconds = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.timeMinutes = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.timeHours = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.timeDays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.timeWeeks = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.timeSundays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.timeMondays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.timeTuesdays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.timeWednesdays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.timeThursdays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.timeFridays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.timeSaturdays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.timeMonths = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.timeYears = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.utcMilliseconds = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.utcSeconds = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.utcMinutes = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.utcHours = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.utcDays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.utcWeeks = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.utcSundays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.utcMondays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.utcTuesdays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.utcWednesdays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.utcThursdays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.utcFridays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.utcSaturdays = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.utcMonths = function(start, stop, step) {};
-
-/**
- * @param {!Date | number} start
- * @param {!Date | number} stop
- * @param {number=} step
- * @return {!Array<!Date>}
- */
-d3.utcYears = function(start, stop, step) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Timers
-// https://github.com/d3/d3-timer
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @return {number}
- */
-d3.now = function() {};
-
-/**
- * @param {function(number): void} callback
- * @param {number=} delay
- * @param {number=} time
- * @return {!d3.timer}
- * @constructor
- */
-d3.timer = function(callback, delay, time) {};
-
-/**
- * @param {function(number): void} callback
- * @param {number=} delay
- * @param {number=} time
- * @return {void}
- */
-d3.timer.prototype.restart = function(callback, delay, time) {};
-
-/**
- * @return {void}
- */
-d3.timer.prototype.stop = function() {};
-
-/**
- * @return {void}
- */
-d3.timerFlush = function() {};
-
-/**
- * @param {function(number): void} callback
- * @param {number=} delay
- * @param {number=} time
- * @return {!d3.timer}
- */
-d3.timeout = function(callback, delay, time) {};
-
-/**
- * @param {function(number): void} callback
- * @param {number=} delay
- * @param {number=} time
- * @return {!d3.timer}
- */
-d3.interval = function(callback, delay, time) {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Transitions
-// https://github.com/d3/d3-transition
-////////////////////////////////////////////////////////////////////////////////
-
-// Selecting Elements
-
-/**
- * @param {?string | d3.transition=} nameOrTransition
- * @return {!d3.transition}
- */
-d3.selection.prototype.transition = function(nameOrTransition) {};
-
-/**
- * @param {?string=} name
- * @return {!d3.selection}
- */
-d3.selection.prototype.interrupt = function(name) {};
-
-/**
- * @param {!Element} node
- * @param {?string=} name
- */
-d3.interrupt = function(node, name) {};
-
-/**
- * @param {?string | d3.transition=} nameOrTransition
- * @return {!d3.transition}
- * @constructor
- */
-d3.transition = function(nameOrTransition) {};
-
-/**
- * @param {?string} selector
- * @return {!d3.transition}
- */
-d3.transition.prototype.select = function(selector) {};
-
-/**
- * @param {?string} selector
- * @return {!d3.transition}
- */
-d3.transition.prototype.selectAll = function(selector) {};
-
-/**
- * @param {string |
- *     function(this:Element, ?, number, !IArrayLike<!Element>): boolean} filter
- * @return {!d3.transition}
- */
-d3.transition.prototype.filter = function(filter) {};
-
-/**
- * @param {!d3.transition} other
- * @return {!d3.transition}
- */
-d3.transition.prototype.merge = function(other) {};
-
-/**
- * @return {!d3.transition}
- */
-d3.transition.prototype.transition = function() {};
-
-/**
- * @return {!d3.selection}
- */
-d3.transition.prototype.selection = function() {};
-
-/**
- * @param {!Element} node
- * @param {?string=} name
- * @return {!d3.transition}
- */
-d3.active = function(node, name) {};
-
-// Modifying Elements
-
-/**
- * @param {string} name
- * @param {?string | number |
- *     function(this:Element, ?, number, !IArrayLike<!Element>):
- *         ?(string | number)} value
- * @return {!d3.transition}
- */
-d3.transition.prototype.attr = function(name, value) {};
-
-/**
- * @param {string} name
- * @param {?function(this:Element, ?, number, !IArrayLike<!Element>):
- *     function(number): (string | number)=} value
- */
-d3.transition.prototype.attrTween = function(name, value) {};
-
-/**
- * @param {string} name
- * @param {?string |
- *     function(this:Element, ?, number, !IArrayLike<!Element>): ?string} value
- * @param {?string=} priority
- * @return {!d3.transition}
- */
-d3.transition.prototype.style = function(name, value, priority) {};
-
-/**
- * @param {string} name
- * @param {?function(this:Element, ?, number, !IArrayLike<!Element>):
- *     function(number): string=} value
- * @param {?string=} priority
- */
-d3.transition.prototype.styleTween = function(name, value, priority) {};
-
-/**
- * @param {?string |
- *     function(this:Element, ?, number, !IArrayLike<!Element>): ?string} value
- * @return {!d3.transition}
- */
-d3.transition.prototype.text = function(value) {};
-
-/**
- * @return {!d3.transition}
- */
-d3.transition.prototype.remove = function() {};
-
-/**
- * @param {string} name
- * @param {?function(this:Element, ?, number, !IArrayLike<!Element>):
- *     function(number)=} value
- */
-d3.transition.prototype.tween = function(name, value) {};
-
-// Timing
-
-/**
- * @param {number |
- *     function(this:Element, ?, number, !IArrayLike<!Element>): number=}
- *     value
- */
-d3.transition.prototype.delay = function(value) {};
-
-/**
- * @param {number |
- *     function(this:Element, ?, number, !IArrayLike<!Element>): number=}
- *     value
- */
-d3.transition.prototype.duration = function(value) {};
-
-/**
- * @param {function(number): number=} value
- */
-d3.transition.prototype.ease = function(value) {};
-
-// Control Flow
-
-/**
- * @param {string} typenames
- * @param {?function(this:Element, ?, number, !IArrayLike<!Element>)=}
- *     listener
- * @return {!d3.selection}
- */
-d3.transition.prototype.on = function(typenames, listener) {};
-
-/**
- * @param {function(this:Element, ?, number, !IArrayLike<!Element>)} callback
- * @return {!d3.transition}
- */
-d3.transition.prototype.each = function(callback) {};
-
-/**
- * @param {!Function} callback
- * @param {...?} var_args
- */
-d3.transition.prototype.call = function(callback, var_args) {};
-
-/**
- * @return {boolean}
- */
-d3.transition.prototype.empty = function() {};
-
-/**
- * @return {!Array<!Element>}
- */
-d3.transition.prototype.nodes = function() {};
-
-/**
- * @return {?Element}
- */
-d3.transition.prototype.node = function() {};
-
-/**
- * @return {number}
- */
-d3.transition.prototype.size = function() {};
-
-////////////////////////////////////////////////////////////////////////////////
-// Voronoi Diagrams
-// https://github.com/d3/d3-voronoi
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @return {!d3.Voronoi}
- */
-d3.voronoi = function() {};
-
-/**
- * @typedef {function(!Array): !d3.VoronoiDiagram}
- */
-d3.Voronoi;
-
-/**
- * @private {!d3.Voronoi}
- */
-d3.Voronoi_;
-
-/**
- * @param {function(?): number=} x
- */
-d3.Voronoi_.x = function(x) {};
-
-/**
- * @param {function(?): number=} y
- */
-d3.Voronoi_.y = function(y) {};
-
-/**
- * @param {!Array<!Array<number>>=} extent
- */
-d3.Voronoi_.extent = function(extent) {};
-
-/**
- * @param {!Array<number>=} size
- */
-d3.Voronoi_.size = function(size) {};
-
-/**
- * @param {!Array<T>} data
- * @return {!Array<!d3.VoronoiPolygon<T>>}
- * @template T
- */
-d3.Voronoi_.polygons = function(data) {};
-
-/**
- * @param {!Array<T>} data
- * @return {!Array<!Array<T>>}
- * @template T
- */
-d3.Voronoi_.triangles = function(data) {};
-
-/**
- * @param {!Array<T>} data
- * @return {!Array<!d3.VoronoiLink<T>>}
- * @template T
- */
-d3.Voronoi_.links = function(data) {};
-
-// Voronoi Diagrams
-
-/**
- * @interface
- */
-d3.VoronoiDiagram = function() {};
-
-/**
- * @type {!Array<!d3.VoronoiEdge>}
- */
-d3.VoronoiDiagram.prototype.edges;
-
-/**
- * @type {!Array<!d3.VoronoiCell | undefined>}
- */
-d3.VoronoiDiagram.prototype.cells;
-
-/**
- * @return {!Array<!d3.VoronoiPolygon | undefined>}
- */
-d3.VoronoiDiagram.prototype.polygons = function() {};
-
-/**
- * @return {!Array<!Array>}
- */
-d3.VoronoiDiagram.prototype.triangles = function() {};
-
-/**
- * @return {!Array<!Array<!d3.VoronoiLink<?>>>}
- */
-d3.VoronoiDiagram.prototype.links = function() {};
-
-/**
- * @param {number} x
- * @param {number} y
- * @param {number=} radius
- * @return {?d3.VoronoiSite}
- */
-d3.VoronoiDiagram.prototype.find = function(x, y, radius) {};
-
-/**
- * @record
- */
-d3.VoronoiCell = function() {};
-
-/**
- * @type {!d3.VoronoiSite}
- */
-d3.VoronoiCell.prototype.site;
-
-/**
- * @type {!Array<number>}
- */
-d3.VoronoiCell.prototype.halfedges;
-
-/**
- * @record
- * @extends {IArrayLike<number>}
- */
-d3.VoronoiSite = function() {};
-
-/**
- * @type {number}
- */
-d3.VoronoiSite.prototype.index;
-
-/**
- * @type {?}
- */
-d3.VoronoiSite.prototype.data;
-
-/**
- * @record
- * @extends {IArrayLike<?Array<number>>}
- */
-d3.VoronoiEdge = function() {};
-
-/**
- * @type {!d3.VoronoiSite}
- */
-d3.VoronoiEdge.prototype.left;
-
-/**
- * @type {?d3.VoronoiSite}
- */
-d3.VoronoiEdge.prototype.right;
-
-/**
- * @record
- * @extends {IArrayLike<?Array<number>>}
- * @template T
- */
-d3.VoronoiPolygon = function() {};
-
-/**
- * @type {T}
- */
-d3.VoronoiPolygon.prototype.data;
-
-/**
- * @record
- * @template T
- */
-d3.VoronoiLink = function() {};
-
-/**
- * @type {T}
- */
-d3.VoronoiLink.prototype.source;
-
-/**
- * @type {T}
- */
-d3.VoronoiLink.prototype.target;
-
-////////////////////////////////////////////////////////////////////////////////
-// Zooming
-// https://github.com/d3/d3-zoom
-////////////////////////////////////////////////////////////////////////////////
-
-// API Reference
-
-/**
- * @return {!d3.Zoom}
- */
-d3.zoom = function() {};
-
-/**
- * @typedef {function(!d3.selection): void}
- */
-d3.Zoom;
-
-/**
- * @private {!d3.Zoom}
- */
-d3.Zoom_;
-
-/**
- * @param {!d3.selection | !d3.transition} selection
- * @param {!d3.zoomTransform |
- *     function(this:Element, T, number, !Array<T>): !d3.zoomTransform}
- *     transform
- * @return {void}
- * @template T
- */
-d3.Zoom_.transform = function(selection, transform) {};
-
-/**
- * @param {!d3.selection | !d3.transition} selection
- * @param {number | function(this:Element, T, number, !Array<T>): number} x
- * @param {number | function(this:Element, T, number, !Array<T>): number} y
- * @return {void}
- * @template T
- */
-d3.Zoom_.translateBy = function(selection, x, y) {};
-
-/**
- * @param {!d3.selection | !d3.transition} selection
- * @param {number | function(this:Element, T, number, !Array<T>): number} x
- * @param {number | function(this:Element, T, number, !Array<T>): number} y
- * @return {void}
- * @template T
- */
-d3.Zoom_.translateTo = function(selection, x, y) {};
-
-/**
- * @param {!d3.selection | !d3.transition} selection
- * @param {number | function(this:Element, T, number, !Array<T>): number} k
- * @return {void}
- * @template T
- */
-d3.Zoom_.scaleBy = function(selection, k) {};
-
-/**
- * @param {!d3.selection | !d3.transition} selection
- * @param {number | function(this:Element, T, number, !Array<T>): number} k
- * @return {void}
- * @template T
- */
-d3.Zoom_.scaleTo = function(selection, k) {};
-
-/**
- * @param {function(!d3.zoomTransform,
- *                  !Array<!Array<number>>,
- *                  !Array<!Array<number>>): !d3.zoomTransform=} constrain
- * @return {!Function}
- */
-d3.Zoom_.constrain = function(constrain) {};
-
-/**
- * @param {function(this:Element, T, number, !Array<T>): boolean=} filter
- * @template T
- */
-d3.Zoom_.filter = function(filter) {};
-
-/**
- * @param {function(this:Element): boolean=} touchable
- * @return {!Function}
- */
-d3.Zoom_.touchable = function(touchable) {};
-
-/**
- * @param {function(): number=} delta
- * @return {!Function}
- */
-d3.Zoom_.wheelDelta = function(delta) {};
-
-/**
- * @param {!Array<!Array<number>> |
- *     function(this:Element, T, number, !Array<T>): !Array<!Array<number>>=}
- *     extent
- * @template T
- */
-d3.Zoom_.extent = function(extent) {};
-
-/**
- * @param {!Array<number>=} extent
- */
-d3.Zoom_.scaleExtent = function(extent) {};
-
-/**
- * @param {!Array<!Array<number>>=} extent
- */
-d3.Zoom_.translateExtent = function(extent) {};
-
-/**
- * @param {number=} distance
- * @return {?} Distance (0 arguments) or this (1 argument).
- */
-d3.Zoom_.clickDistance = function(distance) {};
-
-/**
- * @param {number=} duration
- */
-d3.Zoom_.duration = function(duration) {};
-
-/**
- * @param {function(!Array<number>, !Array<number>):
- *     function(number): !Array<number>=} interpolator
- */
-d3.Zoom_.interpolate = function(interpolator) {};
-
-/**
- * @param {string} typenames
- * @param {?function(this:Element, T, number, !Array<T>): void=} listener
- * @template T
- */
-d3.Zoom_.on = function(typenames, listener) {};
-
-// Zoom Events
-
-/**
- * @record
- */
-d3.ZoomEvent = function() {};
-
-/**
- * @type {!d3.Zoom}
- */
-d3.ZoomEvent.prototype.target;
-
-/**
- * @type {string}
- */
-d3.ZoomEvent.prototype.type;
-
-/**
- * @type {!d3.zoomTransform}
- */
-d3.ZoomEvent.prototype.transform;
-
-/**
- * @type {!Event}
- */
-d3.ZoomEvent.prototype.sourceEvent;
-
-// Zoom Transforms
-
-/**
- * @param {!Element} node
- * @return {!d3.zoomTransform}
- * @constructor
- */
-d3.zoomTransform = function(node) {};
-
-/**
- * @const {number}
- */
-d3.zoomTransform.prototype.x;
-
-/**
- * @const {number}
- */
-d3.zoomTransform.prototype.y;
-
-/**
- * @const {number}
- */
-d3.zoomTransform.prototype.k;
-
-/**
- * @param {number} k
- * @return {!d3.zoomTransform}
- */
-d3.zoomTransform.prototype.scale = function(k) {};
-
-/**
- * @param {number} x
- * @param {number} y
- * @return {!d3.zoomTransform}
- */
-d3.zoomTransform.prototype.translate = function(x, y) {};
-
-/**
- * @param {!Array<number>} point
- * @return {!Array<number>}
- */
-d3.zoomTransform.prototype.apply = function(point) {};
-
-/**
- * @param {number} x
- * @return {number}
- */
-d3.zoomTransform.prototype.applyX = function(x) {};
-
-/**
- * @param {number} y
- * @return {number}
- */
-d3.zoomTransform.prototype.applyY = function(y) {};
-
-/**
- * @param {!Array<number>} point
- * @return {!Array<number>}
- */
-d3.zoomTransform.prototype.invert = function(point) {};
-
-/**
- * @param {number} x
- * @return {number}
- */
-d3.zoomTransform.prototype.invertX = function(x) {};
-
-/**
- * @param {number} y
- * @return {number}
- */
-d3.zoomTransform.prototype.invertY = function(y) {};
-
-/**
- * @param {function(?): ?} x Invertible continuous scale.
- * @return {function(?): ?}
- */
-d3.zoomTransform.prototype.rescaleX = function(x) {};
-
-/**
- * @param {function(?): ?} y Invertible continuous scale.
- * @return {function(?): ?}
- */
-d3.zoomTransform.prototype.rescaleY = function(y) {};
-
-/**
- * @override
- * @return {string}
- */
-d3.zoomTransform.prototype.toString = function() {};
-
-/**
- * @type {!d3.zoomTransform}
- */
-d3.zoomIdentity;
diff --git a/third_party/jdk/BUILD.gn b/third_party/jdk/BUILD.gn
index b6fb2b0..fba5350 100644
--- a/third_party/jdk/BUILD.gn
+++ b/third_party/jdk/BUILD.gn
@@ -12,6 +12,7 @@
 group("java_data") {
   data = [
     "current/bin/java",
+    "current/bin/jcmd",
     "current/conf/",
     "current/jmods/",
     "current/lib/",
diff --git a/third_party/libxslt/README.chromium b/third_party/libxslt/README.chromium
index a225d68..93489c3 100644
--- a/third_party/libxslt/README.chromium
+++ b/third_party/libxslt/README.chromium
@@ -1,6 +1,6 @@
 Name: libxslt
 URL: http://xmlsoft.org/XSLT
-Version: f80ae929fa9e80d66d4c42108c6fb2456ce14b8b
+Version: 677b2e8fe8187f3ba981dc97f65e75fec2dec62c
 CPEPrefix: cpe:/a:xmlsoft:libxslt:1.1.37
 Security Critical: yes
 License: MIT
diff --git a/third_party/libxslt/src/libxslt/attrvt.c b/third_party/libxslt/src/libxslt/attrvt.c
index 6157fcd..9d74a81b 100644
--- a/third_party/libxslt/src/libxslt/attrvt.c
+++ b/third_party/libxslt/src/libxslt/attrvt.c
@@ -154,10 +154,9 @@
     if (avt->nb_seg >= avt->max_seg) {
         size_t size = sizeof(xsltAttrVT) +
                       (avt->max_seg + MAX_AVT_SEG) * sizeof(void *);
-	xsltAttrVTPtr tmp = (xsltAttrVTPtr) xmlRealloc(avt, size);
-	if (tmp == NULL)
+	avt = (xsltAttrVTPtr) xmlRealloc(avt, size);
+	if (avt == NULL)
 	    return NULL;
-        avt = tmp;
 	memset(&avt->segments[avt->nb_seg], 0, MAX_AVT_SEG*sizeof(void *));
 	avt->max_seg += MAX_AVT_SEG;
     }
@@ -181,7 +180,7 @@
     xmlChar *ret = NULL;
     xmlChar *expr = NULL;
     xmlXPathCompExprPtr comp = NULL;
-    xsltAttrVTPtr avt;
+    xsltAttrVTPtr avt, tmp;
     int i = 0, lastavt = 0;
 
     if ((style == NULL) || (attr == NULL) || (attr->children == NULL))
@@ -245,8 +244,9 @@
 		str = cur;
 		if (avt->nb_seg == 0)
 		    avt->strstart = 1;
-		if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
+		if ((tmp = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
 		    goto error;
+                avt = tmp;
 		ret = NULL;
 		lastavt = 0;
 	    }
@@ -290,17 +290,19 @@
 		if (avt->nb_seg == 0)
 		    avt->strstart = 0;
 		if (lastavt == 1) {
-		    if ((avt = xsltSetAttrVTsegment(avt, NULL)) == NULL) {
+		    if ((tmp = xsltSetAttrVTsegment(avt, NULL)) == NULL) {
                         xsltTransformError(NULL, style, attr->parent,
                                            "out of memory\n");
 		        goto error;
                     }
+                    avt = tmp;
 		}
-		if ((avt = xsltSetAttrVTsegment(avt, (void *) comp)) == NULL) {
+		if ((tmp = xsltSetAttrVTsegment(avt, (void *) comp)) == NULL) {
                     xsltTransformError(NULL, style, attr->parent,
                                        "out of memory\n");
 		    goto error;
                 }
+                avt = tmp;
 		lastavt = 1;
 		xmlFree(expr);
 		expr = NULL;
@@ -329,8 +331,9 @@
 	str = cur;
 	if (avt->nb_seg == 0)
 	    avt->strstart = 1;
-	if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
+	if ((tmp = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
 	    goto error;
+        avt = tmp;
 	ret = NULL;
     }
 
diff --git a/third_party/libxslt/src/libxslt/numbers.c b/third_party/libxslt/src/libxslt/numbers.c
index e0ae625..1764abb 100644
--- a/third_party/libxslt/src/libxslt/numbers.c
+++ b/third_party/libxslt/src/libxslt/numbers.c
@@ -965,6 +965,7 @@
     xmlChar *the_format, *prefix = NULL, *suffix = NULL;
     xmlChar *nprefix, *nsuffix = NULL;
     int	    prefix_length, suffix_length = 0, nprefix_length, nsuffix_length;
+    int     exp10;
     double  scale;
     int	    j, len = 0;
     int     self_grouping_len;
@@ -1303,7 +1304,18 @@
 
     /* Round to n digits */
     number = fabs(number);
-    scale = pow(10.0, (double)(format_info.frac_digits + format_info.frac_hash));
+    exp10 = format_info.frac_digits + format_info.frac_hash;
+    /* DBL_MAX_10_EXP should be 308 on IEEE platforms. */
+    if (exp10 > DBL_MAX_10_EXP) {
+        if (format_info.frac_digits > DBL_MAX_10_EXP) {
+            format_info.frac_digits = DBL_MAX_10_EXP;
+            format_info.frac_hash = 0;
+        } else {
+            format_info.frac_hash = DBL_MAX_10_EXP - format_info.frac_digits;
+        }
+        exp10 = DBL_MAX_10_EXP;
+    }
+    scale = pow(10.0, (double) exp10);
     number += .5 / scale;
     number -= fmod(number, 1 / scale);
 
diff --git a/third_party/metrics_proto/README.chromium b/third_party/metrics_proto/README.chromium
index 986f66d3..4505666 100644
--- a/third_party/metrics_proto/README.chromium
+++ b/third_party/metrics_proto/README.chromium
@@ -1,8 +1,8 @@
 Name: Metrics Protos
 Short Name: metrics_proto
 URL: This is the canonical public repository
-Version: 523818867
-Date: 2023/04/12 UTC
+Version: 524292468
+Date: 2023/04/14 UTC
 License: BSD
 Security Critical: Yes
 
diff --git a/third_party/metrics_proto/omnibox_event.proto b/third_party/metrics_proto/omnibox_event.proto
index 637c037..33132bc 100644
--- a/third_party/metrics_proto/omnibox_event.proto
+++ b/third_party/metrics_proto/omnibox_event.proto
@@ -581,6 +581,7 @@
     REMOTE_ZERO_SUGGEST_FEATURE = 7;
     SHORTCUT_BOOST = 8;
     REMOTE_SECONDARY_ZERO_SUGGEST = 9;
+    ML_URL_SCORING = 10;
   }
   // The set of features triggered in the most recent query. Each element is a
   // value of `Features` enum.
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium
index 89a1d6bd..aad0028 100644
--- a/third_party/nearby/README.chromium
+++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@
 Name: Nearby Connections Library
 Short Name: Nearby
 URL: https://github.com/google/nearby
-Version: 00bba362199fbe4d462775e10d2e825a9ee772ce
+Version: 6cdc9890b5f83ff731a6363a785272bd1a75f87e
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/webgpu-cts/ts_sources.txt b/third_party/webgpu-cts/ts_sources.txt
index f0bb289..25c7503 100644
--- a/third_party/webgpu-cts/ts_sources.txt
+++ b/third_party/webgpu-cts/ts_sources.txt
@@ -240,7 +240,6 @@
 src/webgpu/api/validation/capability_checks/limits/maxComputeWorkgroupsPerDimension.spec.ts
 src/webgpu/api/validation/capability_checks/limits/maxDynamicStorageBuffersPerPipelineLayout.spec.ts
 src/webgpu/api/validation/capability_checks/limits/maxDynamicUniformBuffersPerPipelineLayout.spec.ts
-src/webgpu/api/validation/capability_checks/limits/maxFragmentCombinedOutputResources.spec.ts
 src/webgpu/api/validation/capability_checks/limits/maxInterStageShaderComponents.spec.ts
 src/webgpu/api/validation/capability_checks/limits/maxInterStageShaderVariables.spec.ts
 src/webgpu/api/validation/capability_checks/limits/maxSampledTexturesPerShaderStage.spec.ts
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index affd2440..db040102 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -1058,6 +1058,10 @@
   "ui/chromeos/resources/ui_chromeos_resources.grd": {
     "structures": [4660],
   },
+  "<(SHARED_INTERMEDIATE_DIR)/ui/chromeos/styles/cros_typography_resources.grd": {
+    "META": {"sizes": {"includes": [5],}},
+    "includes": [4678],
+  },
   "ui/chromeos/ui_chromeos_strings.grd": {
     "messages": [4680],
   },
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 4aa98fffe..58517931 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -1004,6 +1004,8 @@
       'android-arm32-pgo': 'official_goma_android_arm32_pgo',
       'android-arm64-pgo': 'official_goma_android_arm64_pgo',
       'lacros-amd64-generic-pgo': 'official_reclient_lacros_amd64_pgo',
+      'lacros-arm-generic-pgo': 'official_reclient_lacros_arm_pgo',
+      'lacros-arm64-generic-pgo': 'official_reclient_lacros_arm64_pgo',
       'linux-pgo': 'official_goma_linux_pgo',
       'mac-arm-pgo': 'official_goma_mac_arm_pgo',
       'mac-pgo': 'official_goma_mac_pgo',
diff --git a/tools/mb/mb_config_expectations/tryserver.chrome.pgo.json b/tools/mb/mb_config_expectations/tryserver.chrome.pgo.json
index 0809624..aebf1fa 100644
--- a/tools/mb/mb_config_expectations/tryserver.chrome.pgo.json
+++ b/tools/mb/mb_config_expectations/tryserver.chrome.pgo.json
@@ -49,6 +49,42 @@
       "use_thin_lto": true
     }
   },
+  "lacros-arm-generic-pgo": {
+    "args_file": "//build/args/chromeos/arm-generic-crostoolchain.gni",
+    "gn_args": {
+      "chrome_pgo_phase": 1,
+      "chromeos_is_browser_only": true,
+      "dcheck_always_on": false,
+      "is_cfi": true,
+      "is_chrome_branded": true,
+      "is_chromeos_device": true,
+      "is_debug": false,
+      "is_official_build": true,
+      "is_on_release_branch": true,
+      "symbol_level": 0,
+      "target_os": "chromeos",
+      "use_remoteexec": true,
+      "use_thin_lto": true
+    }
+  },
+  "lacros-arm64-generic-pgo": {
+    "args_file": "//build/args/chromeos/arm64-generic-crostoolchain.gni",
+    "gn_args": {
+      "chrome_pgo_phase": 1,
+      "chromeos_is_browser_only": true,
+      "dcheck_always_on": false,
+      "is_cfi": true,
+      "is_chrome_branded": true,
+      "is_chromeos_device": true,
+      "is_debug": false,
+      "is_official_build": true,
+      "is_on_release_branch": true,
+      "symbol_level": 0,
+      "target_os": "chromeos",
+      "use_remoteexec": true,
+      "use_thin_lto": true
+    }
+  },
   "linux-pgo": {
     "gn_args": {
       "chrome_pgo_phase": 1,
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 1c86ddb..c889f11 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -5513,6 +5513,28 @@
   <description>Recorded when the user adds a bookmark.</description>
 </action>
 
+<action name="Bookmarks.AddedFromSidePanel">
+  <owner>emshack@chromium.org</owner>
+  <owner>chrome-desktop-ui-sea@google.com</owner>
+  <description>
+    Recorded when the user adds a bookmark from the side panel.
+  </description>
+</action>
+
+<action name="Bookmarks.FolderAdded">
+  <owner>emshack@chromium.org</owner>
+  <owner>chrome-desktop-ui-sea@google.com</owner>
+  <description>Recorded when the user adds a bookmark folder.</description>
+</action>
+
+<action name="Bookmarks.FolderAddedFromSidePanel">
+  <owner>emshack@chromium.org</owner>
+  <owner>chrome-desktop-ui-sea@google.com</owner>
+  <description>
+    Recorded when the user adds a bookmark folder from the side panel.
+  </description>
+</action>
+
 <action name="Bookmarks.Opened">
   <owner>wylieb@chromium.org</owner>
   <owner>chrome-collections@google.com</owner>
@@ -7002,6 +7024,36 @@
   </description>
 </action>
 
+<action name="ContentSuggestions.Feed.SignIn.ShowSignInDisableToastFromFeed">
+  <owner>sczs@google.com</owner>
+  <owner>tinazwang@chromium.org</owner>
+  <owner>feed@chromium.org</owner>
+  <description>
+    The user clicks the feed personalization control and triggered a sign-in
+    disabled message to be shown.
+  </description>
+</action>
+
+<action name="ContentSuggestions.Feed.SignIn.ShowSignInOnlyFlowFromFeed">
+  <owner>sczs@google.com</owner>
+  <owner>tinazwang@chromium.org</owner>
+  <owner>feed@chromium.org</owner>
+  <description>
+    The user clicks the feed personalization control and triggered a sign-in
+    only flow to be shown.
+  </description>
+</action>
+
+<action name="ContentSuggestions.Feed.SignIn.ShowSyncnHalfSheetFromFeed">
+  <owner>sczs@google.com</owner>
+  <owner>tinazwang@chromium.org</owner>
+  <owner>feed@chromium.org</owner>
+  <description>
+    The user clicks the feed personalization control and triggered a sign-in
+    half sheet to be shown.
+  </description>
+</action>
+
 <action name="ContentSuggestions.Feed.WebFeed.Selected">
   <owner>adamta@google.com</owner>
   <owner>sczs@chromium.org</owner>
@@ -36939,6 +36991,8 @@
       label="For AutoDarkUserEducationMessage feature."/>
   <suffix name="AutoDarkUserEducationMessageOptIn"
       label="For AutoDarkUserEducationMessageOptIn feature."/>
+  <suffix name="AutofillExternalAccountProfileSuggestion"
+      label="For AutofillExternalAccountProfileSuggestion feature."/>
   <suffix name="AutofillVirtualCardSuggestion"
       label="For AutofillVirtualCardSuggestion feature."/>
   <suffix name="BadgedReadingList" label="For BadgedReadingList feature."/>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 1a568bc..d162372 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3117,6 +3117,9 @@
   <int value="73" label="RESTRICT_SENSITIVE_WEB_CONTENT">
     WebSettingsCompat#enableRestrictSensitiveWebContent()
   </int>
+  <int value="74" label="JS_REPLY_POST_MESSAGE_WITH_PAYLOAD">
+    JsReplyProxy#postMessageWithPayload(WebMessagePayload)
+  </int>
 </enum>
 
 <enum name="AnnouncementNotificationEvent">
@@ -11828,6 +11831,13 @@
   <int value="2" label="Edited by another source"/>
 </enum>
 
+<enum name="BookmarkFolderType">
+  <int value="0" label="Bookmarks Bar"/>
+  <int value="1" label="Other Bookmarks"/>
+  <int value="2" label="Mobile Bookmarks"/>
+  <int value="3" label="User Generated Folder"/>
+</enum>
+
 <enum name="BookmarkGUIDSource">
   <summary>
     Whether a GUID came from BookmarkSpecifics, or, in case it was missing,
@@ -12618,6 +12628,11 @@
   <int value="1" label="Has distilled data"/>
 </enum>
 
+<enum name="BooleanHasKey">
+  <int value="0" label="Lacks key"/>
+  <int value="1" label="Has key"/>
+</enum>
+
 <enum name="BooleanHasNoSniff">
   <int value="0" label="Does not have nosniff"/>
   <int value="1" label="Has nosniff"/>
@@ -17742,6 +17757,7 @@
   <int value="-802" label="DNS_SERVER_FAILED"/>
   <int value="-801" label="DNS_SERVER_REQUIRES_TCP"/>
   <int value="-800" label="DNS_MALFORMED_RESPONSE"/>
+  <int value="-716" label="CERT_VERIFIER_CHANGED"/>
   <int value="-715" label="CHANNEL_ID_IMPORT_FAILED"/>
   <int value="-714" label="CERT_DATABASE_CHANGED"/>
   <int value="-713" label="SELF_SIGNED_CERT_GENERATION_FAILED"/>
@@ -17991,6 +18007,7 @@
   <int value="-1" label="IO_PENDING"/>
   <int value="100" label="100: Continue"/>
   <int value="101" label="101: Switching Protocols"/>
+  <int value="103" label="103: Early Hints"/>
   <int value="200" label="200: OK"/>
   <int value="201" label="201: Created"/>
   <int value="202" label="202: Accepted"/>
@@ -18006,6 +18023,7 @@
   <int value="305" label="305: Use Proxy"/>
   <int value="306" label="306: (Unused)"/>
   <int value="307" label="307: Temporary Redirect"/>
+  <int value="308" label="308: Permanent Redirect"/>
   <int value="400" label="400: Bad Request"/>
   <int value="401" label="401: Unauthorized"/>
   <int value="402" label="402: Payment Required"/>
@@ -18025,6 +18043,7 @@
   <int value="416" label="416: Requested Range Not Satisfiable"/>
   <int value="417" label="417: Expectation Failed"/>
   <int value="418" label="418: I'm a teapot"/>
+  <int value="422" label="422: Unprocessable Content"/>
   <int value="425" label="425: Too Early Experimental"/>
   <int value="429" label="429: Too Many Requests"/>
   <int value="500" label="500: Internal Server Error"/>
@@ -42663,6 +42682,13 @@
   <int value="1" label="Feedback tapped on page from card"/>
 </enum>
 
+<enum name="FeedSignInUI">
+  <int value="0" label="Showing a sign-in half sheet triggered from feed."/>
+  <int value="1" label="Showing a sign-in only flow triggered from feed."/>
+  <int value="2"
+      label="Showing a sign-in disabled snackbar triggered from feed."/>
+</enum>
+
 <enum name="FeedSortType">
   <int value="0" label="Unspecified"/>
   <int value="1" label="Grouped by publisher"/>
@@ -50846,7 +50872,6 @@
 <enum name="HttpResponseCode">
   <int value="100" label="100: Continue"/>
   <int value="101" label="101: Switching Protocols"/>
-  <int value="102" label="102: Processing"/>
   <int value="103" label="103: Early Hints"/>
   <int value="200" label="200: OK"/>
   <int value="201" label="201: Created"/>
@@ -50863,6 +50888,7 @@
   <int value="305" label="305: Use Proxy"/>
   <int value="306" label="306: (Unused)"/>
   <int value="307" label="307: Temporary Redirect"/>
+  <int value="308" label="308: Permanent Redirect"/>
   <int value="400" label="400: Bad Request"/>
   <int value="401" label="401: Unauthorized"/>
   <int value="402" label="402: Payment Required"/>
@@ -50881,6 +50907,9 @@
   <int value="415" label="415: Unsupported Media Type"/>
   <int value="416" label="416: Requested Range Not Satisfiable"/>
   <int value="417" label="417: Expectation Failed"/>
+  <int value="418" label="418: I'm a teapot"/>
+  <int value="422" label="422: Unprocessable Content"/>
+  <int value="425" label="425: Too Early Experimental"/>
   <int value="429" label="429: Too Many Requests"/>
   <int value="500" label="500: Internal Server Error"/>
   <int value="501" label="501: Not Implemented"/>
@@ -59330,6 +59359,7 @@
   <int value="-1449358747" label="RemoveStatusBarInWebApps:enabled"/>
   <int value="-1448511207" label="UseMessagesStagingUrl:disabled"/>
   <int value="-1448094672" label="CCTBrandTransparency:disabled"/>
+  <int value="-1448056519" label="MlUrlScoring:enabled"/>
   <int value="-1447314734" label="QuerySearchBurnInPeriod:enabled"/>
   <int value="-1447147245" label="VideoPlayerNativeControls:enabled"/>
   <int value="-1446625028" label="CrostiniUsbAllowUnsupported:enabled"/>
@@ -62673,6 +62703,7 @@
   <int value="359896413" label="SplitPartiallyOccludedQuads:disabled"/>
   <int value="359918746"
       label="AutofillEnableVirtualCardsRiskBasedAuthentication:disabled"/>
+  <int value="359941469" label="Cr2023ActionChips:disabled"/>
   <int value="360391863" label="NTPOfflineBadge:enabled"/>
   <int value="360599302" label="enable-gpu-rasterization"/>
   <int value="360697704" label="UseSyncInvalidations:enabled"/>
@@ -62859,6 +62890,7 @@
   <int value="458410433" label="disable-views-rect-based-targeting"/>
   <int value="460136092" label="MidiManagerAndroid:disabled"/>
   <int value="460475728" label="wake-on-wifi-packet"/>
+  <int value="460478987" label="Cr2023ActionChips:enabled"/>
   <int value="461523297"
       label="UsernameFirstFlowFallbackCrowdsourcing:enabled"/>
   <int value="461641589" label="WebAppWindowControlsOverlay:disabled"/>
@@ -62979,6 +63011,7 @@
   <int value="533115840"
       label="HoldingSpaceInProgressDownloadsIntegration:enabled"/>
   <int value="533814676" label="CCTResizableForFirstParties:enabled"/>
+  <int value="534825129" label="ReducedWifiPollingInterval:disabled"/>
   <int value="535131384" label="OmniboxTailSuggestions:enabled"/>
   <int value="535194142" label="TemporaryHoldingSpacePreviews:enabled"/>
   <int value="535976218" label="enable-plugin-power-saver"/>
@@ -63444,6 +63477,7 @@
   <int value="779086132" label="enable-data-reduction-proxy-alt"/>
   <int value="779703052" label="ChromeOSAmbientMode:enabled"/>
   <int value="779849093" label="OfflinePagesCTSuppressNotifications:disabled"/>
+  <int value="779990030" label="MlUrlScoring:disabled"/>
   <int value="780092266" label="LauncherNudgeSessionReset:disabled"/>
   <int value="780177218"
       label="AutofillEnableOfferNotificationForPromoCodes:disabled"/>
@@ -64272,6 +64306,7 @@
   <int value="1243704644" label="ArcFixupWindowFeature:enabled"/>
   <int value="1243890754" label="ForbidSyncXHRInPageDismissal:disabled"/>
   <int value="1244050764" label="LauncherPulsingBlocksRefresh:disabled"/>
+  <int value="1244972195" label="ReducedWifiPollingInterval:enabled"/>
   <int value="1245889469" label="enable-surface-worker"/>
   <int value="1246022849"
       label="MessagesForAndroidAutoDarkWebContents:disabled"/>
@@ -64383,6 +64418,7 @@
   <int value="1298981651" label="disable-new-task-manager"/>
   <int value="1299336534"
       label="AutofillSuppressCreditCardSaveForAssistant:disabled"/>
+  <int value="1299784522" label="EmptyStates:disabled"/>
   <int value="1300282719" label="OfflinePagesBackgroundLoading:enabled"/>
   <int value="1300753556" label="ManualPasswordGenerationAndroid:disabled"/>
   <int value="1300900599" label="ArcUpdateO4CListViaA2C2:enabled"/>
@@ -65636,6 +65672,7 @@
   <int value="1972232935" label="DisplayMoveWindowAccels:enabled"/>
   <int value="1972720114" label="WebPaymentsJustInTimePaymentApp:enabled"/>
   <int value="1973376634" label="WebXRMultiGpu:enabled"/>
+  <int value="1974013089" label="EmptyStates:enabled"/>
   <int value="1974565950" label="enable-experimental-accessibility-labels"/>
   <int value="1974776131" label="MediaFeeds:disabled"/>
   <int value="1975327115" label="NewBaseUrlInheritanceBehavior:disabled"/>
@@ -66638,6 +66675,8 @@
   <int value="12" label="Non-invertible transform (obsolete)"/>
   <int value="13" label="Blocking wheel event handler region"/>
   <int value="14" label="Blocking touch event handler region"/>
+  <int value="15" label="Prefer non-composited scrolling"/>
+  <int value="16" label="Background needs repaint on scroll"/>
 </enum>
 
 <enum name="MakeChromeDefaultResult">
@@ -71511,6 +71550,7 @@
   <int value="713" label="SELF_SIGNED_CERT_GENERATION_FAILED"/>
   <int value="714" label="CERT_DATABASE_CHANGED"/>
   <int value="715" label="CHANNEL_ID_IMPORT_FAILED"/>
+  <int value="716" label="CERT_VERIFIER_CHANGED"/>
   <int value="800" label="DNS_MALFORMED_RESPONSE"/>
   <int value="801" label="DNS_SERVER_REQUIRES_TCP"/>
   <int value="802" label="DNS_SERVER_FAILED"/>
@@ -81426,6 +81466,22 @@
   <int value="2" label="Serialization error"/>
 </enum>
 
+<enum name="PersonalizationDynamicColorColorScheme">
+  <int value="0" label="kStatic"/>
+  <int value="1" label="kTonalSpot"/>
+  <int value="2" label="kNeutral"/>
+  <int value="3" label="kExpressive"/>
+  <int value="4" label="kVibrant"/>
+</enum>
+
+<enum name="PersonalizationDynamicColorStaticColor">
+  <int value="0" label="kUnknown"/>
+  <int value="1" label="kGoogleBlue"/>
+  <int value="2" label="kLightPink"/>
+  <int value="3" label="kDarkGreen"/>
+  <int value="4" label="kLightPurple"/>
+</enum>
+
 <enum name="PersonalizationEntryPoint">
   <int value="0" label="Home Screen"/>
   <int value="1" label="System Tray"/>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 5549c5c..490eabe 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -4420,6 +4420,26 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.Personalization.DynamicColor.ColorSchemeButton"
+    enum="PersonalizationDynamicColorColorScheme" expires_after="2024-04-05">
+  <owner>ericamlee@google.com</owner>
+  <owner>assistive-eng@google.com</owner>
+  <summary>
+    Emitted when a user clicks a button to choose a color scheme for dynamic
+    color in personalization hub.
+  </summary>
+</histogram>
+
+<histogram name="Ash.Personalization.DynamicColor.StaticColorButton"
+    enum="PersonalizationDynamicColorStaticColor" expires_after="2024-04-03">
+  <owner>ericamlee@google.com</owner>
+  <owner>assistive-eng@google.com</owner>
+  <summary>
+    Emitted when a user clicks a static color button for dynamic color in
+    personalization hub.
+  </summary>
+</histogram>
+
 <histogram name="Ash.Personalization.DynamicColor.ToggleButton"
     enum="BooleanEnabled" expires_after="2024-04-03">
   <owner>ericamlee@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml
index 5d42cb527..0ebd5d3 100644
--- a/tools/metrics/histograms/metadata/autofill/histograms.xml
+++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -1240,15 +1240,21 @@
 
     2. a {CardIssuer} selected from Autofill suggestions did not have metadata
 
-    It is emitted every time Autofill suggestions shown or selected have an
-    issuer id.
+    Histograms without &quot;Once&quot; are logged every time Autofill
+    suggestions that are shown or selected have an issuer id. Histograms with
+    &quot;Once&quot; are logged once per page load.
   </summary>
   <token key="CardIssuer" variants="Autofill.CreditCardIssuerId"/>
   <token key="FormEventWithMetadata">
     <variant name="SelectedWithMetadata"
         summary="A card with issuer id was selected"/>
+    <variant name="SelectedWithMetadataOnce"
+        summary="A card with issuer id was selected, logged once per page
+                 load"/>
     <variant name="ShownWithMetadata"
         summary="A card with issuer id was shown"/>
+    <variant name="ShownWithMetadataOnce"
+        summary="A card with issuer id was shown, logged once per page load"/>
   </token>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/bookmarks/histograms.xml b/tools/metrics/histograms/metadata/bookmarks/histograms.xml
index 2966addc..9255c52a 100644
--- a/tools/metrics/histograms/metadata/bookmarks/histograms.xml
+++ b/tools/metrics/histograms/metadata/bookmarks/histograms.xml
@@ -436,6 +436,17 @@
   </summary>
 </histogram>
 
+<histogram name="Bookmarks.ParentFolderType" enum="BookmarkFolderType"
+    expires_after="2023-12-31">
+  <owner>emshack@chromium.org</owner>
+  <owner>chrome-desktop-ui-sea@google.com</owner>
+  <component>UI&gt;Browser&gt;Bookmarks</component>
+  <summary>
+    This histogram records the parent folder added to whenever a bookmark is
+    created or moved.
+  </summary>
+</histogram>
+
 <histogram name="Bookmarks.ReadingList.NumberOfItems" units="items"
     expires_after="2023-08-27">
   <owner>shaktisahu@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml
index 85357c7..a56a38c 100644
--- a/tools/metrics/histograms/metadata/chromeos/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -2400,6 +2400,56 @@
 </histogram>
 
 <histogram
+    name="ChromeOS.Settings.Device.Keyboard.{KeyboardType}.Modifiers.{Modifier}RemappedTo.Changed"
+    enum="KeyboardModifierRemappingKeys" expires_after="2024-03-22">
+  <owner>dpad@google.com</owner>
+  <owner>cros-peripherals@google.com</owner>
+  <summary>
+    Records the configured modifier remapping for the {Modifier} key when the
+    {KeyboardType} keyboard is updated.
+  </summary>
+  <token key="KeyboardType">
+    <variant name="External"/>
+    <variant name="ExternalChromeOs"/>
+    <variant name="Internal"/>
+  </token>
+  <token key="Modifier">
+    <variant name="Alt"/>
+    <variant name="Assistant"/>
+    <variant name="Backspace"/>
+    <variant name="CapsLock"/>
+    <variant name="Control"/>
+    <variant name="Escape"/>
+    <variant name="Meta"/>
+  </token>
+</histogram>
+
+<histogram
+    name="ChromeOS.Settings.Device.Keyboard.{KeyboardType}.Modifiers.{Modifier}RemappedTo.Initial"
+    enum="KeyboardModifierRemappingKeys" expires_after="2024-03-22">
+  <owner>dpad@google.com</owner>
+  <owner>cros-peripherals@google.com</owner>
+  <summary>
+    Records the configured modifier remapping for the {Modifier} key when the
+    {KeyboardType} keyboard is first initialized.
+  </summary>
+  <token key="KeyboardType">
+    <variant name="External"/>
+    <variant name="ExternalChromeOs"/>
+    <variant name="Internal"/>
+  </token>
+  <token key="Modifier">
+    <variant name="Alt"/>
+    <variant name="Assistant"/>
+    <variant name="Backspace"/>
+    <variant name="CapsLock"/>
+    <variant name="Control"/>
+    <variant name="Escape"/>
+    <variant name="Meta"/>
+  </token>
+</histogram>
+
+<histogram
     name="ChromeOS.Settings.Device.Keyboard.{KeyboardType}.{KeyboardSetting}.Changed"
     enum="Boolean" expires_after="2024-03-22">
   <owner>dpad@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/content/histograms.xml b/tools/metrics/histograms/metadata/content/histograms.xml
index 528e1c4..c100313a 100644
--- a/tools/metrics/histograms/metadata/content/histograms.xml
+++ b/tools/metrics/histograms/metadata/content/histograms.xml
@@ -982,6 +982,17 @@
   </summary>
 </histogram>
 
+<histogram name="ContentSuggestions.Feed.FeedSignInUI" enum="FeedSignInUI"
+    expires_after="2023-10-15">
+  <owner>sczs@chromium.org</owner>
+  <owner>tinazwang@chromium.org</owner>
+  <owner>feed@chromium.org</owner>
+  <summary>
+    Recorded when a signed out user triggered a sign-in related UI from feed
+    personalization control. iOS only.
+  </summary>
+</histogram>
+
 <histogram name="ContentSuggestions.Feed.ImageFetchStatus"
     enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-09-03">
   <owner>harringtond@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
index 43b2bbe..ea320ff 100644
--- a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
+++ b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
@@ -52,6 +52,9 @@
   <variant name="IPH_AutoDarkUserEducationMessageOptIn"
       summary="message educating users about enabling auto dark web contents
                feature globally"/>
+  <variant name="IPH_AutofillExternalAccountProfileSuggestion"
+      summary="message shown along with the externally created (e.g. in
+               Google Pay) profile suggestion option in the Autofill dropdown"/>
   <variant name="IPH_AutofillVirtualCardSuggestion"
       summary="message shown along with the virtual card suggestion option in
                the Autofill dropdown to educate users virtual cards come with
diff --git a/tools/metrics/histograms/metadata/geolocation/histograms.xml b/tools/metrics/histograms/metadata/geolocation/histograms.xml
index d4fae47..42617bb8 100644
--- a/tools/metrics/histograms/metadata/geolocation/histograms.xml
+++ b/tools/metrics/histograms/metadata/geolocation/histograms.xml
@@ -109,6 +109,17 @@
   </summary>
 </histogram>
 
+<histogram name="Geolocation.NetworkLocationRequest.RequestInterval"
+    units="mins" expires_after="2023-10-31">
+  <owner>alvinji@chromium.org</owner>
+  <owner>device-dev@chromium.org</owner>
+  <summary>
+    For recording the time gap between each HTTP request to geolocation service.
+    The maximum bucket is 10 minutes because that is the maxium interval between
+    wifi data polls.
+  </summary>
+</histogram>
+
 <histogram name="Geolocation.NetworkLocationRequest.ResponseCode"
     enum="HttpResponseCode" expires_after="2023-08-20">
   <owner>mattreynolds@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
index 364ff68..d3ef9fa3 100644
--- a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
@@ -5058,14 +5058,6 @@
   <affected-histogram name="SB2.RequestDestination"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="Scheduler_DOMScheduler_Priority" separator=".">
-  <suffix name="Background" label=""/>
-  <suffix name="UserBlocking" label=""/>
-  <suffix name="UserVisible" label=""/>
-  <affected-histogram
-      name="Scheduler.DOMScheduler.QueueingDurationPerPriority"/>
-</histogram_suffixes>
-
 <histogram_suffixes name="SchedulerDarkMatterMetrics" separator=".">
   <suffix name="Tracked"
       label="Total duration of all tasks managed by the scheduler. This
diff --git a/tools/metrics/histograms/metadata/omnibox/histograms.xml b/tools/metrics/histograms/metadata/omnibox/histograms.xml
index 284fd42..d50757d3 100644
--- a/tools/metrics/histograms/metadata/omnibox/histograms.xml
+++ b/tools/metrics/histograms/metadata/omnibox/histograms.xml
@@ -2322,6 +2322,30 @@
   </summary>
 </histogram>
 
+<histogram name="Omnibox.URLScoringModelExecuted.ElapsedTime" units="ms"
+    expires_after="2024-04-14">
+  <owner>mahmadi@chromium.org</owner>
+  <owner>yoangela@chromium.org</owner>
+  <owner>chrome-desktop-search@google.com</owner>
+  <summary>
+    The amount of time it takes to execute the URL scoring model for all the
+    eligible matches. Emitted when all the providers are done and there is at
+    least one eligible match for model execution.
+  </summary>
+</histogram>
+
+<histogram name="Omnibox.URLScoringModelExecuted.Matches" units="counts"
+    expires_after="2024-04-14">
+  <owner>mahmadi@chromium.org</owner>
+  <owner>yoangela@chromium.org</owner>
+  <owner>chrome-desktop-search@google.com</owner>
+  <summary>
+    The number of matches the URL scoring model was executed for. Emitted when
+    all the providers are done and there is at least one eligible match for
+    model execution.
+  </summary>
+</histogram>
+
 <histogram name="Omnibox.ZeroPrefixOnFocusType" enum="OmniboxFocusType"
     expires_after="2023-04-26">
   <owner>rongtan@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/printing/histograms.xml b/tools/metrics/histograms/metadata/printing/histograms.xml
index 398419f8..44b8302 100644
--- a/tools/metrics/histograms/metadata/printing/histograms.xml
+++ b/tools/metrics/histograms/metadata/printing/histograms.xml
@@ -172,6 +172,28 @@
   </summary>
 </histogram>
 
+<histogram name="Printing.CUPS.NearbyNetworkAutomaticPrintersCount"
+    units="printers" expires_after="2023-12-11">
+  <owner>bmgordon@chromium.org</owner>
+  <owner>project-bolton@google.com</owner>
+  <summary>
+    The number of detected network printers classified as Automatic, excluding
+    Saved printers. Recorded when the user navigates to the OS Settings Printing
+    page to set up printers. Only recorded on Chrome OS.
+  </summary>
+</histogram>
+
+<histogram name="Printing.CUPS.NearbyNetworkDiscoveredPrintersCount"
+    units="printers" expires_after="2023-12-11">
+  <owner>bmgordon@chromium.org</owner>
+  <owner>project-bolton@google.com</owner>
+  <summary>
+    The number of detected network printers classified as Discovered, excluding
+    Saved printers. Recorded when the user navigates to the OS Settings Printing
+    page to set up printers. Only recorded on Chrome OS.
+  </summary>
+</histogram>
+
 <histogram name="Printing.CUPS.NearbyNetworkPrintersCount" units="printers"
     expires_after="2023-08-27">
   <owner>bmgordon@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
index 4f5c0dc..6e67465 100644
--- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
+++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -1092,6 +1092,18 @@
   </summary>
 </histogram>
 
+<histogram name="SafeBrowsing.HPRT.HasOhttpKey" enum="BooleanHasKey"
+    expires_after="2023-10-14">
+  <owner>xinghuilu@chromium.org</owner>
+  <owner>chrome-counter-abuse-alerts@google.com</owner>
+  <summary>
+    Logs whether hash realtime service can obtain a non empty key from OHTTP key
+    service. The lookup will fail if there is no key. Logged each time a top
+    frame URL navigation happens for users who have hash-prefix real-time
+    lookups enabled.
+  </summary>
+</histogram>
+
 <histogram name="SafeBrowsing.HPRT.IsLookupServiceFound" enum="BooleanFound"
     expires_after="2023-09-24">
   <owner>thefrog@chromium.org</owner>
@@ -1137,6 +1149,48 @@
   </summary>
 </histogram>
 
+<histogram name="SafeBrowsing.HPRT.OhttpKeyService.BackoffState"
+    enum="BooleanEnabled" expires_after="2023-10-14">
+  <owner>xinghuilu@chromium.org</owner>
+  <owner>chrome-counter-abuse-alerts@google.com</owner>
+  <summary>
+    Logs if the OHTTP key service is currently in backoff state due to previous
+    errors. Logs whenever a key fetch request is about to be attempted (either
+    triggered by hash prefix lookup, asynchronous workflow or server hint),
+    which will not go through if the service is in backoff mode.
+  </summary>
+</histogram>
+
+<histogram name="SafeBrowsing.HPRT.OhttpKeyService.HasCachedKey"
+    enum="BooleanHasKey" expires_after="2023-10-14">
+  <owner>xinghuilu@chromium.org</owner>
+  <owner>chrome-counter-abuse-alerts@google.com</owner>
+  <summary>
+    Logs whether OHTTP key service has a valid key cached in memory. Logged each
+    time a key is requested through the get OHTTP key API.
+  </summary>
+</histogram>
+
+<histogram name="SafeBrowsing.HPRT.OhttpKeyService.Network.Result"
+    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-10-14">
+  <owner>xinghuilu@chromium.org</owner>
+  <owner>chrome-counter-abuse-alerts@google.com</owner>
+  <summary>
+    Response or error codes from OHTTP key hosting endpoint. Logged on each key
+    fetch request that is sent to the server.
+  </summary>
+</histogram>
+
+<histogram name="SafeBrowsing.HPRT.OhttpKeyService.Network.Time" units="ms"
+    expires_after="2023-10-14">
+  <owner>xinghuilu@chromium.org</owner>
+  <owner>chrome-counter-abuse-alerts@google.com</owner>
+  <summary>
+    Logs the roundtrip time it took to fetch a new OHTTP key. Logged on each key
+    fetch request that is sent to the server.
+  </summary>
+</histogram>
+
 <histogram name="SafeBrowsing.HPRT.OperationResult"
     enum="SafeBrowsingHPRTOperationResult" expires_after="2023-09-24">
   <owner>thefrog@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/sb_client/histograms.xml b/tools/metrics/histograms/metadata/sb_client/histograms.xml
index 7e5104b..7049b368 100644
--- a/tools/metrics/histograms/metadata/sb_client/histograms.xml
+++ b/tools/metrics/histograms/metadata/sb_client/histograms.xml
@@ -108,16 +108,6 @@
   </summary>
 </histogram>
 
-<histogram name="SBClientDownload.DmgHasAPFS" enum="Boolean"
-    expires_after="2023-04-16">
-  <owner>drubery@chromium.org</owner>
-  <owner>chrome-counter-abuse-alerts@google.com</owner>
-  <summary>
-    For each DMG download on Mac, records whether or not the download contains
-    any APFS partitions.
-  </summary>
-</histogram>
-
 <histogram name="SBClientDownload.DmgIterationSuccess" enum="BooleanSuccess"
     expires_after="2022-09-30">
   <obsolete>
@@ -132,16 +122,6 @@
   </summary>
 </histogram>
 
-<histogram name="SBClientDownload.DmgParsedUdif" enum="BooleanSuccess"
-    expires_after="2023-04-16">
-  <owner>drubery@chromium.org</owner>
-  <owner>chrome-counter-abuse-alerts@google.com</owner>
-  <summary>
-    For each DMG download on Mac, records whether or not the UDIF image was
-    parsed successfully.
-  </summary>
-</histogram>
-
 <histogram name="SBClientDownload.DocumentCheckDownloadStats"
     enum="SBClientDownloadCheckDownloadStats" expires_after="2023-08-13">
   <owner>drubery@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/scheduler/histograms.xml b/tools/metrics/histograms/metadata/scheduler/histograms.xml
index 7730c54..2f97562 100644
--- a/tools/metrics/histograms/metadata/scheduler/histograms.xml
+++ b/tools/metrics/histograms/metadata/scheduler/histograms.xml
@@ -46,30 +46,6 @@
   </summary>
 </histogram>
 
-<histogram base="true"
-    name="Scheduler.DOMScheduler.QueueingDurationPerPriority" units="ms"
-    expires_after="2022-12-01">
-<!-- Name completed by histogram_suffixes name="Scheduler.DOMScheduler.Priority" -->
-
-  <owner>kdillon@chromium.org</owner>
-  <owner>shaseley@chromium.org</owner>
-  <summary>
-    Queueing time of a task posted via the postTask API. Reported when the task
-    is starts and bycked by priority. Tasks who have had their priority changed
-    are skipped.
-  </summary>
-</histogram>
-
-<histogram name="Scheduler.DOMScheduler.TaskSignalPriorityWasChanged"
-    enum="PriorityChangeStatus" expires_after="2022-12-01">
-  <owner>kdillon@chromium.org</owner>
-  <owner>shaseley@chromium.org</owner>
-  <summary>
-    Records whether or not a task posted via scheduler.postTask had it's
-    priority changed. Records when the task is started.
-  </summary>
-</histogram>
-
 <histogram name="Scheduler.Experimental.CPUTimePerThread"
     enum="SchedulerThreadType" expires_after="M81">
   <owner>altimin@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 577d729..e47145d 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,24 +5,24 @@
             "full_remote_path": "perfetto-luci-artifacts/adbbb6c78e3a86c5e87b0338d9e42eb6b4ddbf4d/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "9c52fd4a7fc78c09bf65d8310a11d379ce505d2e",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/2276d286905c899bb300bc19f56ebbbd199afbae/trace_processor_shell.exe"
+            "hash": "55d4b8b3774eb6ba9e69b1790f8a2997882bf7ef",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/52e8dd233b135f87fbe2495ff36d6ae30be124c4/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "1d229abc94dea54ab4bb4327e78e18f942d08bf9",
             "full_remote_path": "perfetto-luci-artifacts/adbbb6c78e3a86c5e87b0338d9e42eb6b4ddbf4d/linux-arm/trace_processor_shell"
         },
         "mac": {
-            "hash": "4a33bc015545e4082c53dbcc22ed8900a42836d6",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/0eaad46a44e9ff88f034a199a7de1e814607cf3e/trace_processor_shell"
+            "hash": "4f8fc99b61ab60410d60ad6c6d2bac7dc584861c",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/52e8dd233b135f87fbe2495ff36d6ae30be124c4/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "7a4026b8718994145a52586fdec6e9447573345a",
             "full_remote_path": "perfetto-luci-artifacts/adbbb6c78e3a86c5e87b0338d9e42eb6b4ddbf4d/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "61c0e9181fb06c99ca8f2dd767c228ffef073ea2",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/2276d286905c899bb300bc19f56ebbbd199afbae/trace_processor_shell"
+            "hash": "48d8cfb3468e5ceb67534a79848173e5868e1cde",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/52e8dd233b135f87fbe2495ff36d6ae30be124c4/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/rust/build_bindgen.py b/tools/rust/build_bindgen.py
index cdc92f2..fc52fb8a 100755
--- a/tools/rust/build_bindgen.py
+++ b/tools/rust/build_bindgen.py
@@ -28,8 +28,8 @@
                    MaybeDownloadHostGcc, RunCommand)
 from update import (RmTree)
 
-# The git hash to use. This is the `v0.60.0` tag.
-BINDGEN_GIT_VERSION = '355181134094202e0caae60c1fbf145d8e6ca84b'
+# The git hash to use.
+BINDGEN_GIT_VERSION = '078fb77e82507c1b96f571a18700a03870c96fdd'
 BINDGEN_GIT_REPO = ('https://chromium.googlesource.com/external/' +
                     'github.com/rust-lang/rust-bindgen')
 
@@ -221,7 +221,7 @@
         f'--target-dir={build_dir}',
         f'--target={RustTargetTriple(args.build_mac_arm)}',
         f'--no-default-features',
-        f'--features=clap,logging',
+        f'--features=logging',
         '--release',
         '--bin',
         'bindgen',
diff --git a/tools/rust/update_rust.py b/tools/rust/update_rust.py
index 516abb2..0f6be050 100755
--- a/tools/rust/update_rust.py
+++ b/tools/rust/update_rust.py
@@ -33,7 +33,7 @@
 # These fields are written by //tools/clang/scripts/upload_revision.py, and
 # should not be changed manually.
 RUST_REVISION = 'ac4379fea9e83465d814bb05005689f49bd2141e'
-RUST_SUB_REVISION = 5
+RUST_SUB_REVISION = 7
 
 # Trunk on 2022-10-15.
 #
@@ -65,7 +65,7 @@
 # TODO(lukasza): Include CRUBIT_REVISION and CRUBIT_SUB_REVISION once we
 # include Crubit binaries in the generated package.  See also a TODO comment
 # in BuildCrubit in package_rust.py.
-FALLBACK_REVISION = 'ac4379fea9e83465d814bb05005689f49bd2141e-5-llvmorg-17-init-3874-g93a2fecc-1'
+FALLBACK_REVISION = 'ac4379fea9e83465d814bb05005689f49bd2141e-7-llvmorg-17-init-3874-g93a2fecc-1'
 
 # Hash of src/stage0.json, which itself contains the stage0 toolchain hashes.
 # We trust the Rust build system checks, but to ensure it is not tampered with
diff --git a/ui/accessibility/BUILD.gn b/ui/accessibility/BUILD.gn
index 18fa280..73aa1608 100644
--- a/ui/accessibility/BUILD.gn
+++ b/ui/accessibility/BUILD.gn
@@ -53,6 +53,7 @@
     "ax_action_handler_registry.cc",
     "ax_action_handler_registry.h",
     "ax_base_export.h",
+    "ax_bit_map.h",
     "ax_enum_util.cc",
     "ax_enum_util.h",
     "ax_event.cc",
@@ -260,6 +261,7 @@
 test("accessibility_unittests") {
   testonly = true
   sources = [
+    "ax_bit_map_unittest.cc",
     "ax_computed_node_data_unittest.cc",
     "ax_enum_util_unittest.cc",
     "ax_event_generator_unittest.cc",
diff --git a/ui/accessibility/ax_bit_map.h b/ui/accessibility/ax_bit_map.h
new file mode 100644
index 0000000..fd70b9b
--- /dev/null
+++ b/ui/accessibility/ax_bit_map.h
@@ -0,0 +1,110 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_AX_BIT_MAP_H_
+#define UI_ACCESSIBILITY_AX_BIT_MAP_H_
+
+#include "base/check.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+#include <memory>
+#include <string>
+#include <tuple>
+
+namespace ui {
+
+// A helper class to store AX-related boolean enums.
+template <typename T>
+class AXBitMap {
+ public:
+  static const size_t kElementsPerMapBucket = 64;
+
+  AXBitMap() {
+    for (size_t i = 0;
+         i <= static_cast<size_t>(T::kMaxValue) / kElementsPerMapBucket; ++i) {
+      true_map_[i] = 0;
+      false_map_[i] = 0;
+    }
+  }
+  ~AXBitMap() = default;
+
+  // Returns whether enum T at |value| is set to true, false or unset.
+  absl::optional<bool> Has(const T enum_value) {
+    auto [value_position, true_map, false_map] = GetPositionAndMaps(enum_value);
+    const bool is_in_true_map = (*true_map) >> value_position & 1ull;
+    const bool is_in_false_map = (*false_map) >> value_position & 1ull;
+
+    CHECK(!(is_in_true_map && is_in_false_map))
+        << std::string("A value can't be true and false at the same time.");
+
+    if (is_in_true_map) {
+      return true;
+    }
+
+    if (is_in_false_map) {
+      return false;
+    }
+
+    return absl::nullopt;
+  }
+
+  // Sets the enum T at |enum_value| to true or false.
+  void Set(const T enum_value, const bool bool_value) {
+    auto [value_position, true_map, false_map] = GetPositionAndMaps(enum_value);
+    uint64_t* map_to_set_true;
+    uint64_t* map_to_set_false;
+    if (bool_value) {
+      map_to_set_true = true_map;
+      map_to_set_false = false_map;
+    } else {
+      map_to_set_true = false_map;
+      map_to_set_false = true_map;
+    }
+
+    *map_to_set_true |= 1ull << value_position;
+    *map_to_set_false &= ~(1ull << value_position);
+  }
+
+  // Unsets the enum T at |enum_value|. If it is not set, this is a no-op.
+  void Unset(const T enum_value) {
+    auto [value_position, true_map, false_map] = GetPositionAndMaps(enum_value);
+    (*true_map) &= ~(1ull << value_position);
+    (*false_map) &= ~(1ull << value_position);
+  }
+
+ private:
+  // Helper function that returns a tuple with the position of the value in the
+  // maps, a pointer to the correct bucket in |true_map_| and |false_map_|.
+  std::tuple<uint64_t, uint64_t*, uint64_t*> GetPositionAndMaps(const T value) {
+    uint64_t absolute_value_position = static_cast<uint64_t>(value);
+    const size_t map_bucket = absolute_value_position / kElementsPerMapBucket;
+    uint64_t* true_map = &(true_map_[map_bucket]);
+    uint64_t* false_map = &(false_map_[map_bucket]);
+
+    // Subtracts map_bucket * 64 from |value_position| so that it references the
+    // correct place in the map variables.
+    uint64_t relative_value_position =
+        absolute_value_position - map_bucket * kElementsPerMapBucket;
+
+    return {relative_value_position, true_map, false_map};
+  }
+
+  // Indicates that the enum T is true at the bit shifted value. This array
+  // holds 64 enum values per position, and will contains as many entries to
+  // hold all enum possible values.
+  uint64_t true_map_[static_cast<size_t>(
+      static_cast<size_t>(T::kMaxValue) / kElementsPerMapBucket + 1)];
+
+  // Indicates that the enum T is false at the bit shifted value. This array
+  // holds 64 enum values per position, and will contains as many entries to
+  // hold all enum possible values.
+  uint64_t false_map_[static_cast<size_t>(
+      static_cast<size_t>(T::kMaxValue) / kElementsPerMapBucket + 1)];
+
+  // Undefined/unset implied by not in *_true and *_false;
+};
+
+}  // namespace ui
+
+#endif  // UI_ACCESSIBILITY_AX_BIT_MAP_H_
diff --git a/ui/accessibility/ax_bit_map_unittest.cc b/ui/accessibility/ax_bit_map_unittest.cc
new file mode 100644
index 0000000..2aaee8e
--- /dev/null
+++ b/ui/accessibility/ax_bit_map_unittest.cc
@@ -0,0 +1,115 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accessibility/ax_bit_map.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ui {
+
+enum class SmallTestEnum {
+  kMinValue = 0,
+  kFirstValue = 0,
+  kMiddleValue = 30,
+  kLastValue = 63,
+  kMaxValue = 63,
+};
+
+enum class LargeTestEnum {
+  kMinValue = 0,
+  kFirstValue = 0,
+  kMiddleValue = 64,
+  kLastValue = 127,
+  kMaxValue = 127,
+};
+
+// A macro for testing that a absl::optional has both a value and that its value
+// is set to a particular expectation.
+#define EXPECT_OPTIONAL_EQ(expected, actual) \
+  EXPECT_TRUE(actual.has_value());           \
+  if (actual) {                              \
+    EXPECT_EQ(expected, actual.value());     \
+  }
+
+// Tests a small enum (one that fits inside a single byte (aka kMaxValue <= 63).
+TEST(AXBitMapTest, SmallEnum) {
+  AXBitMap<SmallTestEnum> map;
+  EXPECT_FALSE(map.Has(SmallTestEnum::kMinValue));
+  map.Set(SmallTestEnum::kMinValue, true);
+  EXPECT_OPTIONAL_EQ(true, map.Has(SmallTestEnum::kMinValue));
+  map.Set(SmallTestEnum::kMinValue, false);
+  EXPECT_OPTIONAL_EQ(false, map.Has(SmallTestEnum::kMinValue));
+  map.Unset(SmallTestEnum::kMinValue);
+  EXPECT_FALSE(map.Has(SmallTestEnum::kMinValue));
+
+  EXPECT_FALSE(map.Has(SmallTestEnum::kMiddleValue));
+  map.Set(SmallTestEnum::kMiddleValue, true);
+  EXPECT_OPTIONAL_EQ(true, map.Has(SmallTestEnum::kMiddleValue));
+  map.Set(SmallTestEnum::kMiddleValue, false);
+  EXPECT_OPTIONAL_EQ(false, map.Has(SmallTestEnum::kMiddleValue));
+  map.Unset(SmallTestEnum::kMiddleValue);
+  EXPECT_FALSE(map.Has(SmallTestEnum::kMiddleValue));
+
+  EXPECT_FALSE(map.Has(SmallTestEnum::kLastValue));
+  map.Set(SmallTestEnum::kLastValue, true);
+  EXPECT_OPTIONAL_EQ(true, map.Has(SmallTestEnum::kLastValue));
+  map.Set(SmallTestEnum::kLastValue, false);
+  EXPECT_OPTIONAL_EQ(false, map.Has(SmallTestEnum::kLastValue));
+  map.Unset(SmallTestEnum::kLastValue);
+  EXPECT_FALSE(map.Has(SmallTestEnum::kLastValue));
+
+  map.Set(SmallTestEnum::kMinValue, true);
+  map.Set(SmallTestEnum::kMiddleValue, true);
+  map.Set(SmallTestEnum::kLastValue, true);
+  EXPECT_OPTIONAL_EQ(true, map.Has(SmallTestEnum::kMinValue));
+  EXPECT_OPTIONAL_EQ(true, map.Has(SmallTestEnum::kMiddleValue));
+  EXPECT_OPTIONAL_EQ(true, map.Has(SmallTestEnum::kLastValue));
+  map.Set(SmallTestEnum::kLastValue, false);
+  EXPECT_OPTIONAL_EQ(false, map.Has(SmallTestEnum::kLastValue));
+  map.Unset(SmallTestEnum::kMinValue);
+  EXPECT_FALSE(map.Has(SmallTestEnum::kMinValue));
+  EXPECT_OPTIONAL_EQ(true, map.Has(SmallTestEnum::kMiddleValue));
+}
+
+// Tests a large enum (one that requires two bytes (aka kMaxValue <= 127).
+TEST(AXBitMapTest, LargeEnum) {
+  AXBitMap<LargeTestEnum> map;
+  EXPECT_FALSE(map.Has(LargeTestEnum::kMinValue));
+  map.Set(LargeTestEnum::kMinValue, true);
+  EXPECT_OPTIONAL_EQ(true, map.Has(LargeTestEnum::kMinValue));
+  map.Set(LargeTestEnum::kMinValue, false);
+  EXPECT_OPTIONAL_EQ(false, map.Has(LargeTestEnum::kMinValue));
+  map.Unset(LargeTestEnum::kMinValue);
+  EXPECT_FALSE(map.Has(LargeTestEnum::kMinValue));
+
+  EXPECT_FALSE(map.Has(LargeTestEnum::kMiddleValue));
+  map.Set(LargeTestEnum::kMiddleValue, true);
+  EXPECT_OPTIONAL_EQ(true, map.Has(LargeTestEnum::kMiddleValue));
+  map.Set(LargeTestEnum::kMiddleValue, false);
+  EXPECT_OPTIONAL_EQ(false, map.Has(LargeTestEnum::kMiddleValue));
+  map.Unset(LargeTestEnum::kMiddleValue);
+  EXPECT_FALSE(map.Has(LargeTestEnum::kMiddleValue));
+
+  EXPECT_FALSE(map.Has(LargeTestEnum::kLastValue));
+  map.Set(LargeTestEnum::kLastValue, true);
+  EXPECT_OPTIONAL_EQ(true, map.Has(LargeTestEnum::kLastValue));
+  map.Set(LargeTestEnum::kLastValue, false);
+  EXPECT_OPTIONAL_EQ(false, map.Has(LargeTestEnum::kLastValue));
+  map.Unset(LargeTestEnum::kLastValue);
+  EXPECT_FALSE(map.Has(LargeTestEnum::kLastValue));
+
+  map.Set(LargeTestEnum::kMinValue, true);
+  map.Set(LargeTestEnum::kMiddleValue, true);
+  map.Set(LargeTestEnum::kLastValue, true);
+  EXPECT_OPTIONAL_EQ(true, map.Has(LargeTestEnum::kMinValue));
+  EXPECT_OPTIONAL_EQ(true, map.Has(LargeTestEnum::kMiddleValue));
+  EXPECT_OPTIONAL_EQ(true, map.Has(LargeTestEnum::kLastValue));
+  map.Set(LargeTestEnum::kLastValue, false);
+  EXPECT_OPTIONAL_EQ(false, map.Has(LargeTestEnum::kLastValue));
+  map.Unset(LargeTestEnum::kMinValue);
+  EXPECT_FALSE(map.Has(LargeTestEnum::kMinValue));
+  EXPECT_OPTIONAL_EQ(true, map.Has(LargeTestEnum::kMiddleValue));
+}
+
+}  // namespace ui
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index 958bed82..a05104c7 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -195,6 +195,7 @@
     "java/res/drawable/ic_apps_blue_24dp.xml",
     "java/res/drawable/ic_expand_more_horizontal_black_24dp.xml",
     "java/res/drawable/ic_globe_24dp.xml",
+    "java/res/drawable/ic_globe_48dp.xml",
     "java/res/drawable/menu_bg_baseline.xml",
     "java/res/drawable/transition_expand_less_expand_more_black_24dp.xml",
     "java/res/drawable/transition_expand_more_expand_less_black_24dp.xml",
diff --git a/ui/android/java/res/drawable/ic_globe_48dp.xml b/ui/android/java/res/drawable/ic_globe_48dp.xml
new file mode 100644
index 0000000..9b6828c
--- /dev/null
+++ b/ui/android/java/res/drawable/ic_globe_48dp.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2023 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="48dp"
+    android:height="48dp"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M40.667,24C40.667,14.8 33.2,7.333 24,7.333C14.8,7.333 7.333,14.8 7.333,24C7.333,33.2 14.8,40.667 24,40.667C33.2,40.667 40.667,33.2 40.667,24ZM24,10.667C16.641,10.667 10.667,16.641 10.667,24H17.999C23.678,24.036 26.202,26.885 25.572,32.545H19.813V36.662C21.13,37.097 22.538,37.333 24,37.333C31.359,37.333 37.333,31.359 37.333,24C37.333,23.728 37.325,23.458 37.309,23.191C37.309,23.191 35.667,25.667 32.333,25.667C28.771,25.667 26.99,24.139 26.99,21.084H20.743C20.287,16.537 21.881,14.264 25.526,14.264C25.526,12.639 26.072,11.602 26.879,10.979C25.952,10.774 24.988,10.667 24,10.667Z"
+      android:fillColor="#444746"
+      android:fillType="evenOdd"/>
+</vector>
diff --git a/ui/base/test/skia_gold_matching_algorithm.cc b/ui/base/test/skia_gold_matching_algorithm.cc
index 2d29273..c732cedb1 100644
--- a/ui/base/test/skia_gold_matching_algorithm.cc
+++ b/ui/base/test/skia_gold_matching_algorithm.cc
@@ -9,6 +9,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 
+namespace ui {
 namespace {
 constexpr char kMaxDifferentPixels[] = "fuzzy_max_different_pixels";
 constexpr char kPixelDeltaThreshold[] = "fuzzy_pixel_delta_threshold";
@@ -16,8 +17,10 @@
 constexpr char kIgnoredBorderThickness[] = "fuzzy_ignored_border_thickness";
 }  // namespace
 
-namespace ui {
 namespace test {
+
+// SkiaGoldMatchingAlgorithm ---------------------------------------------------
+
 SkiaGoldMatchingAlgorithm::SkiaGoldMatchingAlgorithm() = default;
 
 SkiaGoldMatchingAlgorithm::~SkiaGoldMatchingAlgorithm() = default;
@@ -30,6 +33,8 @@
                        ":"));
 }
 
+// ExactSkiaGoldMatchingAlgorithm ----------------------------------------------
+
 ExactSkiaGoldMatchingAlgorithm::ExactSkiaGoldMatchingAlgorithm() = default;
 
 ExactSkiaGoldMatchingAlgorithm::~ExactSkiaGoldMatchingAlgorithm() = default;
@@ -44,6 +49,8 @@
   // Nothing to append.
 }
 
+// FuzzySkiaGoldMatchingAlgorithm ----------------------------------------------
+
 FuzzySkiaGoldMatchingAlgorithm::~FuzzySkiaGoldMatchingAlgorithm() = default;
 
 std::string FuzzySkiaGoldMatchingAlgorithm::GetCommandLineSwitchName() const {
@@ -85,6 +92,8 @@
                          ":"));
 }
 
+// SobelSkiaGoldMatchingAlgorithm ----------------------------------------------
+
 SobelSkiaGoldMatchingAlgorithm::~SobelSkiaGoldMatchingAlgorithm() = default;
 
 std::string SobelSkiaGoldMatchingAlgorithm::GetCommandLineSwitchName() const {
@@ -113,5 +122,27 @@
                        ":"));
 }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+
+// PositiveIfOnlyImageAlgorithm ------------------------------------------------
+
+PositiveIfOnlyImageAlgorithm::PositiveIfOnlyImageAlgorithm() = default;
+
+PositiveIfOnlyImageAlgorithm::~PositiveIfOnlyImageAlgorithm() = default;
+
+void PositiveIfOnlyImageAlgorithm::AppendAlgorithmToCmdline(
+    base::CommandLine& cmd) const {
+  SkiaGoldMatchingAlgorithm::AppendAlgorithmToCmdline(cmd);
+
+  // Disallow the user from triaging images.
+  cmd.AppendSwitchASCII("add-test-optional-key", "disallow_triaging:true");
+}
+
+std::string PositiveIfOnlyImageAlgorithm::GetCommandLineSwitchName() const {
+  return "positive_if_only_image";
+}
+
+#endif  // IS_CHROMEOS_ASH
+
 }  // namespace test
 }  // namespace ui
diff --git a/ui/base/test/skia_gold_matching_algorithm.h b/ui/base/test/skia_gold_matching_algorithm.h
index 21eb893..9bfb798 100644
--- a/ui/base/test/skia_gold_matching_algorithm.h
+++ b/ui/base/test/skia_gold_matching_algorithm.h
@@ -7,6 +7,8 @@
 
 #include <string>
 
+#include "build/chromeos_buildflags.h"
+
 namespace base {
 class CommandLine;
 }
@@ -15,8 +17,7 @@
 namespace test {
 
 // Describes what algorithm to use to match golden images.
-// There are three algorithms (exact, fuzzy, sobel), and the latter two have
-// adjustable parameters:
+// Fuzzy and Sobel algorithms have adjustable parameters:
 //
 // Fuzzy has the max number of different pixels, the max per-channel delta sum
 // (i.e. how much a pixel can differ by and still be considered the same), and
@@ -95,6 +96,26 @@
   int edge_threshold_{0};
 };
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+
+// With this algorithm, an image is regarded to match a golden image if:
+// 1. it is an exact matching, and
+// 2. the matched golden image is the only image in its group.
+// This algorithm is used in Ash pixel testing to facilitate the gold image
+// revision update.
+class PositiveIfOnlyImageAlgorithm : public SkiaGoldMatchingAlgorithm {
+ public:
+  PositiveIfOnlyImageAlgorithm();
+  ~PositiveIfOnlyImageAlgorithm() override;
+
+ private:
+  // SkiaGoldMatchingAlgorithm:
+  void AppendAlgorithmToCmdline(base::CommandLine& cmd) const override;
+  std::string GetCommandLineSwitchName() const override;
+};
+
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
 }  // namespace test
 }  // namespace ui
 
diff --git a/ui/chromeos/styles/BUILD.gn b/ui/chromeos/styles/BUILD.gn
index 9d0eb91..07ba115 100644
--- a/ui/chromeos/styles/BUILD.gn
+++ b/ui/chromeos/styles/BUILD.gn
@@ -2,7 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//chrome/common/features.gni")
+import("//tools/grit/grit_rule.gni")
 import("//tools/style_variable_generator/style_variable_generator.gni")
+import("//ui/webui/resources/tools/generate_grd.gni")
 
 style_variable_generator("cros_styles") {
   # If you change the sources, also change the paths in presubmit_support.py
@@ -44,3 +47,30 @@
   ]
   cpp_namespace = "color_internals_tokens"
 }
+
+grit("cros_styles_resources") {
+  # Required since the .grd file is generated at build time.
+  enable_input_discovery_for_gn_analyze = false
+
+  source = "$target_gen_dir/cros_typography_resources.grd"
+  defines = chrome_grit_defines
+  outputs = [
+    "grit/cros_styles_resources.h",
+    "grit/cros_styles_resources_map.cc",
+    "grit/cros_styles_resources_map.h",
+    "cros_styles_resources.pak",
+  ]
+
+  deps = [ ":build_grd" ]
+
+  output_dir = "$root_gen_dir/chrome"
+}
+
+generate_grd("build_grd") {
+  grd_prefix = "cros_styles"
+  out_grd = "$target_gen_dir/cros_typography_resources.grd"
+  public_deps = [ "//ui/chromeos/styles:cros_typography_css" ]
+  input_files_base_dir = rebase_path("$root_gen_dir/", root_build_dir)
+  input_files = [ "ui/chromeos/styles/cros_typography.css" ]
+  resource_path_rewrites = [ "ui/chromeos/styles/cros_typography.css|chromeos/colors/cros_typography.css" ]
+}
diff --git a/ui/chromeos/styles/cros_sys_colors.json5 b/ui/chromeos/styles/cros_sys_colors.json5
index 2af8836..5033b93 100644
--- a/ui/chromeos/styles/cros_sys_colors.json5
+++ b/ui/chromeos/styles/cros_sys_colors.json5
@@ -209,12 +209,16 @@
       dark: 'rgba($cros.ref.neutral0.rgb, 0.6)'
     },
     'system-on-base': {
+      light: 'rgba($cros.ref.neutralvariant99.rgb, 0.6)',
+      dark: 'rgba($cros.ref.neutralvariant40.rgb, 0.5)',
+    },
+    'system-on-base-opaque': {
       light: '$cros.ref.neutralvariant95',
-      dark: 'rgba($cros.ref.neutralvariant40.rgb, 0.4)',
+      dark: '$cros.ref.neutralvariant30',
     },
     'system-on-base1': {
-      light: 'rgba($cros.ref.neutral99.rgb, 0.10)',
-      dark: 'rgba($cros.ref.neutral10.rgb, 0.06)',
+      light: 'rgba($cros.ref.neutral10.rgb, 0.06)',
+      dark: 'rgba($cros.ref.neutral99.rgb, 0.10)',
     },
     'system-primary-container': {
       light: '$cros.ref.primary80',
diff --git a/ui/chromeos/translations/ui_chromeos_strings_da.xtb b/ui/chromeos/translations/ui_chromeos_strings_da.xtb
index 28ab349..2b7530d 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_da.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_da.xtb
@@ -1013,7 +1013,7 @@
 <translation id="9035689366572880647">Angiv aktuel pinkode</translation>
 <translation id="9038620279323455325">Der findes allerede en fil med navnet "<ph name="FILE_NAME" />". Vælg et andet navn.</translation>
 <translation id="9046895021617826162">Forbindelsen mislykkedes</translation>
-<translation id="9065512565307033593">Hvis du ikke bekræfter, mister du adgangen til netværket.</translation>
+<translation id="9065512565307033593">Hvis du ikke verificerer, mister du adgangen til netværket.</translation>
 <translation id="908378762078012445">Russisk med fonetisk AATSEEL-tastatur</translation>
 <translation id="9086302186042011942">Synkroniserer</translation>
 <translation id="9099674669267916096">Sideantal</translation>
diff --git a/ui/color/color_provider_manager.cc b/ui/color/color_provider_manager.cc
index 6c4abab5..a027ca67 100644
--- a/ui/color/color_provider_manager.cc
+++ b/ui/color/color_provider_manager.cc
@@ -59,6 +59,7 @@
           SystemTheme::kDefault,
           FrameType::kChromium,
           absl::nullopt,
+          absl::nullopt,
           nullptr) {}
 
 ColorProviderManager::Key::Key(
@@ -67,6 +68,7 @@
     SystemTheme system_theme,
     FrameType frame_type,
     absl::optional<SkColor> user_color,
+    absl::optional<SchemeVariant> scheme_variant,
     scoped_refptr<ThemeInitializerSupplier> custom_theme)
     : color_mode(color_mode),
       contrast_mode(contrast_mode),
@@ -74,6 +76,7 @@
       system_theme(system_theme),
       frame_type(frame_type),
       user_color(user_color),
+      scheme_variant(scheme_variant),
       custom_theme(std::move(custom_theme)) {}
 
 ColorProviderManager::Key::Key(const Key&) = default;
diff --git a/ui/color/color_provider_manager.h b/ui/color/color_provider_manager.h
index e682f53..8063908 100644
--- a/ui/color/color_provider_manager.h
+++ b/ui/color/color_provider_manager.h
@@ -50,6 +50,13 @@
     // Native system renders the browser frame. Currently GTK only.
     kNative,
   };
+  // The type of color palette that is generated.
+  enum class SchemeVariant {
+    kTonalSpot,
+    kNeutral,
+    kVibrant,
+    kExpressive,
+  };
 
   class COMPONENT_EXPORT(COLOR) InitializerSupplier {
    public:
@@ -99,6 +106,7 @@
         SystemTheme system_theme,
         FrameType frame_type,
         absl::optional<SkColor> user_color = absl::nullopt,
+        absl::optional<SchemeVariant> scheme_variant = absl::nullopt,
         scoped_refptr<ThemeInitializerSupplier> custom_theme = nullptr);
     Key(const Key&);
     Key& operator=(const Key&);
@@ -109,6 +117,7 @@
     SystemTheme system_theme;
     FrameType frame_type;
     absl::optional<SkColor> user_color;
+    absl::optional<SchemeVariant> scheme_variant;
     scoped_refptr<ThemeInitializerSupplier> custom_theme;
     // Only dereferenced when populating the ColorMixer. After that, used to
     // compare addresses during lookup.
@@ -119,12 +128,12 @@
       auto* lhs_app_controller = app_controller.get();
       auto* rhs_app_controller = other.app_controller.get();
       return std::tie(color_mode, contrast_mode, elevation_mode, system_theme,
-                      frame_type, user_color, custom_theme,
+                      frame_type, user_color, scheme_variant, custom_theme,
                       lhs_app_controller) <
              std::tie(other.color_mode, other.contrast_mode,
                       other.elevation_mode, other.system_theme,
-                      other.frame_type, other.user_color, other.custom_theme,
-                      rhs_app_controller);
+                      other.frame_type, other.user_color, other.scheme_variant,
+                      other.custom_theme, rhs_app_controller);
     }
   };
 
diff --git a/ui/color/color_provider_manager_unittest.cc b/ui/color/color_provider_manager_unittest.cc
index aeeea16..5bcd3be 100644
--- a/ui/color/color_provider_manager_unittest.cc
+++ b/ui/color/color_provider_manager_unittest.cc
@@ -35,7 +35,8 @@
   return ColorProviderManager::GetForTesting().GetColorProviderFor(
       {ColorProviderManager::ColorMode::kLight,
        ColorProviderManager::ContrastMode::kNormal, ui::SystemTheme::kDefault,
-       ColorProviderManager::FrameType::kChromium, absl::nullopt, nullptr});
+       ColorProviderManager::FrameType::kChromium, /*user_color=*/absl::nullopt,
+       /*scheme_variant=*/absl::nullopt, nullptr});
 }
 
 class TestInitializerSupplier
diff --git a/ui/color/dynamic_color/BUILD.gn b/ui/color/dynamic_color/BUILD.gn
new file mode 100644
index 0000000..1be397c
--- /dev/null
+++ b/ui/color/dynamic_color/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+component("dynamic_color") {
+  sources = [
+    "palette.cc",
+    "palette.h",
+    "palette_factory.cc",
+    "palette_factory.h",
+  ]
+
+  defines = [ "IS_DYNAMIC_COLOR_IMPL" ]
+
+  deps = [
+    "//base",
+    "//skia",
+    "//third_party/material_color_utilities",
+    "//ui/color:color_headers",
+  ]
+}
diff --git a/ui/color/dynamic_color/palette.cc b/ui/color/dynamic_color/palette.cc
new file mode 100644
index 0000000..fc4aa00
--- /dev/null
+++ b/ui/color/dynamic_color/palette.cc
@@ -0,0 +1,41 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/color/dynamic_color/palette.h"
+
+#include "base/check_op.h"
+#include "third_party/material_color_utilities/src/cpp/cam/cam.h"
+
+namespace ui {
+
+namespace {
+
+using material_color_utilities::Argb;
+using material_color_utilities::Cam;
+using material_color_utilities::CamFromInt;
+using material_color_utilities::IntFromHcl;
+
+}  // namespace
+
+TonalPalette::TonalPalette(SkColor argb) {
+  Cam cam = CamFromInt(static_cast<Argb>(argb));
+  hue_ = cam.hue;
+  chroma_ = cam.chroma;
+}
+
+TonalPalette::TonalPalette(double hue, double chroma)
+    : hue_(hue), chroma_(chroma) {}
+
+TonalPalette::TonalPalette(const TonalPalette& other) = default;
+TonalPalette& TonalPalette::operator=(const TonalPalette&) = default;
+
+TonalPalette::~TonalPalette() = default;
+
+SkColor TonalPalette::get(float tone) const {
+  CHECK_LE(tone, 100.0f);
+  CHECK_GE(tone, 0.0f);
+  return static_cast<SkColor>(IntFromHcl(hue_, chroma_, tone));
+}
+
+}  // namespace ui
diff --git a/ui/color/dynamic_color/palette.h b/ui/color/dynamic_color/palette.h
new file mode 100644
index 0000000..12472e11
--- /dev/null
+++ b/ui/color/dynamic_color/palette.h
@@ -0,0 +1,51 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_COLOR_DYNAMIC_COLOR_PALETTE_H_
+#define UI_COLOR_DYNAMIC_COLOR_PALETTE_H_
+
+#include "base/component_export.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace ui {
+
+// For a given color, provides the color values for the tonal range between 0
+// and 100 in the HCT color space.
+class COMPONENT_EXPORT(DYNAMIC_COLOR) TonalPalette {
+ public:
+  explicit TonalPalette(SkColor seed_color);
+  TonalPalette(double hue, double chroma);
+
+  TonalPalette(const TonalPalette& other);
+  TonalPalette& operator=(const TonalPalette&);
+
+  ~TonalPalette();
+
+  // Returns the color in the palette for the corresponding `tone`.
+  // `tone` must be between 0.f and 100.f or SKColor_TRANSPARENT will be
+  // returned.
+  SkColor get(float tone) const;
+
+ private:
+  double hue_;
+  double chroma_;
+};
+
+// A collection of TonalPalettes representing the reference palette for a
+// particular color configuration.
+class COMPONENT_EXPORT(DYNAMIC_COLOR) Palette {
+ public:
+  virtual ~Palette() = default;
+
+  virtual const TonalPalette& primary() const = 0;
+  virtual const TonalPalette& secondary() const = 0;
+  virtual const TonalPalette& tertiary() const = 0;
+  virtual const TonalPalette& neutral() const = 0;
+  virtual const TonalPalette& neutral_variant() const = 0;
+  virtual const TonalPalette& error() const = 0;
+};
+
+}  // namespace ui
+
+#endif  // UI_COLOR_DYNAMIC_COLOR_PALETTE_H_
diff --git a/ui/color/dynamic_color/palette_factory.cc b/ui/color/dynamic_color/palette_factory.cc
new file mode 100644
index 0000000..7ff6ccb
--- /dev/null
+++ b/ui/color/dynamic_color/palette_factory.cc
@@ -0,0 +1,205 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/color/dynamic_color/palette_factory.h"
+
+#include <array>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "base/containers/span.h"
+#include "third_party/material_color_utilities/src/cpp/cam/hct.h"
+#include "third_party/material_color_utilities/src/cpp/palettes/core.h"
+#include "third_party/material_color_utilities/src/cpp/palettes/tones.h"
+#include "ui/color/color_provider_manager.h"
+#include "ui/color/dynamic_color/palette.h"
+
+namespace ui {
+
+namespace {
+
+using material_color_utilities::Hct;
+using SchemeVariant = ColorProviderManager::SchemeVariant;
+
+// Returns the hue angle for `source_color` modified by the closest match in
+// `hues_to_rotations`.
+double GetRotatedHue(double source_hue,
+                     const base::flat_map<double, double>& hues_to_rotations) {
+  if (hues_to_rotations.size() == 1) {
+    return material_color_utilities::SanitizeDegreesDouble(
+        source_hue + hues_to_rotations.begin()->second);
+  }
+
+  auto it = hues_to_rotations.lower_bound(source_hue);
+  if (it == hues_to_rotations.end()) {
+    return source_hue;
+  }
+
+  return material_color_utilities::SanitizeDegreesDouble(source_hue +
+                                                         it->second);
+}
+
+class CustomPalette : public Palette {
+ public:
+  CustomPalette(TonalPalette&& primary,
+                TonalPalette&& secondary,
+                TonalPalette&& tertiary,
+                TonalPalette&& neutral,
+                TonalPalette&& neutral_variant,
+                TonalPalette&& error)
+      : primary_(primary),
+        secondary_(secondary),
+        tertiary_(tertiary),
+        neutral_(neutral),
+        neutral_variant_(neutral_variant),
+        error_(error) {}
+
+  const TonalPalette& primary() const override { return primary_; }
+
+  const TonalPalette& secondary() const override { return secondary_; }
+
+  const TonalPalette& tertiary() const override { return tertiary_; }
+
+  const TonalPalette& neutral() const override { return neutral_; }
+
+  const TonalPalette& neutral_variant() const override {
+    return neutral_variant_;
+  }
+
+  const TonalPalette& error() const override { return error_; }
+
+ private:
+  const TonalPalette primary_;
+  const TonalPalette secondary_;
+  const TonalPalette tertiary_;
+  const TonalPalette neutral_;
+  const TonalPalette neutral_variant_;
+  const TonalPalette error_;
+};
+
+struct Transform {
+  Transform() = default;
+  Transform(double hue_rotation,
+            double chroma,
+            absl::optional<base::flat_map<double, double>> hues_to_rotations =
+                absl::nullopt)
+      : hue_rotation(hue_rotation),
+        chroma(chroma),
+        hues_to_rotations(hues_to_rotations) {}
+
+  double hue_rotation = 0.0;
+  double chroma = 0.0;
+  absl::optional<base::flat_map<double, double>> hues_to_rotations;
+};
+
+Transform Chroma(double chroma) {
+  Transform transform;
+  transform.chroma = chroma;
+  return transform;
+}
+
+// Specifies the `Transform`s relative to the source color that generates a
+// Palette.
+struct Config {
+  Transform primary;
+  Transform secondary;
+  Transform tertiary;
+  Transform neutral;
+  Transform neutral_variant;
+};
+
+// Returns a `TonalPalette` constructed from `hue` transformed by `transform`.
+TonalPalette MakePalette(double hue, const Transform& transform) {
+  if (transform.hues_to_rotations) {
+    hue = GetRotatedHue(hue, *transform.hues_to_rotations);
+  } else {
+    hue = material_color_utilities::SanitizeDegreesDouble(
+        hue + transform.hue_rotation);
+  }
+  return TonalPalette(hue, transform.chroma);
+}
+
+std::unique_ptr<Palette> FromConfig(SkColor seed_color, const Config& config) {
+  // TODO(skau): Make this const when get_hue() is marked const.
+  Hct source_hct(seed_color);
+  double hue = source_hct.get_hue();
+
+  return std::make_unique<CustomPalette>(
+      MakePalette(hue, config.primary), MakePalette(hue, config.secondary),
+      MakePalette(hue, config.tertiary), MakePalette(hue, config.neutral),
+      MakePalette(hue, config.neutral_variant), TonalPalette(25.0, 84.0));
+}
+
+// Returns a `base::flat_map` from two arrays of equal size.
+template <class S, class T, size_t N>
+base::flat_map<S, T> Zip(const std::array<S, N>& keys,
+                         const std::array<T, N>& values) {
+  CHECK_EQ(keys.size(), values.size());
+  std::vector<std::pair<S, T>> zipped;
+  zipped.reserve(keys.size());
+  for (size_t i = 0; i < keys.size(); i++) {
+    zipped.push_back(std::make_pair(keys[i], values[i]));
+  }
+  return base::flat_map<S, T>(base::sorted_unique_t(), std::move(zipped));
+}
+
+}  // namespace
+
+std::unique_ptr<Palette> GeneratePalette(SkColor seed_color,
+                                         SchemeVariant variant) {
+  Config config;
+  switch (variant) {
+    case SchemeVariant::kTonalSpot:
+      config = {Chroma(40.0), Chroma(16.0), Transform{60.0, 24.0}, Chroma(6.0),
+                Chroma(8.0)};
+      break;
+    case SchemeVariant::kVibrant: {
+      const auto hues =
+          std::to_array<double>({0, 41, 61, 101, 131, 181, 251, 301, 360});
+      const auto secondary_rotations =
+          std::to_array<double>({18, 15, 10, 12, 15, 18, 15, 12, 12});
+      const base::flat_map<double, double> secondary_hues_to_rotations =
+          Zip(hues, secondary_rotations);
+
+      const auto tertiary_rotations =
+          std::to_array<double>({35, 30, 20, 25, 30, 35, 30, 25, 25});
+      const base::flat_map<double, double> tertiary_hues_to_rotations =
+          Zip(hues, tertiary_rotations);
+
+      config = {Chroma(200.0),
+                Transform(0.0, 24.0, secondary_hues_to_rotations),
+                Transform(0.0, 32.0, tertiary_hues_to_rotations), Chroma(8.0),
+                Chroma(12.0)};
+      break;
+    }
+    case SchemeVariant::kNeutral:
+      config = {Chroma(12.0), Chroma(8.0), Chroma(16.0), Chroma(2.0),
+                Chroma(2.0)};
+      break;
+    case SchemeVariant::kExpressive: {
+      const auto hues =
+          std::to_array<double>({0, 21, 51, 121, 151, 191, 271, 321, 360});
+      const auto secondary_rotations =
+          std::to_array<double>({45, 95, 45, 20, 45, 90, 45, 45, 45});
+      const base::flat_map<double, double> secondary_hues_to_rotations =
+          Zip(hues, secondary_rotations);
+
+      const auto tertiary_rotations =
+          std::to_array<double>({120, 120, 20, 45, 20, 15, 20, 120, 120});
+      const base::flat_map<double, double> tertiary_hues_to_rotations =
+          Zip(hues, tertiary_rotations);
+      config = {Transform(120.0, 40.0),
+                Transform(0.0, 24.0, secondary_hues_to_rotations),
+                Transform(0.0, 32.0, tertiary_hues_to_rotations), Chroma(8.0),
+                Chroma(12.0)};
+      break;
+    }
+  }
+
+  return FromConfig(seed_color, config);
+}
+
+}  // namespace ui
diff --git a/ui/color/dynamic_color/palette_factory.h b/ui/color/dynamic_color/palette_factory.h
new file mode 100644
index 0000000..6393d5d
--- /dev/null
+++ b/ui/color/dynamic_color/palette_factory.h
@@ -0,0 +1,26 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_COLOR_DYNAMIC_COLOR_PALETTE_FACTORY_H_
+#define UI_COLOR_DYNAMIC_COLOR_PALETTE_FACTORY_H_
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/color/color_provider_manager.h"
+#include "ui/color/dynamic_color/palette.h"
+
+namespace ui {
+
+// For the desired `seed_color` and `variant`, generates the correct type of
+// `Palette`.
+COMPONENT_EXPORT(DYNAMIC_COLOR)
+std::unique_ptr<Palette> GeneratePalette(
+    SkColor seed_color,
+    ColorProviderManager::SchemeVariant variant);
+
+}  // namespace ui
+
+#endif  // UI_COLOR_DYNAMIC_COLOR_PALETTE_FACTORY_H_
diff --git a/ui/events/ash/keyboard_capability.cc b/ui/events/ash/keyboard_capability.cc
index bd2b88a..3a26d3d 100644
--- a/ui/events/ash/keyboard_capability.cc
+++ b/ui/events/ash/keyboard_capability.cc
@@ -385,6 +385,10 @@
   }
 }
 
+bool IsInternalKeyboard(const ui::InputDevice& keyboard) {
+  return keyboard.type == INPUT_DEVICE_INTERNAL;
+}
+
 }  // namespace
 
 KeyboardCapability::KeyboardCapability(std::unique_ptr<Delegate> delegate)
@@ -799,6 +803,27 @@
   return false;
 }
 
+bool KeyboardCapability::HasCalculatorKey(const InputDevice& keyboard) const {
+  const KeyboardInfo* keyboard_info = GetKeyboardInfo(keyboard);
+  if (!keyboard_info) {
+    return false;
+  }
+
+  // TODO(dpad): Many external keyboards do not have this key, but currently we
+  // do not have a good way to detect these situations.
+  return !IsInternalKeyboard(keyboard);
+}
+
+bool KeyboardCapability::HasCalculatorKeyOnAnyKeyboard() const {
+  for (const ui::InputDevice& keyboard :
+       ui::DeviceDataManager::GetInstance()->GetKeyboardDevices()) {
+    if (HasCalculatorKey(keyboard)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 void KeyboardCapability::OnDeviceListsComplete() {
   TrimKeyboardInfoMap();
 }
diff --git a/ui/events/ash/keyboard_capability.h b/ui/events/ash/keyboard_capability.h
index 74c2ad3..2d6ad5f 100644
--- a/ui/events/ash/keyboard_capability.h
+++ b/ui/events/ash/keyboard_capability.h
@@ -336,8 +336,12 @@
   bool HasGlobeKey(const InputDevice& keyboard) const;
   bool HasGlobeKeyOnAnyKeyboard() const;
 
-  // Gets the corresponding function key for the given `action_key` on the given
-  // `keyboard`.
+  // Check if the calculator key exists on the given keyboard.
+  bool HasCalculatorKey(const InputDevice& keyboard) const;
+  bool HasCalculatorKeyOnAnyKeyboard() const;
+
+  // Gets the corresponding function key for the given `action_key` on the
+  // given `keyboard`.
   absl::optional<KeyboardCode> GetCorrespondingFunctionKey(
       const InputDevice& keyboard,
       TopRowActionKey action_key) const;
diff --git a/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h b/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h
index 49c1389..a7f3a80 100644
--- a/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h
+++ b/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h
@@ -5,14 +5,9 @@
 #ifndef UI_GFX_SCOPED_NS_GRAPHICS_CONTEXT_SAVE_GSTATE_MAC_H_
 #define UI_GFX_SCOPED_NS_GRAPHICS_CONTEXT_SAVE_GSTATE_MAC_H_
 
-#include "base/memory/raw_ptr_exclusion.h"
-#include "ui/gfx/gfx_export.h"
+#include <memory>
 
-#if defined(__OBJC__)
-@class NSGraphicsContext;
-#else
-class NSGraphicsContext;
-#endif
+#include "ui/gfx/gfx_export.h"
 
 namespace gfx {
 
@@ -29,9 +24,8 @@
   ~ScopedNSGraphicsContextSaveGState();
 
  private:
-  // This field is not a raw_ptr<> because it is a pointer to Objective-C
-  // object.
-  RAW_PTR_EXCLUSION NSGraphicsContext* context_;  // weak
+  struct ObjCStorage;
+  std::unique_ptr<ObjCStorage> objc_storage_;
 };
 
 }  // namespace gfx
diff --git a/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.mm b/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.mm
index 62920a8d..ee94ca71 100644
--- a/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.mm
+++ b/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.mm
@@ -10,14 +10,19 @@
 
 namespace gfx {
 
+struct ScopedNSGraphicsContextSaveGState::ObjCStorage {
+  NSGraphicsContext* context_;  // weak
+};
+
 ScopedNSGraphicsContextSaveGState::ScopedNSGraphicsContextSaveGState()
-    : context_([NSGraphicsContext currentContext]) {
+    : objc_storage_(std::make_unique<ObjCStorage>()) {
+  objc_storage_->context_ = NSGraphicsContext.currentContext;
   [NSGraphicsContext saveGraphicsState];
 }
 
 ScopedNSGraphicsContextSaveGState::~ScopedNSGraphicsContextSaveGState() {
   [NSGraphicsContext restoreGraphicsState];
-  DCHECK_EQ(context_, [NSGraphicsContext currentContext]);
+  DCHECK_EQ(objc_storage_->context_, NSGraphicsContext.currentContext);
 }
 
 }  // namespace gfx
diff --git a/ui/gl/swap_chain_presenter.cc b/ui/gl/swap_chain_presenter.cc
index db45afce..969242a29 100644
--- a/ui/gl/swap_chain_presenter.cc
+++ b/ui/gl/swap_chain_presenter.cc
@@ -208,10 +208,9 @@
   raw_ptr<void> param;
 };
 
-// Return true if VpSuperResolution has been set successfully.
-bool ToggleIntelVpSuperResolution(ID3D11VideoContext* video_context,
-                                  ID3D11VideoProcessor* video_processor,
-                                  bool enable) {
+HRESULT ToggleIntelVpSuperResolution(ID3D11VideoContext* video_context,
+                                     ID3D11VideoProcessor* video_processor,
+                                     bool enable) {
   TRACE_EVENT1("gpu", "ToggleIntelVpSuperResolution", "on", enable);
 
   IntelVpeExt ext = {};
@@ -229,7 +228,7 @@
   if (FAILED(hr)) {
     DLOG(ERROR) << "VideoProcessorSetOutputExtension failed with error 0x"
                 << std::hex << hr;
-    return false;
+    return hr;
   }
 
   ext.function = kIntelVpeFnMode;
@@ -242,7 +241,7 @@
   if (FAILED(hr)) {
     DLOG(ERROR) << "VideoProcessorSetOutputExtension failed with error 0x"
                 << std::hex << hr;
-    return false;
+    return hr;
   }
 
   ext.function = kIntelVpeFnScaling;
@@ -257,15 +256,14 @@
   if (FAILED(hr)) {
     DLOG(ERROR) << "VideoProcessorSetStreamExtension failed with error 0x"
                 << std::hex << hr;
-    return false;
   }
-  return enable;
+
+  return hr;
 }
 
-// Return true if VpSuperResolution has been set successfully.
-bool ToggleNvidiaVpSuperResolution(ID3D11VideoContext* video_context,
-                                   ID3D11VideoProcessor* video_processor,
-                                   bool enable) {
+HRESULT ToggleNvidiaVpSuperResolution(ID3D11VideoContext* video_context,
+                                      ID3D11VideoProcessor* video_processor,
+                                      bool enable) {
   TRACE_EVENT1("gpu", "ToggleNvidiaVpSuperResolution", "on", enable);
 
   constexpr GUID kNvidiaPPEInterfaceGUID = {
@@ -295,25 +293,27 @@
   if (FAILED(hr)) {
     DLOG(ERROR) << "VideoProcessorSetStreamExtension failed with error 0x"
                 << std::hex << hr;
-    return false;
   }
-  return enable;
+
+  return hr;
 }
 
-bool ToggleVpSuperResolution(UINT gpu_vendor_id,
-                             ID3D11VideoContext* video_context,
-                             ID3D11VideoProcessor* video_processor,
-                             bool enable) {
+HRESULT ToggleVpSuperResolution(UINT gpu_vendor_id,
+                                ID3D11VideoContext* video_context,
+                                ID3D11VideoProcessor* video_processor,
+                                bool enable) {
   if (gpu_vendor_id == 0x8086 &&
       base::FeatureList::IsEnabled(features::kIntelVpSuperResolution)) {
     return ToggleIntelVpSuperResolution(video_context, video_processor, enable);
   }
+
   if (gpu_vendor_id == 0x10de &&
       base::FeatureList::IsEnabled(features::kNvidiaVpSuperResolution)) {
     return ToggleNvidiaVpSuperResolution(video_context, video_processor,
                                          enable);
   }
-  return false;
+
+  return E_NOTIMPL;
 }
 
 bool IsWithinMargin(int i, int j) {
@@ -605,10 +605,10 @@
   if (params.clip_rect.has_value())
     clipped_onscreen_rect.Intersect(*visual_clip_rect);
 
-  // Restore after test
-  // if (clipped_onscreen_rect == gfx::Rect(monitor_size)) {
-  //  return true;
-  //}
+  // Skip adjustment if the current swap chain size is already correct.
+  if (clipped_onscreen_rect == gfx::Rect(monitor_size)) {
+    return true;
+  }
 
   // Because of the rounding when converting between pixels and DIPs, a
   // fullscreen video can become slightly larger than the monitor - e.g. on
@@ -825,10 +825,10 @@
     }
   }
 
-  // Restore after test
-  // if (new_onscreen_rect == clipped_onscreen_rect) {
-  //  return true;
-  //}
+  // Skip adjustment if the current swap chain size is already correct.
+  if (new_onscreen_rect == clipped_onscreen_rect) {
+    return;
+  }
 
   //
   // Adjust the clip rect.
@@ -1673,9 +1673,13 @@
     bool use_vp_super_resolution = false;
     if (!layer_tree_->disable_vp_super_resolution() &&
         !force_vp_super_resolution_off_) {
-      use_vp_super_resolution =
+      hr =
           ToggleVpSuperResolution(gpu_vendor_id_, video_context.Get(),
                                   video_processor.Get(), !is_on_battery_power_);
+      if (FAILED(hr)) {
+        force_vp_super_resolution_off_ = true;
+      }
+      use_vp_super_resolution = !is_on_battery_power_ && SUCCEEDED(hr);
     }
 
     hr = video_context->VideoProcessorBlt(video_processor.Get(),
diff --git a/ui/native_theme/native_theme.cc b/ui/native_theme/native_theme.cc
index 972b841..4c60eb7 100644
--- a/ui/native_theme/native_theme.cc
+++ b/ui/native_theme/native_theme.cc
@@ -52,7 +52,7 @@
       system_theme_,
       use_custom_frame ? ui::ColorProviderManager::FrameType::kChromium
                        : ui::ColorProviderManager::FrameType::kNative,
-      user_color_, std::move(custom_theme));
+      user_color_, scheme_variant_, std::move(custom_theme));
 }
 
 SkColor NativeTheme::GetSystemButtonPressedColor(SkColor base_color) const {
diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h
index 054fc3f6..f95db55 100644
--- a/ui/native_theme/native_theme.h
+++ b/ui/native_theme/native_theme.h
@@ -500,6 +500,14 @@
   }
   absl::optional<SkColor> user_color() const { return user_color_; }
 
+  void set_scheme_variant(
+      absl::optional<ui::ColorProviderManager::SchemeVariant> scheme_variant) {
+    scheme_variant_ = scheme_variant;
+  }
+  absl::optional<ui::ColorProviderManager::SchemeVariant> scheme_variant() {
+    return scheme_variant_;
+  }
+
   // Updates the state of dark mode, forced colors mode, and the map of system
   // colors. Returns true if NativeTheme was updated as a result, or false if
   // the state of NativeTheme was untouched.
@@ -583,9 +591,14 @@
   // Observers to notify when the native theme changes.
   base::ObserverList<NativeThemeObserver>::Unchecked native_theme_observers_;
 
-  // User's primary color. Included in the ColorProvider Key.
+  // User's primary color. Included in the `ColorProvider::Key` as the basis of
+  // all generated colors.
   absl::optional<SkColor> user_color_;
 
+  // System color scheme variant. Used in `ColorProvider::Key` to specify the
+  // transforms of `user_color_` which generate colors.
+  absl::optional<ui::ColorProviderManager::SchemeVariant> scheme_variant_;
+
   bool should_use_dark_colors_ = false;
   const ui::SystemTheme system_theme_;
   bool forced_colors_ = false;
diff --git a/ui/native_theme/native_theme_constants_fluent.h b/ui/native_theme/native_theme_constants_fluent.h
index 5bc76e6b..49b60d953 100644
--- a/ui/native_theme/native_theme_constants_fluent.h
+++ b/ui/native_theme/native_theme_constants_fluent.h
@@ -7,8 +7,8 @@
 
 namespace ui {
 
-constexpr int kFluentScrollbarThickness = 14;
-constexpr int kFluentScrollbarThumbThickness = 6;
+constexpr int kFluentScrollbarThickness = 15;
+constexpr int kFluentScrollbarThumbThickness = 9;
 
 // A sufficiently large value ensures the most round curve for the corners of
 // the scrollbar thumb.
@@ -32,18 +32,18 @@
 constexpr int kFluentScrollbarButtonSideLength = 18;
 
 // Arrow rect side length. The height and width of the rect are equal.
-constexpr int kFluentScrollbarArrowRectLength = 8;
+constexpr int kFluentScrollbarArrowRectLength = 9;
 
 // Arrow rect side length when the button is pressed. The height and width of
 // the rect are equal.
-constexpr int kFluentScrollbarPressedArrowRectLength = 7;
+constexpr int kFluentScrollbarPressedArrowRectLength = 8;
 
 // Use this length only when the font that contains arrow icons is not present
 // on the device and the default arrows are painted using SkPath. Since the
 // scrollbar thickness is an even number, we shift the odd rect from the
 // button's center. Also, we can avoid the usage of anti-aliasing, which tends
 // to produce visual defects on specific scales.
-constexpr int kFluentScrollbarPressedArrowRectFallbackLength = 6;
+constexpr int kFluentScrollbarPressedArrowRectFallbackLength = 7;
 
 // Offset the arrow icon by this amount off-center, away from the thumb.
 constexpr int kFluentScrollbarArrowOffset = 1;
diff --git a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
index 85d1164..cb818931 100644
--- a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
+++ b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
@@ -32,7 +32,7 @@
         color: var(--cr-primary-text-color);
         font: inherit;
         min-height: 32px;
-        padding: 0 24px;
+        padding: 8px 24px;
         text-align: start;
         user-select: none;
         width: 100%;
diff --git a/ui/webui/resources/mojo/BUILD.gn b/ui/webui/resources/mojo/BUILD.gn
index d97f8f47..a276f73 100644
--- a/ui/webui/resources/mojo/BUILD.gn
+++ b/ui/webui/resources/mojo/BUILD.gn
@@ -65,7 +65,10 @@
     "ui/latency/mojom/latency_info.mojom-webui.js",
   ]
 
-  mojo_ts_files += [ "chromeos/ash/services/hotspot_config/public/mojom/cros_hotspot_config.mojom-webui.ts" ]
+  mojo_ts_files += [
+    "chromeos/ash/services/connectivity/public/mojom/passpoint.mojom-webui.ts",
+    "chromeos/ash/services/hotspot_config/public/mojom/cros_hotspot_config.mojom-webui.ts",
+  ]
 }
 
 preprocess_if_expr("copy_mojo_ts") {
@@ -81,6 +84,7 @@
 
   if (is_chromeos_ash) {
     deps += [
+      "//chromeos/ash/services/connectivity/public/mojom:mojom_ts__generator",
       "//chromeos/ash/services/hotspot_config/public/mojom:mojom_ts__generator",
     ]
   }
diff --git a/ui/webui/resources/tools/PRESUBMIT.py b/ui/webui/resources/tools/PRESUBMIT.py
index c2dc654b..b0b32a7 100644
--- a/ui/webui/resources/tools/PRESUBMIT.py
+++ b/ui/webui/resources/tools/PRESUBMIT.py
@@ -7,8 +7,9 @@
 
 def _CheckChangeOnUploadOrCommit(input_api, output_api):
   results = []
-  webui_sources = set(
-      ['optimize_webui.py', 'rollup_plugin.js', 'generate_grd.py'])
+  webui_sources = set([
+      'optimize_webui.py', 'rollup_plugin.js', 'generate_grd.py', 'minify_js.py'
+  ])
   affected = input_api.AffectedFiles()
   affected_files = [input_api.os_path.basename(f.LocalPath()) for f in affected]
   if webui_sources.intersection(set(affected_files)):
@@ -18,7 +19,9 @@
 
 def RunPresubmitTests(input_api, output_api):
   presubmit_path = input_api.PresubmitLocalPath()
-  sources = ['optimize_webui_test.py', 'generate_grd_test.py']
+  sources = [
+      'optimize_webui_test.py', 'generate_grd_test.py', 'minify_js_test.py'
+  ]
   tests = [input_api.os_path.join(presubmit_path, s) for s in sources]
   return input_api.canned_checks.RunUnitTests(
       input_api, output_api, tests, run_on_python2=False)
diff --git a/ui/webui/resources/tools/build_webui.gni b/ui/webui/resources/tools/build_webui.gni
index 8d4ba38..e6226e72 100644
--- a/ui/webui/resources/tools/build_webui.gni
+++ b/ui/webui/resources/tools/build_webui.gni
@@ -13,6 +13,7 @@
 import("//tools/polymer/html_to_wrapper.gni")
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
+import("//ui/webui/resources/tools/minify_js.gni")
 import("//ui/webui/resources/tools/optimize_webui.gni")
 
 if (use_blink) {
@@ -38,7 +39,10 @@
     optimize = invoker.optimize
   }
 
-  optimize_ts = optimize && defined(invoker.optimize_webui_in_files)
+  minify_and_bundle = optimize && defined(invoker.optimize_webui_in_files)
+  if (!minify_and_bundle) {
+    minify_only = optimize && !defined(invoker.optimize_webui_in_files)
+  }
 
   enable_source_maps = false
   if (defined(invoker.enable_source_maps)) {
@@ -130,9 +134,10 @@
   #  4) ts_library()
   #  5) merge_js_source_maps() (only if the |invoker.enable_source_maps| flag is
   #     true)
-  #  6) optimize_webui() (only if |invoker.optimize| is true)
-  #  7) generate_grd()
-  #  8) grit()
+  #  6) optimize_webui() (only if invoker.optimize && defined(invoker.optimize_webui_in_files))
+  #  7) minify_js() (only if invoker.optimize && !defined(invoker.optimize_webui_in_files))
+  #  8) generate_grd()
+  #  9) grit()
 
   if (defined(invoker.static_files)) {
     preprocess_if_expr("preprocess_static_files") {
@@ -275,6 +280,7 @@
       visibility = [
         ":$generate_grd_target_name",
         ":build_bundle",
+        ":build_min_js",
       ]
 
       if (enable_source_maps) {
@@ -363,7 +369,7 @@
     }
   }
 
-  if (optimize_ts) {
+  if (minify_and_bundle) {
     bundle_manifest = "bundle_manifest.json"
 
     optimize_webui("build_bundle") {
@@ -382,6 +388,18 @@
 
       deps = [ ":build_ts" ]
     }
+  } else if (minify_only) {
+    minify_js("build_min_js") {
+      visibility = [ ":$generate_grd_target_name" ]
+      in_folder = ts_out_dir
+      out_folder = "$target_gen_dir/minified"
+      in_files = []
+      js_files = filter_include(get_target_outputs(":build_ts"), [ "*.js" ])
+      foreach(_js_file, js_files) {
+        in_files += [ string_replace(_js_file, "$ts_out_dir/", "") ]
+      }
+      deps = [ ":build_ts" ]
+    }
   }
 
   generate_grd(generate_grd_target_name) {
@@ -407,7 +425,7 @@
           [ "${target_gen_dir}/preprocess_static_files_manifest.json" ]
     }
 
-    if (optimize_ts) {
+    if (minify_and_bundle) {
       deps += [ ":build_bundle" ]
       manifest_files += [ "$target_gen_dir/$bundle_manifest" ]
       resource_path_rewrites = []
@@ -416,6 +434,9 @@
         output_file = string_replace(f, "${name}.js", "${name}.rollup.js")
         resource_path_rewrites += [ "${output_file}|${f}" ]
       }
+    } else if (minify_only) {
+      deps += [ ":build_min_js" ]
+      manifest_files += [ "$target_gen_dir/minify_js_manifest.json" ]
     } else {
       if (enable_source_maps) {
         deps += [ ":merge_source_maps" ]
diff --git a/ui/webui/resources/tools/minify_js.gni b/ui/webui/resources/tools/minify_js.gni
new file mode 100644
index 0000000..bc72d1f6
--- /dev/null
+++ b/ui/webui/resources/tools/minify_js.gni
@@ -0,0 +1,39 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/node/node.gni")
+
+template("minify_js") {
+  node(target_name) {
+    script = "//ui/webui/resources/tools/minify_js.py"
+    forward_variables_from(invoker,
+                           [
+                             "visibility",
+                             "deps",
+                             "in_folder",
+                             "out_folder",
+                           ])
+
+    inputs = []
+    outputs = []
+    foreach(f, invoker.in_files) {
+      assert(get_path_info(f, "extension") == "js")
+      inputs += [ "$in_folder/$f" ]
+      outputs += [ "$out_folder/$f" ]
+    }
+
+    args = [
+             "--in_folder",
+             rebase_path(in_folder, root_build_dir),
+             "--out_folder",
+             rebase_path(out_folder, root_build_dir),
+             "--out_manifest",
+             rebase_path("$target_gen_dir/minify_js_manifest.json",
+                         root_build_dir),
+             "--in_files",
+           ] + invoker.in_files
+
+    outputs += [ "$target_gen_dir/minify_js_manifest.json" ]
+  }
+}
diff --git a/ui/webui/resources/tools/minify_js.py b/ui/webui/resources/tools/minify_js.py
new file mode 100755
index 0000000..37c2efb
--- /dev/null
+++ b/ui/webui/resources/tools/minify_js.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import json
+import sys
+import os
+
+_HERE_PATH = os.path.dirname(__file__)
+_SRC_PATH = os.path.normpath(os.path.join(_HERE_PATH, '..', '..', '..', '..'))
+_CWD = os.getcwd()
+
+sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'node'))
+import node
+import node_modules
+
+
+def main(argv):
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--in_folder', required=True)
+  parser.add_argument('--out_folder', required=True)
+  parser.add_argument('--in_files', nargs='*', required=True)
+  parser.add_argument('--out_manifest', required=True)
+
+  args = parser.parse_args(argv)
+  out_path = os.path.normpath(
+      os.path.join(_CWD, args.out_folder).replace('\\', '/'))
+  in_path = os.path.normpath(
+      os.path.join(_CWD, args.in_folder).replace('\\', '/'))
+
+  for input_file in args.in_files:
+    node.RunNode([
+        node_modules.PathToTerser(),
+        os.path.join(in_path, input_file), '--comments',
+        '/Copyright|license|LICENSE/', '--output',
+        os.path.join(out_path, input_file)
+    ])
+
+  manifest_data = {}
+  manifest_data['base_dir'] = args.out_folder
+  manifest_data['files'] = args.in_files
+  with open(os.path.normpath(os.path.join(_CWD, args.out_manifest)), 'w') \
+      as manifest_file:
+    json.dump(manifest_data, manifest_file)
+
+
+if __name__ == '__main__':
+  main(sys.argv[1:])
diff --git a/ui/webui/resources/tools/minify_js_test.py b/ui/webui/resources/tools/minify_js_test.py
new file mode 100755
index 0000000..b8fd71f0
--- /dev/null
+++ b/ui/webui/resources/tools/minify_js_test.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import minify_js
+import os
+import tempfile
+import shutil
+import unittest
+
+_HERE_DIR = os.path.dirname(__file__)
+
+
+class MinifyJsTest(unittest.TestCase):
+
+  def setUp(self):
+    self._out_dir = tempfile.mkdtemp(dir=_HERE_DIR)
+
+  def tearDown(self):
+    shutil.rmtree(self._out_dir)
+
+  def _read_file(self, path):
+    with open(path, 'r') as file:
+      return file.read()
+
+  def _run_test(self, in_files, expected_files):
+    manifest_path = os.path.join(self._out_dir, "manifest.json")
+    args = [
+        "--in_folder",
+        os.path.join(_HERE_DIR, "tests", "minify_js"),
+        "--out_folder",
+        self._out_dir,
+        "--out_manifest",
+        manifest_path,
+        "--in_files",
+        *in_files,
+    ]
+
+    minify_js.main(args)
+
+    manifest_contents = self._read_file(manifest_path)
+    manifest_data = json.loads(self._read_file(manifest_path))
+
+    self.assertEqual(manifest_data['base_dir'], self._out_dir)
+
+    for index, in_file in enumerate(in_files):
+      actual_contents = self._read_file(os.path.join(self._out_dir, in_file))
+      expected_contents = self._read_file(expected_files[index])
+      self.assertMultiLineEqual(expected_contents, actual_contents)
+      self.assertTrue(in_file in manifest_data['files'])
+
+  def testMinifySimpleFile(self):
+    self._run_test(["foo.js"], ["tests/minify_js/foo_expected.js"])
+
+  def testMinifyComplexFile(self):
+    self._run_test(["bar.js"], ["tests/minify_js/bar_expected.js"])
+
+  def testMinifyMultipleFiles(self):
+    self._run_test(
+        ["foo.js", "bar.js"],
+        ["tests/minify_js/foo_expected.js", "tests/minify_js/bar_expected.js"])
+
+
+if __name__ == "__main__":
+  unittest.main()
diff --git a/ui/webui/resources/tools/tests/minify_js/bar.js b/ui/webui/resources/tools/tests/minify_js/bar.js
new file mode 100644
index 0000000..fdea861
--- /dev/null
+++ b/ui/webui/resources/tools/tests/minify_js/bar.js
@@ -0,0 +1,10 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// comments should be removed
+const foo = {
+    'bar': 0,
+    baz: 5,
+};
+const qux = foo.bar + foo.baz;
diff --git a/ui/webui/resources/tools/tests/minify_js/bar_expected.js b/ui/webui/resources/tools/tests/minify_js/bar_expected.js
new file mode 100644
index 0000000..4c05219
--- /dev/null
+++ b/ui/webui/resources/tools/tests/minify_js/bar_expected.js
@@ -0,0 +1,4 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+const foo={bar:0,baz:5};const qux=foo.bar+foo.baz;
\ No newline at end of file
diff --git a/ui/webui/resources/tools/tests/minify_js/foo.js b/ui/webui/resources/tools/tests/minify_js/foo.js
new file mode 100644
index 0000000..a006727b
--- /dev/null
+++ b/ui/webui/resources/tools/tests/minify_js/foo.js
@@ -0,0 +1,5 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+const foo = 0;
diff --git a/ui/webui/resources/tools/tests/minify_js/foo_expected.js b/ui/webui/resources/tools/tests/minify_js/foo_expected.js
new file mode 100644
index 0000000..f71abc5
--- /dev/null
+++ b/ui/webui/resources/tools/tests/minify_js/foo_expected.js
@@ -0,0 +1,4 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+const foo=0;
\ No newline at end of file
diff --git a/weblayer/BUILD.gn b/weblayer/BUILD.gn
index 8dafca7..073c5b7c 100644
--- a/weblayer/BUILD.gn
+++ b/weblayer/BUILD.gn
@@ -836,32 +836,6 @@
     ]
   }
 
-  # Lib used in standalone WebView which allows manual JNI registration.
-  static_library("weblayer_lib_webview") {
-    public_deps = [ ":weblayer_lib_base" ]
-    deps = [
-      "//base",
-      "//weblayer/browser/java:jni",
-      "//weblayer/browser/java:weblayer_jni_registration($default_toolchain)",
-    ]
-    sources = [
-      "browser/web_view_compatibility_helper_impl.cc",
-      "browser/web_view_compatibility_helper_impl.h",
-    ]
-    defines = [ "WEBLAYER_MANUAL_JNI_REGISTRATION" ]
-
-    # Explicit dependency required for JNI registration to be able to
-    # find the native side functions.
-    if (is_component_build) {
-      deps += [
-        "//components/browser_ui/photo_picker/android",
-        "//device/gamepad",
-        "//media/midi",
-        "//ui/events/devices",
-      ]
-    }
-  }
-
   static_library("weblayer_lib_webview_test") {
     testonly = true
     public_deps = [ ":weblayer_lib_base" ]
@@ -869,13 +843,7 @@
       ":weblayer_android_test_jni_impl",
       "//base",
       "//weblayer/browser/java:jni",
-      "//weblayer/browser/java:weblayer_jni_registration($default_toolchain)",
     ]
-    sources = [
-      "browser/web_view_compatibility_helper_impl.cc",
-      "browser/web_view_compatibility_helper_impl.h",
-    ]
-    defines = [ "WEBLAYER_MANUAL_JNI_REGISTRATION" ]
 
     # Explicit dependency required for JNI registration to be able to
     # find the native side functions.
@@ -893,10 +861,6 @@
   static_library("weblayer_lib") {
     public_deps = [ ":weblayer_lib_base" ]
     deps = [ "//weblayer/browser/java:jni" ]
-    sources = [
-      "browser/web_view_compatibility_helper_impl.cc",
-      "browser/web_view_compatibility_helper_impl.h",
-    ]
   }
 
   shared_library("libweblayer_test") {
@@ -907,7 +871,6 @@
       "//base",
       "//components/android_autofill/browser/test_support:native",
       "//content/public/app",
-      "//weblayer/browser/java:test_weblayer_jni_registration($default_toolchain)",
     ]
     configs -= [ "//build/config/android:hide_all_but_jni_onload" ]
     configs += [ "//build/config/android:hide_all_but_jni" ]
diff --git a/weblayer/app/entry_point.cc b/weblayer/app/entry_point.cc
index 5e140ee..cf69f1b 100644
--- a/weblayer/app/entry_point.cc
+++ b/weblayer/app/entry_point.cc
@@ -5,8 +5,6 @@
 #include "base/android/jni_android.h"
 #include "base/android/library_loader/library_loader_hooks.h"
 #include "weblayer/app/jni_onload.h"
-#include "weblayer/browser/java/test_weblayer_jni_registration_generated.h"
-#include "weblayer/browser/web_view_compatibility_helper_impl.h"
 
 namespace {
 
@@ -18,11 +16,6 @@
 
 JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
   base::android::InitVM(vm);
-  JNIEnv* env = base::android::AttachCurrentThread();
-  if (!weblayer_test::RegisterNatives(env) ||
-      !weblayer::MaybeRegisterNatives()) {
-    return -1;
-  }
   base::android::SetNativeInitializationHook(&NativeInit);
   return JNI_VERSION_1_4;
 }
diff --git a/weblayer/browser/java/BUILD.gn b/weblayer/browser/java/BUILD.gn
index 262169d..1b411748 100644
--- a/weblayer/browser/java/BUILD.gn
+++ b/weblayer/browser/java/BUILD.gn
@@ -92,7 +92,6 @@
   sources = [
     "org/chromium/weblayer_private/ApplicationInfoHelper.java",
     "org/chromium/weblayer_private/ChildProcessServiceImpl.java",
-    "org/chromium/weblayer_private/WebViewCompatibilityHelperImpl.java",
   ]
   deps = [
     ":base_module_interfaces_java",
@@ -442,21 +441,6 @@
   ]
 }
 
-if (current_toolchain == default_toolchain) {
-  generate_jni_registration("weblayer_jni_registration") {
-    targets = [ ":java" ]
-    manual_jni_registration = true
-    namespace = "weblayer"
-  }
-
-  generate_jni_registration("test_weblayer_jni_registration") {
-    testonly = true
-    targets = [ ":test_java" ]
-    manual_jni_registration = true
-    namespace = "weblayer_test"
-  }
-}
-
 generate_jni("test_jni") {
   testonly = true
   sources = [
@@ -497,7 +481,6 @@
     "org/chromium/weblayer_private/WebLayerExceptionFilter.java",
     "org/chromium/weblayer_private/WebLayerFactoryImpl.java",
     "org/chromium/weblayer_private/WebLayerImpl.java",
-    "org/chromium/weblayer_private/WebViewCompatibilityHelperImpl.java",
     "org/chromium/weblayer_private/WebappsHelper.java",
     "org/chromium/weblayer_private/bluetooth/WebLayerBluetoothChooserAndroidDelegate.java",
     "org/chromium/weblayer_private/bluetooth/WebLayerBluetoothScanningPromptAndroidDelegate.java",
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/WebViewCompatibilityHelperImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/WebViewCompatibilityHelperImpl.java
deleted file mode 100644
index 369d778a..0000000
--- a/weblayer/browser/java/org/chromium/weblayer_private/WebViewCompatibilityHelperImpl.java
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.weblayer_private;
-
-import org.chromium.base.annotations.CalledByNative;
-import org.chromium.base.annotations.JNINamespace;
-
-/**
- * Helper class to tell native code whether manual JNI registration is required.
- */
-@JNINamespace("weblayer")
-public final class WebViewCompatibilityHelperImpl {
-    private static boolean sRequiresManualJniRegistration;
-
-    @CalledByNative
-    private static boolean requiresManualJniRegistration() {
-        return sRequiresManualJniRegistration;
-    }
-
-    public static void setRequiresManualJniRegistration(boolean isRequired) {
-        sRequiresManualJniRegistration = isRequired;
-    }
-}
diff --git a/weblayer/browser/web_view_compatibility_helper_impl.cc b/weblayer/browser/web_view_compatibility_helper_impl.cc
deleted file mode 100644
index b9d9720..0000000
--- a/weblayer/browser/web_view_compatibility_helper_impl.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#if defined(WEBLAYER_MANUAL_JNI_REGISTRATION)
-#include "base/android/library_loader/library_loader_hooks.h"  // nogncheck
-#include "weblayer/browser/java/jni/WebViewCompatibilityHelperImpl_jni.h"  // nogncheck
-#include "weblayer/browser/java/weblayer_jni_registration_generated.h"  // nogncheck
-#endif
-
-namespace weblayer {
-
-bool MaybeRegisterNatives() {
-#if defined(WEBLAYER_MANUAL_JNI_REGISTRATION)
-  JNIEnv* env = base::android::AttachCurrentThread();
-  if (Java_WebViewCompatibilityHelperImpl_requiresManualJniRegistration(env)) {
-    if (!RegisterNatives(env)) {
-      return false;
-    }
-  }
-#endif
-  return true;
-}
-
-}  // namespace weblayer
diff --git a/weblayer/browser/web_view_compatibility_helper_impl.h b/weblayer/browser/web_view_compatibility_helper_impl.h
deleted file mode 100644
index 4c5c27df..0000000
--- a/weblayer/browser/web_view_compatibility_helper_impl.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WEBLAYER_BROWSER_WEB_VIEW_COMPATIBILITY_HELPER_IMPL_H_
-#define WEBLAYER_BROWSER_WEB_VIEW_COMPATIBILITY_HELPER_IMPL_H_
-
-namespace weblayer {
-
-// Manually registers JNI for WebLayer if necessary.
-bool MaybeRegisterNatives();
-
-}  // namespace weblayer
-
-#endif  // WEBLAYER_BROWSER_WEB_VIEW_COMPATIBILITY_HELPER_IMPL_H_