diff --git a/DEPS b/DEPS
index 71522a2..7b9045e 100644
--- a/DEPS
+++ b/DEPS
@@ -204,11 +204,11 @@
   # 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': '5f9ba6953f8dcc47aac69b3b212cf5ba7ae62c5a',
+  'skia_revision': 'c0c5106bd4d4f5c0142221109563eee45663eef5',
   # 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': '8c8f17af29f1a4073630ba7ca924ddb4ca45abd6',
+  'v8_revision': '04e154e4ca48094b482c0f1d77803987ec7b7cc6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -216,7 +216,7 @@
   # 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': '19a302fca592e3825998b78b7d7d075c51f3c4f6',
+  'angle_revision': '1ad5791d97bea23f092b206679a56302defa378f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -271,7 +271,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '5537c0394234a7fdd580c4c5b5a943d7c934e400',
+  'catapult_revision': 'd1cf5db4152d162ef170c43626872c897625cc9f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -279,7 +279,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': '38f2fff09dacc4d9cd0c477893b2a97e50522952',
+  'devtools_frontend_revision': '63989d27ead708330f28ebce558f547cee3e4300',
   # 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.
@@ -567,7 +567,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '8d8763ef717236005cdb7300e1c712038a337f72',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '62ccb5c72fb6822c7199abbeeafcba8dd61e34e0',
       'condition': 'checkout_ios',
   },
 
@@ -923,7 +923,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '1ec57124a67c6fd4ea2f2fe9ce9fdb6c31d3fd5d',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '968b1fe7d7cb848e250ffb62e27f547450f5b9e9',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1295,7 +1295,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '8ddf5ae4b8a57c7acc28dad9f2e3857c1d3b7bc0',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '0fdb2247e82e7f60e5391c674ce7267019a5692d',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1373,7 +1373,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': 'yKXInPLMrLZXhnetjQTEJav1jUW4zl7skzS8L51VrQYC'
+              'version': 'Ld6Ho8txe7fnUwYDIgKsMmU0e2gBZ9Zx1n43O83aofUC'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1545,7 +1545,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '3c2fe3888658d82b47ca831d59a2e07579619c2d',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '10f76ac226f2b569924a5060d4dd2ca1231aa30a',
+    Var('webrtc_git') + '/src.git' + '@' + '31d3b217d3b5c9e98559bb0ef9612659b36e88e5',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1617,7 +1617,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ba66a670730d83bd2b6992ec9da5e242b0fce21a',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d472d834dbda0e46609e789bd5336f1e245e37e9',
     'condition': 'checkout_src_internal',
   },
 
@@ -1636,7 +1636,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': '6AHX-97XEsRATZXtxtSFgMgB4HPdjrF2NmTP1UctxQQC',
+        'version': '9Aak3tK4oVEWWOriZzuRXEUPGWU0lUrVTTcsG4FucPgC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 2835b34a..a81d5c4 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -333,7 +333,6 @@
   '^chrome/browser/history/',
   '^chrome/browser/lifetime/',
   '^chrome/browser/media_galleries/',
-  '^chrome/browser/media/',
   '^chrome/browser/net/',
   '^chrome/browser/notifications/',
   '^chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc',
@@ -361,7 +360,6 @@
   '^chrome/browser/service_process/',
   '^chrome/browser/signin/',
   '^chrome/browser/site_isolation/site_per_process_text_input_browsertest.cc',
-  '^chrome/browser/ssl/',
   '^chrome/browser/supervised_user/',
   '^chrome/browser/sync_file_system/',
   '^chrome/browser/thumbnail/cc/',
diff --git a/android_webview/OWNERS b/android_webview/OWNERS
index 7fe521d..5a3e874 100644
--- a/android_webview/OWNERS
+++ b/android_webview/OWNERS
@@ -1,8 +1,6 @@
 boliu@chromium.org
-changwan@chromium.org
 michaelbai@chromium.org
 ntfschr@chromium.org
-tobiasjs@chromium.org
 torne@chromium.org
 
 # Documentation changes:
diff --git a/ash/app_list/app_list_color_provider_impl.cc b/ash/app_list/app_list_color_provider_impl.cc
index f2f093b..821fb6d9 100644
--- a/ash/app_list/app_list_color_provider_impl.cc
+++ b/ash/app_list/app_list_color_provider_impl.cc
@@ -186,6 +186,18 @@
       SkColorSetA(gfx::kGoogleGrey900, 0x12));
 }
 
+SkColor AppListColorProviderImpl::GetFocusRingColor() const {
+  return DeprecatedGetControlsLayerColor(
+      AshColorProvider::ControlsLayerType::kControlBackgroundColorActive,
+      gfx::kGoogleBlue300);
+}
+
+SkColor AppListColorProviderImpl::GetFolderItemFocusRingColor() const {
+  return DeprecatedGetControlsLayerColor(
+      AshColorProvider::ControlsLayerType::kControlBackgroundColorActive,
+      gfx::kGoogleBlue600);
+}
+
 float AppListColorProviderImpl::GetFolderBackgrounBlurSigma() const {
   return static_cast<float>(AshColorProvider::LayerBlurSigma::kBlurDefault);
 }
diff --git a/ash/app_list/app_list_color_provider_impl.h b/ash/app_list/app_list_color_provider_impl.h
index c8e60be72..d1b5b925 100644
--- a/ash/app_list/app_list_color_provider_impl.h
+++ b/ash/app_list/app_list_color_provider_impl.h
@@ -46,6 +46,8 @@
   SkColor GetSeparatorColor() const override;
   SkColor GetSearchResultViewHighlightColor() const override;
   SkColor GetSearchResultViewInkDropColor() const override;
+  SkColor GetFocusRingColor() const override;
+  SkColor GetFolderItemFocusRingColor() const override;
   float GetFolderBackgrounBlurSigma() const override;
 
  private:
diff --git a/ash/app_list/test/test_app_list_color_provider.cc b/ash/app_list/test/test_app_list_color_provider.cc
index d1372f1e..3318835a 100644
--- a/ash/app_list/test/test_app_list_color_provider.cc
+++ b/ash/app_list/test/test_app_list_color_provider.cc
@@ -132,6 +132,14 @@
   return SkColorSetA(SK_ColorWHITE, 0x17);
 }
 
+SkColor TestAppListColorProvider::GetFocusRingColor() const {
+  return gfx::kGoogleBlue300;
+}
+
+SkColor TestAppListColorProvider::GetFolderItemFocusRingColor() const {
+  return gfx::kGoogleBlue600;
+}
+
 float TestAppListColorProvider::GetFolderBackgrounBlurSigma() const {
   return 30.0f;
 }
diff --git a/ash/app_list/test/test_app_list_color_provider.h b/ash/app_list/test/test_app_list_color_provider.h
index 1e32608..3f7a3560 100644
--- a/ash/app_list/test/test_app_list_color_provider.h
+++ b/ash/app_list/test/test_app_list_color_provider.h
@@ -46,6 +46,8 @@
   SkColor GetSeparatorColor() const override;
   SkColor GetSearchResultViewHighlightColor() const override;
   SkColor GetSearchResultViewInkDropColor() const override;
+  SkColor GetFocusRingColor() const override;
+  SkColor GetFolderItemFocusRingColor() const override;
   float GetFolderBackgrounBlurSigma() const override;
 };
 
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc
index 1c50b2b5d..27a41fbb 100644
--- a/ash/app_list/views/app_list_item_view.cc
+++ b/ash/app_list/views/app_list_item_view.cc
@@ -72,9 +72,6 @@
 // The drag and drop icon scaling up or down animation transition duration.
 constexpr int kDragDropAppIconScaleTransitionInMs = 200;
 
-// The color of the focus ring within a folder.
-constexpr SkColor kFolderGridFocusRingColor = gfx::kGoogleBlue600;
-
 // The color of an item selected via right-click context menu.
 constexpr SkColor kContextSelection =
     SkColorSetA(SK_ColorWHITE, 41);  // 16% opacity
@@ -691,9 +688,10 @@
     cc::PaintFlags flags;
     flags.setAntiAlias(true);
     if (delegate_->KeyboardTraversalEngaged()) {
-      flags.setColor(apps_grid_view_->is_in_folder()
-                         ? kFolderGridFocusRingColor
-                         : GetAppListConfig().grid_selected_color());
+      flags.setColor(
+          apps_grid_view_->is_in_folder()
+              ? AppListColorProvider::Get()->GetFolderItemFocusRingColor()
+              : AppListColorProvider::Get()->GetFocusRingColor());
       flags.setStyle(cc::PaintFlags::kStroke_Style);
       flags.setStrokeWidth(kFocusRingWidth);
     } else {
diff --git a/ash/app_list/views/expand_arrow_view.cc b/ash/app_list/views/expand_arrow_view.cc
index 6a0f0674..ffb1e20 100644
--- a/ash/app_list/views/expand_arrow_view.cc
+++ b/ash/app_list/views/expand_arrow_view.cc
@@ -75,7 +75,6 @@
 constexpr auto kCycleDuration = base::TimeDelta::FromMilliseconds(1000);
 constexpr auto kCycleInterval = base::TimeDelta::FromMilliseconds(500);
 
-constexpr SkColor kFocusRingColor = gfx::kGoogleBlue300;
 constexpr int kFocusRingWidth = 2;
 
 // THe bounds for the tap target of the expand arrow button.
@@ -198,7 +197,7 @@
   if (HasFocus()) {
     cc::PaintFlags focus_ring_flags;
     focus_ring_flags.setAntiAlias(true);
-    focus_ring_flags.setColor(kFocusRingColor);
+    focus_ring_flags.setColor(AppListColorProvider::Get()->GetFocusRingColor());
     focus_ring_flags.setStyle(cc::PaintFlags::Style::kStroke_Style);
     focus_ring_flags.setStrokeWidth(kFocusRingWidth);
 
diff --git a/ash/app_list/views/search_box_view.cc b/ash/app_list/views/search_box_view.cc
index fc02aa1d..956979a 100644
--- a/ash/app_list/views/search_box_view.cc
+++ b/ash/app_list/views/search_box_view.cc
@@ -65,8 +65,6 @@
 // Padding between the focus ring and the search box view
 constexpr int kSearchBoxFocusRingPadding = 4;
 
-constexpr SkColor kSearchBoxFocusRingColor = gfx::kGoogleBlue300;
-
 constexpr int kSearchBoxFocusRingCornerRadius = 28;
 
 // Minimum amount of characters required to enable autocomplete.
@@ -210,7 +208,7 @@
     bounds.Inset(-kSearchBoxFocusRingPadding, -kSearchBoxFocusRingPadding);
     cc::PaintFlags flags;
     flags.setAntiAlias(true);
-    flags.setColor(kSearchBoxFocusRingColor);
+    flags.setColor(AppListColorProvider::Get()->GetFocusRingColor());
     flags.setStyle(cc::PaintFlags::Style::kStroke_Style);
     flags.setStrokeWidth(kSearchBoxFocusRingWidth);
     canvas->DrawRoundRect(bounds, kSearchBoxFocusRingCornerRadius, flags);
diff --git a/ash/app_list/views/search_result_actions_view.cc b/ash/app_list/views/search_result_actions_view.cc
index f4051b3..689f6ef 100644
--- a/ash/app_list/views/search_result_actions_view.cc
+++ b/ash/app_list/views/search_result_actions_view.cc
@@ -34,6 +34,8 @@
 // Image buttons.
 constexpr int kImageButtonSizeDip = 40;
 constexpr int kActionButtonBetweenSpacing = 8;
+// The width of the focus ring.
+constexpr int kFocusRingWidth = 2;
 
 }  // namespace
 
@@ -62,7 +64,7 @@
 
   void SetButtonImage(const gfx::ImageSkia& source, int icon_dimension);
 
-  int GetInkDropRadius() const;
+  int GetButtonRadius() const;
   const char* GetClassName() const override;
 
   SearchResultActionsView* parent_;
@@ -121,7 +123,7 @@
 std::unique_ptr<views::InkDropRipple>
 SearchResultImageButton::CreateInkDropRipple() const {
   const gfx::Point center = GetLocalBounds().CenterPoint();
-  const int ripple_radius = GetInkDropRadius();
+  const int ripple_radius = GetButtonRadius();
   gfx::Rect bounds(center.x() - ripple_radius, center.y() - ripple_radius,
                    2 * ripple_radius, 2 * ripple_radius);
   SkColor ripple_color =
@@ -152,11 +154,11 @@
   if (HasFocus() || parent_->GetSelectedAction() == tag()) {
     cc::PaintFlags circle_flags;
     circle_flags.setAntiAlias(true);
-    circle_flags.setColor(
-        AppListColorProvider::Get()->GetSearchResultViewHighlightColor());
-    circle_flags.setStyle(cc::PaintFlags::kFill_Style);
-    canvas->DrawCircle(GetLocalBounds().CenterPoint(), GetInkDropRadius(),
-                       circle_flags);
+    circle_flags.setColor(AppListColorProvider::Get()->GetFocusRingColor());
+    circle_flags.setStyle(cc::PaintFlags::kStroke_Style);
+    circle_flags.setStrokeWidth(kFocusRingWidth);
+    canvas->DrawCircle(GetLocalBounds().CenterPoint(),
+                       GetButtonRadius() - kFocusRingWidth, circle_flags);
   }
 }
 
@@ -168,7 +170,7 @@
                gfx::Size(icon_dimension, icon_dimension)));
 }
 
-int SearchResultImageButton::GetInkDropRadius() const {
+int SearchResultImageButton::GetButtonRadius() const {
   return width() / 2;
 }
 
diff --git a/ash/app_list/views/search_result_suggestion_chip_view.cc b/ash/app_list/views/search_result_suggestion_chip_view.cc
index 63158c4..930a987 100644
--- a/ash/app_list/views/search_result_suggestion_chip_view.cc
+++ b/ash/app_list/views/search_result_suggestion_chip_view.cc
@@ -34,7 +34,6 @@
 namespace {
 
 constexpr SkColor kRippleColor = SkColorSetA(gfx::kGoogleGrey100, 0x0F);
-constexpr SkColor kFocusRingColor = gfx::kGoogleBlue300;
 constexpr int kMaxTextWidth = 192;
 constexpr int kBlurRadius = 5;
 constexpr int kIconMarginDip = 8;
@@ -61,7 +60,7 @@
                           base::Unretained(this)));
 
   SetInstallFocusRingOnFocus(true);
-  focus_ring()->SetColor(kFocusRingColor);
+  focus_ring()->SetColor(AppListColorProvider::Get()->GetFocusRingColor());
 
   SetInkDropMode(InkDropMode::ON);
   views::InstallPillHighlightPathGenerator(this);
@@ -126,9 +125,10 @@
 
   // Focus Ring should only be visible when keyboard traversal is occurring.
   if (view_delegate_->KeyboardTraversalEngaged())
-    focus_ring()->SetColor(kFocusRingColor);
+    focus_ring()->SetColor(AppListColorProvider::Get()->GetFocusRingColor());
   else
-    focus_ring()->SetColor(SkColorSetA(kFocusRingColor, 0));
+    focus_ring()->SetColor(
+        SkColorSetA(AppListColorProvider::Get()->GetFocusRingColor(), 0));
 }
 
 void SearchResultSuggestionChipView::OnFocus() {
diff --git a/ash/app_list/views/search_result_tile_item_view.cc b/ash/app_list/views/search_result_tile_item_view.cc
index 25e42d5..cc7c683 100644
--- a/ash/app_list/views/search_result_tile_item_view.cc
+++ b/ash/app_list/views/search_result_tile_item_view.cc
@@ -41,6 +41,9 @@
 
 namespace {
 
+// The width of the focus ring.
+constexpr int kFocusRingWidth = 2;
+
 constexpr int kSearchTileWidth = 80;
 constexpr int kSearchTileTopPadding = 4;
 constexpr int kSearchTitleSpacing = 7;
@@ -298,20 +301,19 @@
   gfx::Rect rect(GetContentsBounds());
   cc::PaintFlags flags;
   flags.setAntiAlias(true);
-  flags.setStyle(cc::PaintFlags::kFill_Style);
+  flags.setStyle(cc::PaintFlags::kStroke_Style);
+  flags.setStrokeWidth(kFocusRingWidth);
+  flags.setColor(AppListColorProvider::Get()->GetFocusRingColor());
+
   if (IsSuggestedAppTileShownInAppPage()) {
     rect.ClampToCenteredSize(AppListConfig::instance().grid_focus_size());
-    flags.setColor(
-        AppListColorProvider::Get()->GetSearchResultViewInkDropColor());
     canvas->DrawRoundRect(gfx::RectF(rect),
                           AppListConfig::instance().grid_focus_corner_radius(),
                           flags);
   } else {
     const int kLeftRightPadding = (rect.width() - kIconSelectedSize) / 2;
-    rect.Inset(kLeftRightPadding, 0);
-    rect.set_height(kIconSelectedSize);
-    flags.setColor(
-        AppListColorProvider::Get()->GetSearchResultViewInkDropColor());
+    rect.Inset(kLeftRightPadding, kFocusRingWidth);
+    rect.set_height(kIconSelectedSize - 2 * kFocusRingWidth);
     canvas->DrawRoundRect(gfx::RectF(rect), kIconSelectedCornerRadius, flags);
   }
 }
diff --git a/ash/app_list/views/search_result_view.cc b/ash/app_list/views/search_result_view.cc
index 948a1ba..b7cf9926 100644
--- a/ash/app_list/views/search_result_view.cc
+++ b/ash/app_list/views/search_result_view.cc
@@ -47,8 +47,8 @@
 
 // URL color.
 constexpr SkColor kUrlColor = gfx::kGoogleBlue600;
-// Search result border color.
-constexpr SkColor kResultBorderColor = SkColorSetARGB(0xFF, 0xE5, 0xE5, 0xE5);
+// The width of the focus bar.
+constexpr int kFocusBarWidth = 3;
 
 // Delta applied to font size of all AppListSearchResult titles.
 constexpr int kSearchResultTitleTextSizeDelta = 2;
@@ -271,17 +271,6 @@
       text_bounds,
       AppListColorProvider::Get()->GetSearchBoxCardBackgroundColor());
 
-  // Possibly call FillRect a second time (these colours are partially
-  // transparent, so the previous FillRect is not redundant).
-  if (selected() && !actions_view()->HasSelectedAction()) {
-    canvas->FillRect(
-        content_rect,
-        AppListColorProvider::Get()->GetSearchResultViewHighlightColor());
-  }
-
-  gfx::Rect border_bottom = gfx::SubtractRects(rect, content_rect);
-  canvas->FillRect(border_bottom, kResultBorderColor);
-
   if (title_text_ && details_text_) {
     gfx::Size title_size(text_bounds.width(), kTitleLineHeight);
     gfx::Size details_size(text_bounds.width(), kDetailsLineHeight);
@@ -304,6 +293,33 @@
     title_text_->SetDisplayRect(centered_title_rect);
     title_text_->Draw(canvas);
   }
+
+  // Possibly call FillRect a second time (these colours are partially
+  // transparent, so the previous FillRect is not redundant).
+  if (selected() && !actions_view()->HasSelectedAction()) {
+    // Fill search result view row item.
+    canvas->FillRect(
+        content_rect,
+        AppListColorProvider::Get()->GetSearchResultViewHighlightColor());
+
+    SkPath path;
+    gfx::Rect focus_ring_bounds = content_rect;
+    focus_ring_bounds.set_x(focus_ring_bounds.x() - kFocusBarWidth);
+    focus_ring_bounds.set_width(kFocusBarWidth * 2);
+    path.addRRect(SkRRect::MakeRectXY(RectToSkRect(focus_ring_bounds),
+                                      kFocusBarWidth, kFocusBarWidth));
+    canvas->ClipPath(path, true);
+
+    cc::PaintFlags flags;
+    flags.setAntiAlias(true);
+    flags.setColor(AppListColorProvider::Get()->GetFocusRingColor());
+    flags.setStyle(cc::PaintFlags::kStroke_Style);
+    flags.setStrokeWidth(kFocusBarWidth);
+    gfx::Point top_point = content_rect.origin();
+    gfx::Point bottom_point =
+        top_point + gfx::Vector2d(0, content_rect.height());
+    canvas->DrawLine(top_point, bottom_point, flags);
+  }
 }
 
 void SearchResultView::OnMouseEntered(const ui::MouseEvent& event) {
diff --git a/ash/clipboard/clipboard_history.cc b/ash/clipboard/clipboard_history.cc
index 6625ba8..ff9327c 100644
--- a/ash/clipboard/clipboard_history.cc
+++ b/ash/clipboard/clipboard_history.cc
@@ -56,7 +56,10 @@
   if (iter == history_list_.cend())
     return;
 
+  auto removed = std::move(*iter);
   history_list_.erase(iter);
+  for (auto& observer : observers_)
+    observer.OnClipboardHistoryItemRemoved(removed);
 }
 
 void ClipboardHistory::OnClipboardDataChanged() {
diff --git a/ash/clipboard/views/clipboard_history_bitmap_item_view.cc b/ash/clipboard/views/clipboard_history_bitmap_item_view.cc
index b06c0a8..658b8d17 100644
--- a/ash/clipboard/views/clipboard_history_bitmap_item_view.cc
+++ b/ash/clipboard/views/clipboard_history_bitmap_item_view.cc
@@ -197,7 +197,6 @@
 
     auto delete_button =
         std::make_unique<ClipboardHistoryDeleteButton>(container_);
-    delete_button->SetVisible(false);
     delete_button->SetProperty(
         views::kMarginsKey,
         ClipboardHistoryViews::kBitmapItemDeleteButtonMargins);
diff --git a/ash/clipboard/views/clipboard_history_delete_button.cc b/ash/clipboard/views/clipboard_history_delete_button.cc
index 16b4023..b307dd8 100644
--- a/ash/clipboard/views/clipboard_history_delete_button.cc
+++ b/ash/clipboard/views/clipboard_history_delete_button.cc
@@ -9,6 +9,8 @@
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/style/ash_color_provider.h"
 #include "ash/style/scoped_light_mode_as_default.h"
+#include "ui/views/animation/ink_drop.h"
+#include "ui/views/controls/highlight_path_generator.h"
 
 namespace ash {
 ClipboardHistoryDeleteButton::ClipboardHistoryDeleteButton(
@@ -24,6 +26,22 @@
   SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   SetPreferredSize(gfx::Size(ClipboardHistoryViews::kDeleteButtonSizeDip,
                              ClipboardHistoryViews::kDeleteButtonSizeDip));
+  SetVisible(false);
+  SetInkDropMode(views::InkDropHostView::InkDropMode::ON);
+  ink_drop_container_ =
+      AddChildView(std::make_unique<views::InkDropContainerView>());
+
+  // Typically we should not create a layer for a view used in the clipboard
+  // history menu. Because if a layer extends outside of the menu's bounds, it
+  // does not get cut (in addition, due to the lack of ownership, it is hard to
+  // change this behavior). However, it is safe to paint to layer here since the
+  // default visibility is false,
+  SetPaintToLayer();
+  layer()->SetFillsBoundsOpaquely(false);
+
+  // The ink drop ripple should be circular.
+  views::InstallFixedSizeCircleHighlightPathGenerator(
+      this, ClipboardHistoryViews::kDeleteButtonSizeDip / 2);
 }
 
 ClipboardHistoryDeleteButton::~ClipboardHistoryDeleteButton() = default;
@@ -32,6 +50,16 @@
   return "DeleteButton";
 }
 
+void ClipboardHistoryDeleteButton::AddLayerBeneathView(ui::Layer* layer) {
+  ink_drop_container_->AddLayerBeneathView(layer);
+}
+
+std::unique_ptr<views::InkDrop> ClipboardHistoryDeleteButton::CreateInkDrop() {
+  std::unique_ptr<views::InkDrop> ink_drop = views::Button::CreateInkDrop();
+  ink_drop->SetShowHighlightOnHover(false);
+  return ink_drop;
+}
+
 void ClipboardHistoryDeleteButton::OnThemeChanged() {
   // Use the light mode as default because the light mode is the default mode of
   // the native theme which decides the context menu's background color.
@@ -41,5 +69,15 @@
   views::ImageButton::OnThemeChanged();
   AshColorProvider::Get()->DecorateCloseButton(
       this, ClipboardHistoryViews::kDeleteButtonSizeDip, kCloseButtonIcon);
+
+  const AshColorProvider::RippleAttributes ripple_attributes =
+      AshColorProvider::Get()->GetRippleAttributes();
+  SetInkDropBaseColor(ripple_attributes.base_color);
+  SetInkDropVisibleOpacity(ripple_attributes.inkdrop_opacity);
 }
+
+void ClipboardHistoryDeleteButton::RemoveLayerBeneathView(ui::Layer* layer) {
+  ink_drop_container_->RemoveLayerBeneathView(layer);
+}
+
 }  // namespace ash
diff --git a/ash/clipboard/views/clipboard_history_delete_button.h b/ash/clipboard/views/clipboard_history_delete_button.h
index 6336426b..060b2379 100644
--- a/ash/clipboard/views/clipboard_history_delete_button.h
+++ b/ash/clipboard/views/clipboard_history_delete_button.h
@@ -7,6 +7,10 @@
 
 #include "ui/views/controls/button/image_button.h"
 
+namespace views {
+class InkDropContainerView;
+}  // namespace views
+
 namespace ash {
 class ClipboardHistoryItemView;
 
@@ -23,7 +27,14 @@
  private:
   // views::ImageButton:
   const char* GetClassName() const override;
+  void AddLayerBeneathView(ui::Layer* layer) override;
+  std::unique_ptr<views::InkDrop> CreateInkDrop() override;
   void OnThemeChanged() override;
+  void RemoveLayerBeneathView(ui::Layer* layer) override;
+
+  // Used to accommodate the ink drop layer. It ensures that the ink drop is
+  // above the view background.
+  views::InkDropContainerView* ink_drop_container_ = nullptr;
 };
 }  // namespace ash
 
diff --git a/ash/clipboard/views/clipboard_history_text_item_view.cc b/ash/clipboard/views/clipboard_history_text_item_view.cc
index 8e3099a..3c13c6e 100644
--- a/ash/clipboard/views/clipboard_history_text_item_view.cc
+++ b/ash/clipboard/views/clipboard_history_text_item_view.cc
@@ -46,7 +46,6 @@
   ClipboardHistoryDeleteButton* CreateDeleteButton() override {
     auto delete_button =
         std::make_unique<ClipboardHistoryDeleteButton>(container());
-    delete_button->SetVisible(false);
     delete_button->SetProperty(
         views::kMarginsKey,
         ClipboardHistoryViews::kDefaultItemDeleteButtonMargins);
diff --git a/ash/public/cpp/app_list/app_list_color_provider.h b/ash/public/cpp/app_list/app_list_color_provider.h
index b9f70fe..ec4c3e9 100644
--- a/ash/public/cpp/app_list/app_list_color_provider.h
+++ b/ash/public/cpp/app_list/app_list_color_provider.h
@@ -49,6 +49,9 @@
   virtual SkColor GetSeparatorColor() const = 0;
   virtual SkColor GetSearchResultViewHighlightColor() const = 0;
   virtual SkColor GetSearchResultViewInkDropColor() const = 0;
+  virtual SkColor GetFocusRingColor() const = 0;
+  virtual SkColor GetFolderItemFocusRingColor() const = 0;
+
   virtual float GetFolderBackgrounBlurSigma() const = 0;
 
  protected:
diff --git a/ash/public/cpp/app_list/app_list_config.cc b/ash/public/cpp/app_list/app_list_config.cc
index 333dda13..c3860d38 100644
--- a/ash/public/cpp/app_list/app_list_config.cc
+++ b/ash/public/cpp/app_list/app_list_config.cc
@@ -314,7 +314,6 @@
       page_flip_zone_size_(20),
       grid_tile_spacing_in_folder_(8),
       blur_radius_(30),
-      grid_selected_color_(gfx::kGoogleBlue300),
       page_transition_duration_(base::TimeDelta::FromMilliseconds(250)),
       overscroll_page_transition_duration_(
           base::TimeDelta::FromMilliseconds(50)),
@@ -461,7 +460,6 @@
                    scale_x,
                    inner_tile_scale_y)),
       blur_radius_(base_config.blur_radius_),
-      grid_selected_color_(base_config.grid_selected_color_),
       page_transition_duration_(base_config.page_transition_duration_),
       overscroll_page_transition_duration_(
           base_config.overscroll_page_transition_duration_),
diff --git a/ash/public/cpp/app_list/app_list_config.h b/ash/public/cpp/app_list/app_list_config.h
index b4e1b54..666ff46 100644
--- a/ash/public/cpp/app_list/app_list_config.h
+++ b/ash/public/cpp/app_list/app_list_config.h
@@ -148,7 +148,6 @@
     return grid_tile_spacing_in_folder_;
   }
   int blur_radius() const { return blur_radius_; }
-  SkColor grid_selected_color() const { return grid_selected_color_; }
   base::TimeDelta page_transition_duration() const {
     return page_transition_duration_;
   }
@@ -433,10 +432,6 @@
   // The blur radius used in the app list.
   const int blur_radius_;
 
-  // The keyboard select color for grid views, which are on top of a black
-  // shield view for new design (12% white).
-  const SkColor grid_selected_color_;
-
   // Duration for page transition.
   const base::TimeDelta page_transition_duration_;
 
diff --git a/base/observer_list.h b/base/observer_list.h
index 834ee64e..db220a2a 100644
--- a/base/observer_list.h
+++ b/base/observer_list.h
@@ -273,6 +273,7 @@
       NOTREACHED() << "Observers can only be added once!";
       return;
     }
+    observers_count_++;
     observers_.emplace_back(ObserverStorageType(obs));
   }
 
@@ -284,7 +285,8 @@
         observers_, [obs](const auto& o) { return o.IsEqual(obs); });
     if (it == observers_.end())
       return;
-
+    if (!it->IsMarkedForRemoval())
+      observers_count_--;
     if (live_iterators_.empty()) {
       observers_.erase(it);
     } else {
@@ -314,8 +316,13 @@
       for (auto& observer : observers_)
         observer.MarkForRemoval();
     }
+    observers_count_ = 0;
   }
 
+  bool has_observers() const { return observers_count_ > 0; }
+
+  // Deprecated: use |has_observers()|.
+  // TODO(1155308): migrate all callers and make this test only.
   bool might_have_observers() const { return !observers_.empty(); }
 
  private:
@@ -334,6 +341,8 @@
 
   base::LinkedList<internal::WeakLinkNode<ObserverList>> live_iterators_;
 
+  size_t observers_count_{0};
+
   const ObserverListPolicy policy_;
 
   SEQUENCE_CHECKER(iteration_sequence_checker_);
diff --git a/base/observer_list_unittest.cc b/base/observer_list_unittest.cc
index 8fe0950..1a6a28e 100644
--- a/base/observer_list_unittest.cc
+++ b/base/observer_list_unittest.cc
@@ -364,6 +364,7 @@
   EXPECT_TRUE(col.HasObserver(&a));
   EXPECT_FALSE(col.HasObserver(&c));
 
+  EXPECT_TRUE(col.has_observers());
   EXPECT_TRUE(col.might_have_observers());
 
   using It = typename ObserverListConstFoo::const_iterator;
@@ -379,44 +380,55 @@
     EXPECT_EQ(itb, it);
     EXPECT_EQ(++it, col.end());
 
+    EXPECT_TRUE(col.has_observers());
     EXPECT_TRUE(col.might_have_observers());
     EXPECT_EQ(&*ita, &a);
     EXPECT_EQ(&*itb, &b);
 
     ol.RemoveObserver(&a);
+    EXPECT_TRUE(col.has_observers());
     EXPECT_TRUE(col.might_have_observers());
     EXPECT_FALSE(col.HasObserver(&a));
     EXPECT_EQ(&*itb, &b);
 
     ol.RemoveObserver(&b);
+    EXPECT_FALSE(col.has_observers());
     EXPECT_TRUE(col.might_have_observers());
     EXPECT_FALSE(col.HasObserver(&a));
     EXPECT_FALSE(col.HasObserver(&b));
 
     it = It();
     ita = It();
+    EXPECT_FALSE(col.has_observers());
     EXPECT_TRUE(col.might_have_observers());
     ita = itb;
     itb = It();
+    EXPECT_FALSE(col.has_observers());
     EXPECT_TRUE(col.might_have_observers());
     ita = It();
+    EXPECT_FALSE(col.has_observers());
     EXPECT_FALSE(col.might_have_observers());
   }
 
   ol.AddObserver(&a);
   ol.AddObserver(&b);
+  EXPECT_TRUE(col.has_observers());
   EXPECT_TRUE(col.might_have_observers());
   ol.Clear();
+  EXPECT_FALSE(col.has_observers());
   EXPECT_FALSE(col.might_have_observers());
 
   ol.AddObserver(&a);
   ol.AddObserver(&b);
+  EXPECT_TRUE(col.has_observers());
   EXPECT_TRUE(col.might_have_observers());
   {
     const It it = col.begin();
     ol.Clear();
+    EXPECT_FALSE(col.has_observers());
     EXPECT_TRUE(col.might_have_observers());
   }
+  EXPECT_FALSE(col.has_observers());
   EXPECT_FALSE(col.might_have_observers());
 }
 
@@ -1001,6 +1013,7 @@
     // On the non-death fork, no UAF occurs since the deleted observer is never
     // notified, but also the observer list still has |l2| in it. Check that.
     list->RemoveObserver(&l1);
+    EXPECT_TRUE(list->has_observers());
     EXPECT_TRUE(list->might_have_observers());
 
     // Now (in the non-death fork()) there's a problem. To delete |it|, we need
diff --git a/build/android/gyp/compile_resources.py b/build/android/gyp/compile_resources.py
index 40db7055d..7c71f2bb 100755
--- a/build/android/gyp/compile_resources.py
+++ b/build/android/gyp/compile_resources.py
@@ -242,6 +242,11 @@
       '--uses-split',
       help='Value to set uses-split to in the AndroidManifest.xml.')
 
+  input_opts.add_argument(
+      '--extra-verification-manifest',
+      help='Path to AndroidManifest.xml which should be merged into base '
+      'manifest when performing verification.')
+
   diff_utils.AddCommandLineFlags(parser)
   options = parser.parse_args(args)
 
@@ -412,7 +417,7 @@
           os.path.relpath(dst_file, res_root))
 
 
-def _FixManifest(options, temp_dir):
+def _FixManifest(options, temp_dir, extra_manifest=None):
   """Fix the APK's AndroidManifest.xml.
 
   This adds any missing namespaces for 'android' and 'tools', and
@@ -422,6 +427,8 @@
   Args:
     options: The command-line arguments tuple.
     temp_dir: A temporary directory where the fixed manifest will be written to.
+    extra_manifest: Path to an AndroidManifest.xml file which will get merged
+        into the application node of the base manifest.
   Returns:
     Tuple of:
      * Manifest path within |temp_dir|.
@@ -452,6 +459,11 @@
   doc, manifest_node, app_node = manifest_utils.ParseManifest(
       options.android_manifest)
 
+  if extra_manifest:
+    _, _, extra_app_nodes = manifest_utils.ParseManifest(extra_manifest)
+    for node in extra_app_nodes:
+      app_node.append(node)
+
   manifest_utils.AssertUsesSdk(manifest_node, options.min_sdk_version,
                                options.target_sdk_version)
   # We explicitly check that maxSdkVersion is set in the manifest since we don't
@@ -1039,9 +1051,10 @@
       shutil.move(temp, final)
 
 
-def _CreateNormalizedManifest(options):
+def _CreateNormalizedManifestForVerification(options):
   with build_utils.TempDir() as tempdir:
-    fixed_manifest, _ = _FixManifest(options, tempdir)
+    fixed_manifest, _ = _FixManifest(
+        options, tempdir, extra_manifest=options.extra_verification_manifest)
     with open(fixed_manifest) as f:
       return manifest_utils.NormalizeManifest(f.read())
 
@@ -1140,7 +1153,7 @@
   options = _ParseArgs(args)
 
   if options.expected_file:
-    actual_data = _CreateNormalizedManifest(options)
+    actual_data = _CreateNormalizedManifestForVerification(options)
     diff_utils.CheckExpectations(actual_data, options)
     if options.only_verify_expectations:
       return
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index da00159..9238ba6 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -2751,6 +2751,16 @@
         if (fail_on_android_expectations) {
           args += [ "--fail-on-expectations" ]
         }
+        if (defined(invoker.extra_verification_manifest)) {
+          inputs += [ invoker.extra_verification_manifest ]
+          args += [
+            "--extra-verification-manifest",
+            rebase_path(invoker.extra_verification_manifest, root_build_dir),
+          ]
+          if (defined(invoker.extra_verification_manifest_dep)) {
+            deps += [ invoker.extra_verification_manifest_dep ]
+          }
+        }
       }
       _deps += [ ":$_expectations_target" ]
     }
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 973c0f93..0baa5a1 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2473,6 +2473,8 @@
                                "enforce_resource_overlays_in_tests",
                                "expected_android_manifest",
                                "expected_android_manifest_base",
+                               "extra_verification_manifest",
+                               "extra_verification_manifest_dep",
                                "manifest_package",
                                "max_sdk_version",
                                "no_xml_namespaces",
@@ -3608,6 +3610,8 @@
                                "enable_multidex",
                                "expected_android_manifest",
                                "expected_android_manifest_base",
+                               "extra_verification_manifest",
+                               "extra_verification_manifest_dep",
                                "generate_buildconfig_java",
                                "generate_final_jni",
                                "input_jars_paths",
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index b6ea818..b206e09 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20201203.2.1
+0.20201203.3.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index b6ea818..d1d50ac 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20201203.2.1
+0.20201203.4.1
diff --git a/cc/metrics/event_metrics.cc b/cc/metrics/event_metrics.cc
index b4cac606..a148018 100644
--- a/cc/metrics/event_metrics.cc
+++ b/cc/metrics/event_metrics.cc
@@ -48,6 +48,7 @@
     EVENT_TYPE(FirstGestureScrollUpdate,
                ui::ET_GESTURE_SCROLL_UPDATE,
                EventMetrics::ScrollUpdateType::kStarted),
+    EVENT_TYPE(MouseDragged, ui::ET_MOUSE_DRAGGED),
 #undef EVENT_TYPE
 };
 static_assert(base::size(kInterestingEvents) ==
diff --git a/cc/metrics/event_metrics.h b/cc/metrics/event_metrics.h
index 63504526..df59cc9e 100644
--- a/cc/metrics/event_metrics.h
+++ b/cc/metrics/event_metrics.h
@@ -49,7 +49,8 @@
     kGestureTapUnconfirmed,
     kGestureTwoFingerTap,
     kFirstGestureScrollUpdate,
-    kMaxValue = kFirstGestureScrollUpdate,
+    kMouseDragged,
+    kMaxValue = kMouseDragged,
   };
 
   // Type of scroll events. This list should be in the same order as values of
diff --git a/chrome/VERSION b/chrome/VERSION
index ed83715..6243587 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=89
 MINOR=0
-BUILD=4345
+BUILD=4346
 PATCH=0
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index f8072ae..eff0dd36 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -501,6 +501,16 @@
         # TODO(crbug.com/1150459): Remove this once internal repo is updated.
         not_needed(invoker, [ "module_descs" ])
 
+        # If the manifest is being verified, add the chrome module's manifest.
+        if (defined(invoker.expected_android_manifest)) {
+          _bundle_target_gen_dir =
+              get_label_info(invoker.bundle_target, "target_gen_dir")
+          _bundle_name = get_label_info(invoker.bundle_target, "name")
+          extra_verification_manifest = "${_bundle_target_gen_dir}/${_bundle_name}__chrome_bundle_module_manifest/AndroidManifest.xml"
+          extra_verification_manifest_dep =
+              "${invoker.bundle_target}__chrome_bundle_module__merge_manifests"
+        }
+
         # 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.
@@ -728,6 +738,8 @@
       "alternative_android_sdk_dep",
       "app_as_shared_lib",
       "deps",
+      "extra_verification_manifest",
+      "extra_verification_manifest_dep",
       "is_monochrome",
       "is_trichrome",
       "isolated_splits_enabled",
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn
index b161de2e..cf5d58ed 100644
--- a/chrome/android/features/autofill_assistant/BUILD.gn
+++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -228,6 +228,7 @@
     "java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataNativeDelegate.java",
     "java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantDateTime.java",
   ]
+  split_name = "autofill_assistant"
 }
 
 generate_jni("test_support_jni_headers") {
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index d4cbf53..acb86d9 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5437,6 +5437,9 @@
       <message name="IDS_NTP_CONFIRM_MSG_SHORTCUT_ADDED" desc="The title of the shortcut added confirmation message when adding a custom link. (On the New Tab Page)">
         Shortcut added
       </message>
+      <message name="IDS_NTP_CUSTOM_LINKS_ALREADY_EXISTS" desc="When adding/editing a custom link, this error is shown when the URL already exists in another custom link. (On the New Tab Page)">
+        Shortcut already exists
+      </message>
       <message name="IDS_NTP_CONFIRM_MSG_RESTORE_DEFAULTS" desc="The text label of the restore default shortcuts button when editing a custom link. (On the New Tab Page)">
         Restore default shortcuts
       </message>
@@ -10712,6 +10715,9 @@
       <message name="IDS_WEBAUTHN_UV_ERROR_LOCKED" desc="Error message. Displayed when the user's authenticator has been locked due to too many failed attempts to read their fingerprint, and they are required to enter a PIN to unlock it.">
         Your security key is locked because your fingerprint couldn't be recognized. To unlock it, enter your PIN.
       </message>
+      <message name="IDS_WEBAUTHN_FORCE_PIN_CHANGE" desc="An error message shown when a user attempts to use a security key (an authentication hardware device) that has a default PIN (short, often numeric codes that are often used with, for example, ATM cards) set. Before using the key, the user needs to change the PIN to a new code.">
+        To use your new security key, set a new PIN
+      </message>
 
       <!-- WebAuthn account selection for resident keys -->
       <message name="IDS_WEBAUTHN_SELECT_ACCOUNT" desc="The title on a dialog where the user is expected to select an account from a list. For example, the list may include several identities, e.g. joe@gmail.com, mary@gmail.com, and the user has to select one to login as.">
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_CUSTOM_LINKS_ALREADY_EXISTS.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_CUSTOM_LINKS_ALREADY_EXISTS.png.sha1
new file mode 100644
index 0000000..0b6e26c
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_NTP_CUSTOM_LINKS_ALREADY_EXISTS.png.sha1
@@ -0,0 +1 @@
+4fefa22bd37edcf1d7019e4e7c8743da87a55571
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_WEBAUTHN_FORCE_PIN_CHANGE.png.sha1 b/chrome/app/generated_resources_grd/IDS_WEBAUTHN_FORCE_PIN_CHANGE.png.sha1
new file mode 100644
index 0000000..ae22bdd
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_WEBAUTHN_FORCE_PIN_CHANGE.png.sha1
@@ -0,0 +1 @@
+697aabe9210b76443db969c47be4a9b9020b73ac
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 1193d40d..606bde2 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1839,6 +1839,10 @@
     "translate/chrome_translate_client.h",
     "translate/translate_accept_languages_factory.cc",
     "translate/translate_accept_languages_factory.h",
+    "translate/translate_model_service_factory.cc",
+    "translate/translate_model_service_factory.h",
+    "translate/translate_model_service_impl.cc",
+    "translate/translate_model_service_impl.h",
     "translate/translate_ranker_factory.cc",
     "translate/translate_ranker_factory.h",
     "translate/translate_ranker_metrics_provider.cc",
@@ -1884,6 +1888,8 @@
     "wake_lock/wake_lock_permission_context.h",
     "web_data_service_factory.cc",
     "web_data_service_factory.h",
+    "webapps/chrome_webapps_client.cc",
+    "webapps/chrome_webapps_client.h",
     "window_placement/window_placement_permission_context.cc",
     "window_placement/window_placement_permission_context.h",
   ]
@@ -2244,6 +2250,7 @@
     "//components/visitedlink/common",
     "//components/web_cache/browser",
     "//components/web_resource",
+    "//components/webapps",
     "//components/webdata/common",
     "//components/webdata_services",
     "//components/webrtc",
@@ -4380,6 +4387,8 @@
       "nearby_sharing/share_target_info.h",
       "nearby_sharing/sharesheet/nearby_share_action.cc",
       "nearby_sharing/sharesheet/nearby_share_action.h",
+      "nearby_sharing/sharesheet/nearby_share_web_view.cc",
+      "nearby_sharing/sharesheet/nearby_share_web_view.h",
       "nearby_sharing/transfer_metadata.cc",
       "nearby_sharing/transfer_metadata.h",
       "nearby_sharing/transfer_metadata_builder.cc",
diff --git a/chrome/browser/apps/app_service/borealis_apps.cc b/chrome/browser/apps/app_service/borealis_apps.cc
index 6388bcfc..5ab9e88 100644
--- a/chrome/browser/apps/app_service/borealis_apps.cc
+++ b/chrome/browser/apps/app_service/borealis_apps.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/apps/app_service/app_icon_factory.h"
 #include "chrome/browser/apps/app_service/menu_util.h"
 #include "chrome/browser/chromeos/borealis/borealis_app_launcher.h"
+#include "chrome/browser/chromeos/borealis/borealis_context_manager.h"
 #include "chrome/browser/chromeos/borealis/borealis_features.h"
 #include "chrome/browser/chromeos/borealis/borealis_service.h"
 #include "chrome/browser/chromeos/borealis/borealis_util.h"
@@ -66,7 +67,7 @@
     : profile_(profile) {
   Registry()->AddObserver(this);
 
-  anonymous_observation_.Observe(
+  anonymous_app_observation_.Observe(
       &borealis::BorealisService::GetForProfile(profile_)->WindowManager());
 
   PublisherBase::Initialize(app_service, apps::mojom::AppType::kBorealis);
@@ -178,6 +179,16 @@
                                 GetMenuModelCallback callback) {
   apps::mojom::MenuItemsPtr menu_items = apps::mojom::MenuItems::New();
 
+  // TODO(b/170677773): Show shutdown in another app.
+  if (app_id == borealis::kBorealisAppId &&
+      borealis::BorealisService::GetForProfile(profile_)
+          ->ContextManager()
+          .IsRunning()) {
+    // TODO(b/174705762): Use borealis-specific strings.
+    AddCommandItem(ash::SHUTDOWN_GUEST_OS, IDS_PLUGIN_VM_SHUT_DOWN_MENU_ITEM,
+                   &menu_items);
+  }
+
   if (ShouldAddCloseItem(app_id, menu_type, profile_)) {
     AddCommandItem(ash::MENU_CLOSE, IDS_SHELF_CONTEXT_MENU_CLOSE, &menu_items);
   }
@@ -219,8 +230,8 @@
   }
 }
 
-void BorealisApps::NewAnonymousAppDetected(const std::string& shelf_app_id,
-                                           const std::string& shelf_app_name) {
+void BorealisApps::OnAnonymousAppAdded(const std::string& shelf_app_id,
+                                       const std::string& shelf_app_name) {
   apps::mojom::AppPtr app = apps::PublisherBase::MakeApp(
       apps::mojom::AppType::kBorealis, shelf_app_id,
       apps::mojom::Readiness::kReady, shelf_app_name,
@@ -238,9 +249,21 @@
   Publish(std::move(app), subscribers_);
 }
 
-void BorealisApps::WindowManagerWillBeDeleted(
+void BorealisApps::OnAnonymousAppRemoved(const std::string& shelf_app_id) {
+  // First uninstall the anonymous app, then remove it.
+  for (auto readiness : {apps::mojom::Readiness::kUninstalledByUser,
+                         apps::mojom::Readiness::kRemoved}) {
+    apps::mojom::AppPtr app = apps::mojom::App::New();
+    app->app_type = apps::mojom::AppType::kBorealis;
+    app->app_id = shelf_app_id;
+    app->readiness = readiness;
+    Publish(std::move(app), subscribers_);
+  }
+}
+
+void BorealisApps::OnWindowManagerDeleted(
     borealis::BorealisWindowManager* window_manager) {
-  anonymous_observation_.Reset();
+  anonymous_app_observation_.Reset();
 }
 
 }  // namespace apps
diff --git a/chrome/browser/apps/app_service/borealis_apps.h b/chrome/browser/apps/app_service/borealis_apps.h
index 6b2f67cb..e39bf90 100644
--- a/chrome/browser/apps/app_service/borealis_apps.h
+++ b/chrome/browser/apps/app_service/borealis_apps.h
@@ -75,9 +75,10 @@
       const std::vector<std::string>& inserted_apps) override;
 
   // borealis::BorealisWindowManager::AnonymousAppObserver overrides.
-  void NewAnonymousAppDetected(const std::string& shelf_app_id,
-                               const std::string& shelf_app_name) override;
-  void WindowManagerWillBeDeleted(
+  void OnAnonymousAppAdded(const std::string& shelf_app_id,
+                           const std::string& shelf_app_name) override;
+  void OnAnonymousAppRemoved(const std::string& shelf_app_id) override;
+  void OnWindowManagerDeleted(
       borealis::BorealisWindowManager* window_manager) override;
 
   mojo::RemoteSet<apps::mojom::Subscriber> subscribers_;
@@ -88,7 +89,7 @@
 
   base::ScopedObservation<borealis::BorealisWindowManager,
                           borealis::BorealisWindowManager::AnonymousAppObserver>
-      anonymous_observation_{this};
+      anonymous_app_observation_{this};
 };
 
 }  // namespace apps
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index bb3bee8..08c74c34 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -75,6 +75,7 @@
 #include "chrome/browser/status_icons/status_tray.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/update_client/chrome_update_query_params_delegate.h"
+#include "chrome/browser/webapps/chrome_webapps_client.h"
 #include "chrome/common/buildflags.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_constants.h"
@@ -307,6 +308,9 @@
   // Make sure permissions client has been set.
   ChromePermissionsClient::GetInstance();
 
+  // Make sure webapps client has been set.
+  webapps::ChromeWebappsClient::GetInstance();
+
 #if !defined(OS_ANDROID)
   KeepAliveRegistry::GetInstance()->SetIsShuttingDown(false);
   KeepAliveRegistry::GetInstance()->AddObserver(this);
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 39839b1..f238c3b 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -505,7 +505,6 @@
       <if expr="chromeos">
         <include name="IDR_SMART_DIM_20181115_EXAMPLE_PREPROCESSOR_CONFIG_PB" file="chromeos\power\ml\smart_dim\20181115_example_preprocessor_config.pb" type="BINDATA" />
         <include name="IDR_SMART_DIM_20190521_EXAMPLE_PREPROCESSOR_CONFIG_PB" file="chromeos\power\ml\smart_dim\20190521_example_preprocessor_config.pb" type="BINDATA" />
-        <include name="IDR_TOP_CAT_20190722_EXAMPLE_PREPROCESSOR_CONFIG_PB" file="ui\app_list\search\search_result_ranker\20190722_example_preprocessor_config.pb" type="BINDATA" />
         <include name="IDR_SEARCH_RANKER_20190923_EXAMPLE_PREPROCESSOR_CONFIG_PB" file="ui\app_list\search\search_result_ranker\search_ranker_assets\20190923_example_preprocessor_config.pb" type="BINDATA" />
       </if>
       <if expr="chromeos">
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 1a37dc7..591e593 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -877,8 +877,6 @@
     "borealis/borealis_features.h",
     "borealis/borealis_installer.cc",
     "borealis/borealis_installer.h",
-    "borealis/borealis_installer_factory.cc",
-    "borealis/borealis_installer_factory.h",
     "borealis/borealis_installer_impl.cc",
     "borealis/borealis_installer_impl.h",
     "borealis/borealis_launch_watcher.cc",
@@ -893,6 +891,8 @@
     "borealis/borealis_service_factory.h",
     "borealis/borealis_service_impl.cc",
     "borealis/borealis_service_impl.h",
+    "borealis/borealis_shutdown_monitor.cc",
+    "borealis/borealis_shutdown_monitor.h",
     "borealis/borealis_task.cc",
     "borealis/borealis_task.h",
     "borealis/borealis_util.cc",
@@ -2027,8 +2027,6 @@
     "net/network_diagnostics/tls_prober.h",
     "net/network_diagnostics/udp_prober.cc",
     "net/network_diagnostics/udp_prober.h",
-    "net/network_diagnostics/video_conferencing_routine.cc",
-    "net/network_diagnostics/video_conferencing_routine.h",
     "net/network_health/network_health.cc",
     "net/network_health/network_health.h",
     "net/network_health/network_health_localized_strings.cc",
@@ -3157,6 +3155,8 @@
     "attestation/mock_enrollment_certificate_uploader.h",
     "attestation/mock_machine_certificate_uploader.cc",
     "attestation/mock_machine_certificate_uploader.h",
+    "borealis/borealis_context_manager_mock.cc",
+    "borealis/borealis_context_manager_mock.h",
     "borealis/borealis_service_fake.cc",
     "borealis/borealis_service_fake.h",
     "cert_provisioning/mock_cert_provisioning_scheduler.cc",
@@ -3389,6 +3389,7 @@
     "borealis/borealis_features_unittest.cc",
     "borealis/borealis_installer_unittest.cc",
     "borealis/borealis_launch_watcher_unittest.cc",
+    "borealis/borealis_shutdown_monitor_unittest.cc",
     "borealis/borealis_task_unittest.cc",
     "borealis/borealis_window_manager_unittest.cc",
     "borealis/infra/described_unittest.cc",
@@ -3660,7 +3661,6 @@
     "net/network_diagnostics/signal_strength_routine_unittest.cc",
     "net/network_diagnostics/tls_prober_unittest.cc",
     "net/network_diagnostics/udp_prober_unittest.cc",
-    "net/network_diagnostics/video_conferencing_routine_unittest.cc",
     "net/network_health/network_health_unittest.cc",
     "net/network_portal_detector_impl_unittest.cc",
     "net/network_pref_state_observer_unittest.cc",
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager.h b/chrome/browser/chromeos/borealis/borealis_context_manager.h
index c9f86add..fbaadb225 100644
--- a/chrome/browser/chromeos/borealis/borealis_context_manager.h
+++ b/chrome/browser/chromeos/borealis/borealis_context_manager.h
@@ -60,6 +60,9 @@
   // Starts the Borealis VM and/or runs the callback when it is running.
   virtual void StartBorealis(ResultCallback callback) = 0;
 
+  // Returns true if the VM is currently running.
+  virtual bool IsRunning() = 0;
+
   // Stop the current running state, re-initializing the context manager
   // to the state it was in prior to being started. All pending callbacks are
   // invoked with kCancelled result.
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager_impl.cc b/chrome/browser/chromeos/borealis/borealis_context_manager_impl.cc
index 80137f7..840a7b8 100644
--- a/chrome/browser/chromeos/borealis/borealis_context_manager_impl.cc
+++ b/chrome/browser/chromeos/borealis/borealis_context_manager_impl.cc
@@ -30,7 +30,7 @@
 BorealisContextManagerImpl::~BorealisContextManagerImpl() = default;
 
 void BorealisContextManagerImpl::StartBorealis(ResultCallback callback) {
-  if (context_ && task_queue_.empty()) {
+  if (IsRunning()) {
     std::move(callback).Run(GetResult());
     return;
   }
@@ -45,7 +45,14 @@
   }
 }
 
+bool BorealisContextManagerImpl::IsRunning() {
+  return context_ && task_queue_.empty();
+}
+
 void BorealisContextManagerImpl::ShutDownBorealis() {
+  // The VM is already off.
+  if (!context_)
+    return;
   // TODO(b/172178036): This could have been a task-sequence but that
   // abstraction is proving insufficient.
   vm_tools::concierge::StopVmRequest request;
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager_impl.h b/chrome/browser/chromeos/borealis/borealis_context_manager_impl.h
index 2d2028be..b5f087f 100644
--- a/chrome/browser/chromeos/borealis/borealis_context_manager_impl.h
+++ b/chrome/browser/chromeos/borealis/borealis_context_manager_impl.h
@@ -29,6 +29,7 @@
 
   // BorealisContextManager:
   void StartBorealis(ResultCallback callback) override;
+  bool IsRunning() override;
   void ShutDownBorealis() override;
 
   // Public due to testing.
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager_mock.cc b/chrome/browser/chromeos/borealis/borealis_context_manager_mock.cc
new file mode 100644
index 0000000..ceef4c9
--- /dev/null
+++ b/chrome/browser/chromeos/borealis/borealis_context_manager_mock.cc
@@ -0,0 +1,13 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/borealis/borealis_context_manager_mock.h"
+
+namespace borealis {
+
+BorealisContextManagerMock::BorealisContextManagerMock() = default;
+
+BorealisContextManagerMock::~BorealisContextManagerMock() = default;
+
+}  // namespace borealis
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager_mock.h b/chrome/browser/chromeos/borealis/borealis_context_manager_mock.h
new file mode 100644
index 0000000..caae7e4e
--- /dev/null
+++ b/chrome/browser/chromeos/borealis/borealis_context_manager_mock.h
@@ -0,0 +1,32 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_BOREALIS_BOREALIS_CONTEXT_MANAGER_MOCK_H_
+#define CHROME_BROWSER_CHROMEOS_BOREALIS_BOREALIS_CONTEXT_MANAGER_MOCK_H_
+
+#include "chrome/browser/chromeos/borealis/borealis_context_manager.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace borealis {
+
+class BorealisContextManagerMock : public BorealisContextManager {
+ public:
+  BorealisContextManagerMock();
+
+  ~BorealisContextManagerMock();
+
+  MOCK_METHOD(void,
+              StartBorealis,
+              (BorealisContextManager::ResultCallback),
+              ());
+
+  MOCK_METHOD(bool, IsRunning, (), ());
+
+  MOCK_METHOD(void, ShutDownBorealis, (), ());
+};
+
+}  // namespace borealis
+
+#endif  // CHROME_BROWSER_CHROMEOS_BOREALIS_BOREALIS_CONTEXT_MANAGER_MOCK_H_
diff --git a/chrome/browser/chromeos/borealis/borealis_installer.h b/chrome/browser/chromeos/borealis/borealis_installer.h
index 768689e..87b6143 100644
--- a/chrome/browser/chromeos/borealis/borealis_installer.h
+++ b/chrome/browser/chromeos/borealis/borealis_installer.h
@@ -33,6 +33,7 @@
   };
 
   BorealisInstaller();
+  ~BorealisInstaller() override;
 
   static std::string GetInstallingStateName(InstallingState state);
 
@@ -45,14 +46,6 @@
 
   virtual void AddObserver(Observer* observer) = 0;
   virtual void RemoveObserver(Observer* observer) = 0;
-
- protected:
-  ~BorealisInstaller() override;
-
-  base::ObserverList<Observer> observers_;
-
- private:
-  base::WeakPtrFactory<BorealisInstaller> weak_ptr_factory_{this};
 };
 
 }  // namespace borealis
diff --git a/chrome/browser/chromeos/borealis/borealis_installer_factory.cc b/chrome/browser/chromeos/borealis/borealis_installer_factory.cc
deleted file mode 100644
index 3525b9d..0000000
--- a/chrome/browser/chromeos/borealis/borealis_installer_factory.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/borealis/borealis_installer_factory.h"
-
-#include "chrome/browser/chromeos/borealis/borealis_installer_impl.h"
-#include "chrome/browser/download/download_service_factory.h"
-#include "chrome/browser/profiles/incognito_helpers.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-
-namespace borealis {
-
-// static
-BorealisInstaller* BorealisInstallerFactory::GetForProfile(Profile* profile) {
-  return static_cast<BorealisInstaller*>(
-      GetInstance()->GetServiceForBrowserContext(profile, true));
-}
-
-// static
-BorealisInstallerFactory* BorealisInstallerFactory::GetInstance() {
-  static base::NoDestructor<BorealisInstallerFactory> factory;
-  return factory.get();
-}
-
-BorealisInstallerFactory::BorealisInstallerFactory()
-    : BrowserContextKeyedServiceFactory(
-          "BorealisInstaller",
-          BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(DownloadServiceFactory::GetInstance());
-}
-
-BorealisInstallerFactory::~BorealisInstallerFactory() = default;
-
-KeyedService* BorealisInstallerFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  return new BorealisInstallerImpl(Profile::FromBrowserContext(context));
-}
-
-content::BrowserContext* BorealisInstallerFactory::GetBrowserContextToUse(
-    content::BrowserContext* context) const {
-  return chrome::GetBrowserContextRedirectedInIncognito(context);
-}
-
-}  // namespace borealis
diff --git a/chrome/browser/chromeos/borealis/borealis_installer_factory.h b/chrome/browser/chromeos/borealis/borealis_installer_factory.h
deleted file mode 100644
index 54d6ac4..0000000
--- a/chrome/browser/chromeos/borealis/borealis_installer_factory.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_BOREALIS_BOREALIS_INSTALLER_FACTORY_H_
-#define CHROME_BROWSER_CHROMEOS_BOREALIS_BOREALIS_INSTALLER_FACTORY_H_
-
-#include "base/macros.h"
-#include "base/no_destructor.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-
-namespace content {
-class BrowserContext;
-}  // namespace content
-
-class Profile;
-
-namespace borealis {
-
-class BorealisInstaller;
-
-class BorealisInstallerFactory : public BrowserContextKeyedServiceFactory {
- public:
-  static BorealisInstaller* GetForProfile(Profile* profile);
-  static BorealisInstallerFactory* GetInstance();
-
- private:
-  friend base::NoDestructor<BorealisInstallerFactory>;
-
-  BorealisInstallerFactory();
-  ~BorealisInstallerFactory() override;
-
-  // BrowserContextKeyedServiceFactory implementation.
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* context) const override;
-  content::BrowserContext* GetBrowserContextToUse(
-      content::BrowserContext* context) const override;
-
-  DISALLOW_COPY_AND_ASSIGN(BorealisInstallerFactory);
-};
-
-}  // namespace borealis
-
-#endif  // CHROME_BROWSER_CHROMEOS_BOREALIS_BOREALIS_INSTALLER_FACTORY_H_
diff --git a/chrome/browser/chromeos/borealis/borealis_installer_impl.h b/chrome/browser/chromeos/borealis/borealis_installer_impl.h
index 19b4365..300539e 100644
--- a/chrome/browser/chromeos/borealis/borealis_installer_impl.h
+++ b/chrome/browser/chromeos/borealis/borealis_installer_impl.h
@@ -19,6 +19,7 @@
 class BorealisInstallerImpl : public BorealisInstaller {
  public:
   explicit BorealisInstallerImpl(Profile* profile);
+  ~BorealisInstallerImpl() override;
 
   // Disallow copy and assign.
   BorealisInstallerImpl(const BorealisInstallerImpl&) = delete;
@@ -41,8 +42,6 @@
     kCancelling,
   };
 
-  ~BorealisInstallerImpl() override;
-
   void StartDlcInstallation();
   void InstallationEnded(BorealisInstallResult result);
 
@@ -58,6 +57,7 @@
   double progress_;
   base::TimeTicks installation_start_tick_;
   Profile* profile_;
+  base::ObserverList<Observer> observers_;
 
   base::WeakPtrFactory<BorealisInstallerImpl> weak_ptr_factory_;
 };
diff --git a/chrome/browser/chromeos/borealis/borealis_installer_unittest.cc b/chrome/browser/chromeos/borealis/borealis_installer_unittest.cc
index 5bf2f22..0704a013 100644
--- a/chrome/browser/chromeos/borealis/borealis_installer_unittest.cc
+++ b/chrome/browser/chromeos/borealis/borealis_installer_unittest.cc
@@ -9,7 +9,6 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chromeos/borealis/borealis_features.h"
-#include "chrome/browser/chromeos/borealis/borealis_installer_factory.h"
 #include "chrome/browser/chromeos/borealis/borealis_metrics.h"
 #include "chrome/browser/chromeos/borealis/borealis_prefs.h"
 #include "chrome/browser/chromeos/borealis/borealis_service.h"
@@ -53,7 +52,8 @@
     histogram_tester_ = std::make_unique<base::HistogramTester>();
     CreateProfile();
 
-    installer_ = BorealisInstallerFactory::GetForProfile(profile_.get());
+    installer_impl_ = std::make_unique<BorealisInstallerImpl>(profile_.get());
+    installer_ = installer_impl_.get();
     observer_ = std::make_unique<StrictMock<MockObserver>>();
     installer_->AddObserver(observer_.get());
 
@@ -110,6 +110,7 @@
 
   std::unique_ptr<TestingProfile> profile_;
   std::unique_ptr<base::HistogramTester> histogram_tester_;
+  std::unique_ptr<BorealisInstallerImpl> installer_impl_;
   BorealisInstaller* installer_;
   std::unique_ptr<MockObserver> observer_;
   content::BrowserTaskEnvironment task_environment_;
diff --git a/chrome/browser/chromeos/borealis/borealis_service.h b/chrome/browser/chromeos/borealis/borealis_service.h
index 70fc8efe..c540e4a 100644
--- a/chrome/browser/chromeos/borealis/borealis_service.h
+++ b/chrome/browser/chromeos/borealis/borealis_service.h
@@ -14,6 +14,8 @@
 class BorealisAppLauncher;
 class BorealisContextManager;
 class BorealisFeatures;
+class BorealisInstaller;
+class BorealisShutdownMonitor;
 class BorealisWindowManager;
 
 // A common location for all the interdependant components of borealis.
@@ -27,6 +29,8 @@
   virtual BorealisAppLauncher& AppLauncher() = 0;
   virtual BorealisContextManager& ContextManager() = 0;
   virtual BorealisFeatures& Features() = 0;
+  virtual BorealisInstaller& Installer() = 0;
+  virtual BorealisShutdownMonitor& ShutdownMonitor() = 0;
   virtual BorealisWindowManager& WindowManager() = 0;
 };
 
diff --git a/chrome/browser/chromeos/borealis/borealis_service_fake.cc b/chrome/browser/chromeos/borealis/borealis_service_fake.cc
index 53f9374..9139992b 100644
--- a/chrome/browser/chromeos/borealis/borealis_service_fake.cc
+++ b/chrome/browser/chromeos/borealis/borealis_service_fake.cc
@@ -36,6 +36,16 @@
   return *features_;
 }
 
+BorealisInstaller& BorealisServiceFake::Installer() {
+  DCHECK(installer_);
+  return *installer_;
+}
+
+BorealisShutdownMonitor& BorealisServiceFake::ShutdownMonitor() {
+  DCHECK(shutdown_monitor_);
+  return *shutdown_monitor_;
+}
+
 BorealisWindowManager& BorealisServiceFake::WindowManager() {
   DCHECK(window_manager_);
   return *window_manager_;
@@ -55,6 +65,15 @@
   features_ = features;
 }
 
+void BorealisServiceFake::SetInstallerForTesting(BorealisInstaller* installer) {
+  installer_ = installer;
+}
+
+void BorealisServiceFake::SetShutdownMonitorForTesting(
+    BorealisShutdownMonitor* shutdown_monitor) {
+  shutdown_monitor_ = shutdown_monitor;
+}
+
 void BorealisServiceFake::SetWindowManagerForTesting(
     BorealisWindowManager* window_manager) {
   window_manager_ = window_manager;
diff --git a/chrome/browser/chromeos/borealis/borealis_service_fake.h b/chrome/browser/chromeos/borealis/borealis_service_fake.h
index 8b91c21..57dd1fd 100644
--- a/chrome/browser/chromeos/borealis/borealis_service_fake.h
+++ b/chrome/browser/chromeos/borealis/borealis_service_fake.h
@@ -25,17 +25,23 @@
   BorealisAppLauncher& AppLauncher() override;
   BorealisContextManager& ContextManager() override;
   BorealisFeatures& Features() override;
+  BorealisInstaller& Installer() override;
+  BorealisShutdownMonitor& ShutdownMonitor() override;
   BorealisWindowManager& WindowManager() override;
 
   void SetAppLauncherForTesting(BorealisAppLauncher* app_launcher);
   void SetContextManagerForTesting(BorealisContextManager* context_manager);
   void SetFeaturesForTesting(BorealisFeatures* features);
+  void SetInstallerForTesting(BorealisInstaller* installer);
+  void SetShutdownMonitorForTesting(BorealisShutdownMonitor* shutdown_monitor);
   void SetWindowManagerForTesting(BorealisWindowManager* window_manager);
 
  private:
   BorealisAppLauncher* app_launcher_ = nullptr;
   BorealisContextManager* context_manager_ = nullptr;
   BorealisFeatures* features_ = nullptr;
+  BorealisInstaller* installer_ = nullptr;
+  BorealisShutdownMonitor* shutdown_monitor_ = nullptr;
   BorealisWindowManager* window_manager_ = nullptr;
 };
 
diff --git a/chrome/browser/chromeos/borealis/borealis_service_impl.cc b/chrome/browser/chromeos/borealis/borealis_service_impl.cc
index 9e5d0fd..3df41e40 100644
--- a/chrome/browser/chromeos/borealis/borealis_service_impl.cc
+++ b/chrome/browser/chromeos/borealis/borealis_service_impl.cc
@@ -4,11 +4,6 @@
 
 #include "chrome/browser/chromeos/borealis/borealis_service_impl.h"
 
-#include "chrome/browser/chromeos/borealis/borealis_app_launcher.h"
-#include "chrome/browser/chromeos/borealis/borealis_features.h"
-#include "chrome/browser/chromeos/borealis/borealis_window_manager.h"
-#include "chrome/browser/profiles/profile.h"
-
 namespace borealis {
 
 BorealisServiceImpl::BorealisServiceImpl(Profile* profile)
@@ -16,6 +11,8 @@
       app_launcher_(profile_),
       context_manager_(profile),
       features_(profile_),
+      installer_(profile_),
+      shutdown_monitor_(profile_),
       window_manager_(profile_) {}
 
 BorealisServiceImpl::~BorealisServiceImpl() = default;
@@ -32,6 +29,14 @@
   return features_;
 }
 
+BorealisInstaller& BorealisServiceImpl::Installer() {
+  return installer_;
+}
+
+BorealisShutdownMonitor& BorealisServiceImpl::ShutdownMonitor() {
+  return shutdown_monitor_;
+}
+
 BorealisWindowManager& BorealisServiceImpl::WindowManager() {
   return window_manager_;
 }
diff --git a/chrome/browser/chromeos/borealis/borealis_service_impl.h b/chrome/browser/chromeos/borealis/borealis_service_impl.h
index 5b8333f..5088c2b 100644
--- a/chrome/browser/chromeos/borealis/borealis_service_impl.h
+++ b/chrome/browser/chromeos/borealis/borealis_service_impl.h
@@ -10,6 +10,8 @@
 #include "chrome/browser/chromeos/borealis/borealis_app_launcher.h"
 #include "chrome/browser/chromeos/borealis/borealis_context_manager_impl.h"
 #include "chrome/browser/chromeos/borealis/borealis_features.h"
+#include "chrome/browser/chromeos/borealis/borealis_installer_impl.h"
+#include "chrome/browser/chromeos/borealis/borealis_shutdown_monitor.h"
 #include "chrome/browser/chromeos/borealis/borealis_window_manager.h"
 
 namespace borealis {
@@ -25,6 +27,8 @@
   BorealisAppLauncher& AppLauncher() override;
   BorealisContextManager& ContextManager() override;
   BorealisFeatures& Features() override;
+  BorealisInstaller& Installer() override;
+  BorealisShutdownMonitor& ShutdownMonitor() override;
   BorealisWindowManager& WindowManager() override;
 
   Profile* const profile_;
@@ -32,6 +36,8 @@
   BorealisAppLauncher app_launcher_;
   BorealisContextManagerImpl context_manager_;
   BorealisFeatures features_;
+  BorealisInstallerImpl installer_;
+  BorealisShutdownMonitor shutdown_monitor_;
   BorealisWindowManager window_manager_;
 };
 
diff --git a/chrome/browser/chromeos/borealis/borealis_shutdown_monitor.cc b/chrome/browser/chromeos/borealis/borealis_shutdown_monitor.cc
new file mode 100644
index 0000000..c2d4c8f0
--- /dev/null
+++ b/chrome/browser/chromeos/borealis/borealis_shutdown_monitor.cc
@@ -0,0 +1,48 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/borealis/borealis_shutdown_monitor.h"
+
+#include "base/threading/thread_task_runner_handle.h"
+#include "chrome/browser/chromeos/borealis/borealis_context_manager.h"
+#include "chrome/browser/chromeos/borealis/borealis_service.h"
+
+namespace {
+
+// The default time period used when initiating delayed shutdowns.
+constexpr base::TimeDelta kDefaultDelay = base::TimeDelta::FromSeconds(60);
+
+}  // namespace
+
+namespace borealis {
+
+BorealisShutdownMonitor::BorealisShutdownMonitor(Profile* profile)
+    : profile_(profile), delay_(kDefaultDelay) {}
+
+BorealisShutdownMonitor::~BorealisShutdownMonitor() = default;
+
+void BorealisShutdownMonitor::ShutdownWithDelay() {
+  // Reset() cancels the previous request if it was already there. Also,
+  // Unretained() is safe because the callback is cancelled when
+  // |in_progress_request_| is destroyed.
+  in_progress_request_.Reset(base::BindOnce(
+      &BorealisShutdownMonitor::ShutdownNow, base::Unretained(this)));
+  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, in_progress_request_.callback(), delay_);
+}
+
+void BorealisShutdownMonitor::ShutdownNow() {
+  BorealisService::GetForProfile(profile_)->ContextManager().ShutDownBorealis();
+}
+
+void BorealisShutdownMonitor::CancelDelayedShutdown() {
+  in_progress_request_.Cancel();
+}
+
+void BorealisShutdownMonitor::SetShutdownDelayForTesting(
+    base::TimeDelta delay) {
+  delay_ = delay;
+}
+
+}  // namespace borealis
diff --git a/chrome/browser/chromeos/borealis/borealis_shutdown_monitor.h b/chrome/browser/chromeos/borealis/borealis_shutdown_monitor.h
new file mode 100644
index 0000000..0b571df
--- /dev/null
+++ b/chrome/browser/chromeos/borealis/borealis_shutdown_monitor.h
@@ -0,0 +1,51 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_BOREALIS_BOREALIS_SHUTDOWN_MONITOR_H_
+#define CHROME_BROWSER_CHROMEOS_BOREALIS_BOREALIS_SHUTDOWN_MONITOR_H_
+
+#include "base/cancelable_callback.h"
+#include "base/time/time.h"
+
+class Profile;
+
+namespace borealis {
+
+// Manages the automatic shutdown of borealis either immediately, or via a timed
+// delay.
+class BorealisShutdownMonitor {
+ public:
+  explicit BorealisShutdownMonitor(Profile* profile);
+  ~BorealisShutdownMonitor();
+
+  // Initiate a delayed shutdown, which will trigger the real shutdown after a
+  // fixed time period, unless the shutdown is aborted in the interim. If a
+  // delayed shutdown is in progress, this will reset the delay.
+  void ShutdownWithDelay();
+
+  // Initiate a shutdown immediately, without the delay.
+  void ShutdownNow();
+
+  // Cancels any in-progress delayed shutdowns.
+  void CancelDelayedShutdown();
+
+  // Overrides the default delay of the shutdown.
+  void SetShutdownDelayForTesting(base::TimeDelta delay);
+
+ private:
+  // The profile which we will shutdown borealis for.
+  Profile* profile_;
+
+  // The length of time we wait before issuing a shutdown after a delayed
+  // shutdown is requested.
+  base::TimeDelta delay_;
+
+  // The currently in-flight request to shutdown borealis. This will be in the
+  // default state unless a request is actually underway.
+  base::CancelableOnceClosure in_progress_request_;
+};
+
+}  // namespace borealis
+
+#endif  // CHROME_BROWSER_CHROMEOS_BOREALIS_BOREALIS_SHUTDOWN_MONITOR_H_
diff --git a/chrome/browser/chromeos/borealis/borealis_shutdown_monitor_unittest.cc b/chrome/browser/chromeos/borealis/borealis_shutdown_monitor_unittest.cc
new file mode 100644
index 0000000..b7baa84
--- /dev/null
+++ b/chrome/browser/chromeos/borealis/borealis_shutdown_monitor_unittest.cc
@@ -0,0 +1,95 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/borealis/borealis_shutdown_monitor.h"
+
+#include <memory>
+
+#include "chrome/browser/chromeos/borealis/borealis_context_manager_mock.h"
+#include "chrome/browser/chromeos/borealis/borealis_features.h"
+#include "chrome/browser/chromeos/borealis/borealis_service_fake.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace borealis {
+namespace {
+
+class BorealisShutdownMonitorTest : public testing::Test {
+ protected:
+  BorealisShutdownMonitorTest()
+      : service_fake_(BorealisServiceFake::UseFakeForTesting(&profile_)),
+        features_(&profile_) {
+    service_fake_->SetFeaturesForTesting(&features_);
+    service_fake_->SetContextManagerForTesting(&context_manager_mock_);
+  }
+
+  Profile* profile() { return &profile_; }
+
+  content::BrowserTaskEnvironment task_environment_;
+  TestingProfile profile_;
+  BorealisServiceFake* service_fake_;
+  BorealisFeatures features_;
+  testing::StrictMock<BorealisContextManagerMock> context_manager_mock_;
+};
+
+TEST_F(BorealisShutdownMonitorTest, CanShutdownImmediately) {
+  BorealisShutdownMonitor monitor(profile());
+
+  EXPECT_CALL(context_manager_mock_, ShutDownBorealis());
+  monitor.ShutdownNow();
+}
+
+TEST_F(BorealisShutdownMonitorTest, CanShutdownWithDelay) {
+  BorealisShutdownMonitor monitor(profile());
+
+  monitor.SetShutdownDelayForTesting(base::TimeDelta::FromSeconds(0));
+  monitor.ShutdownWithDelay();
+
+  EXPECT_CALL(context_manager_mock_, ShutDownBorealis());
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(BorealisShutdownMonitorTest, CancelDelayedShutdownPreventsIt) {
+  BorealisShutdownMonitor monitor(profile());
+
+  EXPECT_CALL(context_manager_mock_, ShutDownBorealis()).Times(0);
+
+  monitor.SetShutdownDelayForTesting(base::TimeDelta::FromSeconds(0));
+  monitor.ShutdownWithDelay();
+
+  monitor.CancelDelayedShutdown();
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(BorealisShutdownMonitorTest, LaterShutdownOverridesEarlier) {
+  BorealisShutdownMonitor monitor(profile());
+
+  EXPECT_CALL(context_manager_mock_, ShutDownBorealis()).Times(0);
+
+  monitor.SetShutdownDelayForTesting(base::TimeDelta::FromSeconds(0));
+  monitor.ShutdownWithDelay();
+
+  // I'm assuming this thread won't be idle for 99 seconds.
+  monitor.SetShutdownDelayForTesting(base::TimeDelta::FromSeconds(99));
+  monitor.ShutdownWithDelay();
+
+  task_environment_.RunUntilIdle();
+}
+
+TEST_F(BorealisShutdownMonitorTest, DeletingMonitorCancelsShutdowns) {
+  auto monitor = std::make_unique<BorealisShutdownMonitor>(profile());
+
+  EXPECT_CALL(context_manager_mock_, ShutDownBorealis()).Times(0);
+
+  monitor->SetShutdownDelayForTesting(base::TimeDelta::FromSeconds(0));
+  monitor->ShutdownWithDelay();
+  monitor.reset();
+
+  task_environment_.RunUntilIdle();
+}
+
+}  // namespace
+}  // namespace borealis
diff --git a/chrome/browser/chromeos/borealis/borealis_window_manager.cc b/chrome/browser/chromeos/borealis/borealis_window_manager.cc
index 281ef9e..9ea962359 100644
--- a/chrome/browser/chromeos/borealis/borealis_window_manager.cc
+++ b/chrome/browser/chromeos/borealis/borealis_window_manager.cc
@@ -6,11 +6,14 @@
 
 #include <string>
 
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/chromeos/borealis/borealis_util.h"
 #include "chrome/browser/chromeos/crostini/crostini_shelf_utils.h"
 #include "components/exo/shell_surface_util.h"
+#include "ui/aura/window.h"
 
 namespace {
 
@@ -30,6 +33,10 @@
   return exo::GetShellStartupId(window);
 }
 
+std::string WindowToAnonymousAppId(aura::Window* window) {
+  return kBorealisAnonymousPrefix + *GetWindowId(window);
+}
+
 // Returns a name for the app with the given |anon_id|.
 std::string AnonymousIdentifierToName(const std::string& anon_id) {
   return anon_id.substr(anon_id.find(kBorealisWindowPrefix) +
@@ -52,8 +59,16 @@
     : profile_(profile) {}
 
 BorealisWindowManager::~BorealisWindowManager() {
+  for (auto& id_to_windows : anon_ids_to_windows_) {
+    for (aura::Window* window : id_to_windows.second) {
+      window->RemoveObserver(this);
+    }
+    for (auto& observer : observers_) {
+      observer.OnAnonymousAppRemoved(id_to_windows.first);
+    }
+  }
   for (auto& observer : observers_) {
-    observer.WindowManagerWillBeDeleted(this);
+    observer.OnWindowManagerDeleted(this);
   }
   DCHECK(!observers_.might_have_observers());
 }
@@ -84,18 +99,35 @@
     return crostini_equivalent_id;
 
   // The app has no registration, it is anonymous.
-  std::string anon_id = kBorealisAnonymousPrefix + *GetWindowId(window);
-  HandleAnonymousApp(anon_id);
+  std::string anon_id = WindowToAnonymousAppId(window);
+  if (!anon_ids_to_windows_.contains(anon_id)) {
+    std::string anon_name = AnonymousIdentifierToName(anon_id);
+    for (auto& observer : observers_)
+      observer.OnAnonymousAppAdded(anon_id, anon_name);
+  }
+  // Add the window to the tracking set, and if it wasn't already there, add an
+  // observer.
+  if (anon_ids_to_windows_[anon_id].emplace(window).second) {
+    window->AddObserver(this);
+  }
   return anon_id;
 }
 
-void BorealisWindowManager::HandleAnonymousApp(const std::string& anon_id) {
-  if (known_anon_ids_.contains(anon_id))
+void BorealisWindowManager::OnWindowDestroying(aura::Window* window) {
+  std::string anon_id = WindowToAnonymousAppId(window);
+  base::flat_map<std::string, base::flat_set<aura::Window*>>::iterator iter =
+      anon_ids_to_windows_.find(anon_id);
+
+  DCHECK(iter != anon_ids_to_windows_.end());
+  DCHECK(iter->second.contains(window));
+
+  iter->second.erase(window);
+  if (!iter->second.empty())
     return;
-  known_anon_ids_.emplace(anon_id);
-  std::string anon_name = AnonymousIdentifierToName(anon_id);
+
   for (auto& observer : observers_)
-    observer.NewAnonymousAppDetected(anon_id, anon_name);
+    observer.OnAnonymousAppRemoved(anon_id);
+  anon_ids_to_windows_.erase(iter);
 }
 
 }  // namespace borealis
diff --git a/chrome/browser/chromeos/borealis/borealis_window_manager.h b/chrome/browser/chromeos/borealis/borealis_window_manager.h
index 4a9a1539..b5a964bf 100644
--- a/chrome/browser/chromeos/borealis/borealis_window_manager.h
+++ b/chrome/browser/chromeos/borealis/borealis_window_manager.h
@@ -7,9 +7,11 @@
 
 #include <string>
 
+#include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
 #include "base/observer_list.h"
 #include "base/observer_list_types.h"
+#include "ui/aura/window_observer.h"
 
 class Profile;
 
@@ -19,7 +21,7 @@
 
 namespace borealis {
 
-class BorealisWindowManager {
+class BorealisWindowManager : public aura::WindowObserver {
  public:
   // Returns true if this window belongs to a borealis VM (based on its app_id
   // and startup_id).
@@ -32,17 +34,22 @@
     // belongs too. The |shelf_app_name| represents the system's best-guess for
     // what the app should be called. This us usually not a localized string but
     // something we read from the window's properties.
-    virtual void NewAnonymousAppDetected(const std::string& shelf_app_id,
-                                         const std::string& shelf_app_name) = 0;
+    virtual void OnAnonymousAppAdded(const std::string& shelf_app_id,
+                                     const std::string& shelf_app_name) = 0;
+
+    // Called when the last window for the anonymous app with |shelf_app_id| is
+    // closed, and the app is no longer relevant.
+    virtual void OnAnonymousAppRemoved(const std::string& shelf_app_id) = 0;
+
     // Called when the window manager is being deleted. Observers should
     // unregister themselves from it.
-    virtual void WindowManagerWillBeDeleted(
+    virtual void OnWindowManagerDeleted(
         BorealisWindowManager* window_manager) = 0;
   };
 
   explicit BorealisWindowManager(Profile* profile);
 
-  ~BorealisWindowManager();
+  ~BorealisWindowManager() override;
 
   void AddObserver(AnonymousAppObserver* observer);
   void RemoveObserver(AnonymousAppObserver* observer);
@@ -50,10 +57,12 @@
   std::string GetShelfAppId(aura::Window* window);
 
  private:
-  void HandleAnonymousApp(const std::string& anon_id);
+  // aura::WindowObserver overrides.
+  void OnWindowDestroying(aura::Window* window) override;
 
   Profile* const profile_;
-  base::flat_set<std::string> known_anon_ids_;
+  base::flat_map<std::string, base::flat_set<aura::Window*>>
+      anon_ids_to_windows_;
   base::ObserverList<AnonymousAppObserver> observers_;
 };
 
diff --git a/chrome/browser/chromeos/borealis/borealis_window_manager_unittest.cc b/chrome/browser/chromeos/borealis/borealis_window_manager_unittest.cc
index c508ff4..f8b838a 100644
--- a/chrome/browser/chromeos/borealis/borealis_window_manager_unittest.cc
+++ b/chrome/browser/chromeos/borealis/borealis_window_manager_unittest.cc
@@ -22,11 +22,13 @@
     : public borealis::BorealisWindowManager::AnonymousAppObserver {
  public:
   MOCK_METHOD(void,
-              NewAnonymousAppDetected,
+              OnAnonymousAppAdded,
               (const std::string&, const std::string&),
               ());
 
-  MOCK_METHOD(void, WindowManagerWillBeDeleted, (BorealisWindowManager*), ());
+  MOCK_METHOD(void, OnAnonymousAppRemoved, (const std::string&), ());
+
+  MOCK_METHOD(void, OnWindowManagerDeleted, (BorealisWindowManager*), ());
 };
 
 class BorealisWindowManagerTest : public testing::Test {
@@ -64,7 +66,7 @@
   BorealisWindowManager window_manager(profile());
   window_manager.AddObserver(&observer);
 
-  EXPECT_CALL(observer, WindowManagerWillBeDeleted(&window_manager))
+  EXPECT_CALL(observer, OnWindowManagerDeleted(&window_manager))
       .WillOnce(testing::Invoke([&observer](BorealisWindowManager* wm) {
         wm->RemoveObserver(&observer);
       }));
@@ -72,9 +74,9 @@
 
 TEST_F(BorealisWindowManagerTest, ObserverCalledForAnonymousApp) {
   testing::StrictMock<MockAnonObserver> observer;
-  EXPECT_CALL(observer,
-              NewAnonymousAppDetected(testing::ContainsRegex("anonymous_app"),
-                                      testing::_));
+  EXPECT_CALL(
+      observer,
+      OnAnonymousAppAdded(testing::ContainsRegex("anonymous_app"), testing::_));
 
   BorealisWindowManager window_manager(profile());
   window_manager.AddObserver(&observer);
@@ -82,6 +84,35 @@
       MakeWindow("org.chromium.borealis.anonymous_app");
   window_manager.GetShelfAppId(window.get());
 
+  EXPECT_CALL(observer,
+              OnAnonymousAppRemoved(testing::ContainsRegex("anonymous_app")));
+  window.reset();
+
+  window_manager.RemoveObserver(&observer);
+}
+
+TEST_F(BorealisWindowManagerTest, HandlesMultipleWindows) {
+  testing::StrictMock<MockAnonObserver> observer;
+
+  BorealisWindowManager window_manager(profile());
+  window_manager.AddObserver(&observer);
+
+  // We add an anonymous window for the same app twice, but we should only see
+  // one observer call.
+  EXPECT_CALL(observer, OnAnonymousAppAdded(testing::_, testing::_)).Times(1);
+
+  std::unique_ptr<aura::Window> window1 =
+      MakeWindow("org.chromium.borealis.anonymous_app");
+  window_manager.GetShelfAppId(window1.get());
+  std::unique_ptr<aura::Window> window2 =
+      MakeWindow("org.chromium.borealis.anonymous_app");
+  window_manager.GetShelfAppId(window2.get());
+
+  // We only expect to see the app removed after the last window closes.
+  window1.reset();
+  EXPECT_CALL(observer, OnAnonymousAppRemoved(testing::_)).Times(1);
+  window2.reset();
+
   window_manager.RemoveObserver(&observer);
 }
 
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
index af5c37aa..ef06058 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -395,6 +395,8 @@
     case apps::mojom::Readiness::kUninstalledByUser:
       return api::autotest_private::AppReadiness::
           APP_READINESS_UNINSTALLEDBYUSER;
+    case apps::mojom::Readiness::kRemoved:
+      return api::autotest_private::AppReadiness::APP_READINESS_REMOVED;
     case apps::mojom::Readiness::kUnknown:
       return api::autotest_private::AppReadiness::APP_READINESS_NONE;
   }
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 7618e26..f5161b9 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -66,16 +66,6 @@
     return *this;
   }
 
-  TestCase& FilesNg() {
-    options.files_ng = true;
-    return *this;
-  }
-
-  TestCase& DisableFilesNg() {
-    options.files_ng = false;
-    return *this;
-  }
-
   TestCase& FilesSwa() {
     options.files_swa = true;
     return *this;
@@ -165,9 +155,6 @@
     if (options.tablet_mode)
       full_name += "_TabletMode";
 
-    if (!options.files_ng)
-      full_name += "_DisableFilesNg";
-
     if (options.files_swa)
       full_name += "_FilesSwa";
 
@@ -389,8 +376,7 @@
     CreateNewFolder, /* create_new_folder.js */
     FilesAppBrowserTest,
     ::testing::Values(TestCase("selectCreateFolderDownloads").InGuestMode(),
-                      TestCase("selectCreateFolderDownloads").FilesNg(),
-                      TestCase("selectCreateFolderDownloads").DisableFilesNg(),
+                      TestCase("selectCreateFolderDownloads"),
                       TestCase("createFolderDownloads").InGuestMode(),
                       TestCase("createFolderDownloads"),
                       TestCase("createFolderNestedDownloads"),
@@ -400,8 +386,7 @@
     KeyboardOperations, /* keyboard_operations.js */
     FilesAppBrowserTest,
     ::testing::Values(TestCase("keyboardDeleteDownloads").InGuestMode(),
-                      TestCase("keyboardDeleteDownloads").FilesNg(),
-                      TestCase("keyboardDeleteDownloads").DisableFilesNg(),
+                      TestCase("keyboardDeleteDownloads"),
                       TestCase("keyboardDeleteDrive"),
                       TestCase("keyboardDeleteFolderDownloads").InGuestMode(),
                       TestCase("keyboardDeleteFolderDownloads"),
@@ -419,8 +404,7 @@
                       TestCase("renameFileDownloads"),
                       TestCase("renameFileDrive"),
                       TestCase("renameNewFolderDownloads").InGuestMode(),
-                      TestCase("renameNewFolderDownloads").FilesNg(),
-                      TestCase("renameNewFolderDownloads").DisableFilesNg(),
+                      TestCase("renameNewFolderDownloads"),
                       TestCase("renameNewFolderDrive")));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
@@ -484,7 +468,7 @@
         TestCase("toolbarDeleteEntry").InGuestMode(),
         TestCase("toolbarDeleteEntry"),
         TestCase("toolbarRefreshButtonWithSelection").EnableArc(),
-        TestCase("toolbarAltACommand").FilesNg(),
+        TestCase("toolbarAltACommand"),
         TestCase("toolbarRefreshButtonHiddenInRecents"),
         TestCase("toolbarMultiMenuFollowsButton"),
         TestCase("toolbarSharesheetButtonWithSelection").EnableSharesheet(),
@@ -496,8 +480,7 @@
     QuickView, /* quick_view.js */
     FilesAppBrowserTest,
     ::testing::Values(
-        TestCase("openQuickView").DisableFilesNg(),
-        TestCase("openQuickView").FilesNg(),
+        TestCase("openQuickView"),
         TestCase("openQuickViewDialog"),
         TestCase("openQuickViewAndEscape"),
         TestCase("openQuickView").InGuestMode(),
@@ -565,10 +548,8 @@
     DirectoryTree, /* directory_tree.js */
     FilesAppBrowserTest,
     ::testing::Values(
-        TestCase("directoryTreeActiveDirectory").DisableFilesNg(),
-        TestCase("directoryTreeActiveDirectory").FilesNg(),
-        TestCase("directoryTreeSelectedDirectory").DisableFilesNg(),
-        TestCase("directoryTreeSelectedDirectory").FilesNg(),
+        TestCase("directoryTreeActiveDirectory"),
+        TestCase("directoryTreeSelectedDirectory"),
         TestCase("directoryTreeRecentsSubtypeScroll").EnableUnifiedMediaView(),
         TestCase("directoryTreeHorizontalScroll"),
         TestCase("directoryTreeExpandHorizontalScroll"),
@@ -585,8 +566,7 @@
     FilesAppBrowserTest,
     ::testing::Values(
         TestCase("dirCopyWithContextMenu").InGuestMode(),
-        TestCase("dirCopyWithContextMenu").FilesNg(),
-        TestCase("dirCopyWithContextMenu").DisableFilesNg(),
+        TestCase("dirCopyWithContextMenu"),
         TestCase("dirCopyWithKeyboard").InGuestMode(),
         TestCase("dirCopyWithKeyboard"),
         TestCase("dirCopyWithoutChangingCurrent"),
@@ -693,14 +673,12 @@
         TestCase("transferFromDriveToTeamDrive"),
         TestCase("transferFromTeamDriveToDownloads"),
         TestCase("transferHostedFileFromTeamDriveToDownloads"),
-        TestCase("transferFromDownloadsToTeamDrive").DisableFilesNg(),
-        TestCase("transferFromDownloadsToTeamDrive").FilesNg(),
-        TestCase("transferBetweenTeamDrives").DisableFilesNg(),
-        TestCase("transferBetweenTeamDrives").FilesNg(),
+        TestCase("transferFromDownloadsToTeamDrive"),
+        TestCase("transferBetweenTeamDrives"),
         TestCase("transferDragDropActiveLeave"),
         TestCase("transferDragDropActiveDrop"),
-        TestCase("transferDragDropTreeItemAccepts").FilesNg(),
-        TestCase("transferDragDropTreeItemDenies").FilesNg(),
+        TestCase("transferDragDropTreeItemAccepts"),
+        TestCase("transferDragDropTreeItemDenies"),
         TestCase("transferDragAndHoverTreeItemEntryList"),
         TestCase("transferDragAndHoverTreeItemFakeEntry"),
         TestCase("transferDragAndHoverTreeItemFakeEntry")
@@ -735,8 +713,7 @@
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
     ShareAndManageDialog, /* share_and_manage_dialog.js */
     FilesAppBrowserTest,
-    ::testing::Values(TestCase("shareFileDrive").DisableFilesNg(),
-                      TestCase("shareFileDrive").FilesNg(),
+    ::testing::Values(TestCase("shareFileDrive"),
                       TestCase("shareDirectoryDrive"),
                       TestCase("shareHostedFileDrive"),
                       TestCase("manageHostedFileDrive"),
@@ -748,8 +725,7 @@
                       TestCase("shareTeamDrive"),
                       TestCase("manageHostedFileTeamDrive"),
                       TestCase("manageFileTeamDrive"),
-                      TestCase("manageDirectoryTeamDrive").DisableFilesNg(),
-                      TestCase("manageDirectoryTeamDrive").FilesNg(),
+                      TestCase("manageDirectoryTeamDrive"),
                       TestCase("manageTeamDrive")));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
@@ -783,10 +759,8 @@
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
     FolderShortcuts, /* folder_shortcuts.js */
     FilesAppBrowserTest,
-    ::testing::Values(TestCase("traverseFolderShortcuts").DisableFilesNg(),
-                      TestCase("traverseFolderShortcuts").FilesNg(),
-                      TestCase("addRemoveFolderShortcuts").DisableFilesNg(),
-                      TestCase("addRemoveFolderShortcuts").FilesNg()));
+    ::testing::Values(TestCase("traverseFolderShortcuts"),
+                      TestCase("addRemoveFolderShortcuts")));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
     SortColumns, /* sort_columns.js */
@@ -798,50 +772,20 @@
     TabIndex, /* tab_index.js: */
     FilesAppBrowserTest,
     ::testing::Values(
-        TestCase("tabindexSearchBoxFocus").FilesNg(),
-        TestCase("tabindexSearchBoxFocus").DisableFilesNg(),
-        TestCase("tabindexFocus").DisableFilesNg(),
-        TestCase("tabindexFocusDownloads").FilesNg(),
-        TestCase("tabindexFocusDownloads").DisableFilesNg(),
-        TestCase("tabindexFocusDownloads").InGuestMode().FilesNg(),
-        TestCase("tabindexFocusDownloads").InGuestMode().DisableFilesNg(),
-        // TestCase("tabindexFocusBreadcrumbBackground").FilesNg(),
-        TestCase("tabindexFocusBreadcrumbBackground").DisableFilesNg(),
-        TestCase("tabindexFocusDirectorySelected")
-            .FilesNg()
-            .DisableSharesheet(),
-        TestCase("tabindexFocusDirectorySelected")
-            .DisableFilesNg()
-            .DisableSharesheet(),
+        TestCase("tabindexSearchBoxFocus"),
+        TestCase("tabindexFocus"),
+        TestCase("tabindexFocusDownloads"),
+        TestCase("tabindexFocusDownloads").InGuestMode(),
+        TestCase("tabindexFocusDirectorySelected").DisableSharesheet(),
         TestCase("tabindexFocusDirectorySelectedSharesheetEnabled")
-            .FilesNg()
             .EnableSharesheet(),
-        TestCase("tabindexOpenDialogDownloadsFilesNg").WithBrowser().FilesNg(),
-        TestCase("tabindexOpenDialogDownloads").WithBrowser().DisableFilesNg(),
-        TestCase("tabindexOpenDialogDownloads")
-            .WithBrowser()
-            .InGuestMode()
-            .DisableFilesNg(),
-        TestCase("tabindexOpenDialogDownloadsFilesNg")
-            .WithBrowser()
-            .InGuestMode()
-            .FilesNg(),
-        TestCase("tabindexSaveFileDialogDriveFilesNg").WithBrowser().FilesNg(),
-        TestCase("tabindexSaveFileDialogDrive").WithBrowser().DisableFilesNg(),
-        TestCase("tabindexSaveFileDialogDownloadsFilesNg")
-            .WithBrowser()
-            .FilesNg(),
+        TestCase("tabindexOpenDialogDownloads").WithBrowser(),
+        TestCase("tabindexOpenDialogDownloads").WithBrowser().InGuestMode(),
+        TestCase("tabindexSaveFileDialogDrive").WithBrowser(),
+        TestCase("tabindexSaveFileDialogDownloads").WithBrowser(),
         TestCase("tabindexSaveFileDialogDownloads")
             .WithBrowser()
-            .DisableFilesNg(),
-        TestCase("tabindexSaveFileDialogDownloads")
-            .WithBrowser()
-            .InGuestMode()
-            .DisableFilesNg(),
-        TestCase("tabindexSaveFileDialogDownloadsFilesNg")
-            .WithBrowser()
-            .InGuestMode()
-            .FilesNg()));
+            .InGuestMode()));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
     FileDialog, /* file_dialog.js */
@@ -900,13 +844,12 @@
     GridView, /* grid_view.js */
     FilesAppBrowserTest,
     ::testing::Values(
-        TestCase("showGridViewDownloads").DisableFilesNg(),
         TestCase("showGridViewDownloads").InGuestMode(),
-        TestCase("showGridViewDownloads").FilesNg(),
+        TestCase("showGridViewDownloads"),
         TestCase("showGridViewDrive"),
         TestCase("showGridViewButtonSwitches"),
         TestCase("showGridViewKeyboardSelectionA11y"),
-        TestCase("showGridViewTitles").FilesNg(),
+        TestCase("showGridViewTitles"),
         TestCase("showGridViewMouseSelectionA11y"),
         TestCase("showGridViewDocumentsProvider").EnableDocumentsProvider()));
 
@@ -952,25 +895,19 @@
                       TestCase("filesTooltipMouseOver"),
                       TestCase("filesTooltipClickHides"),
                       TestCase("filesTooltipHidesOnWindowResize"),
-                      TestCase("filesCardTooltipClickHides")));
+                      TestCase("filesCardTooltipClickHides"),
+                      TestCase("filesTooltipHidesOnDeleteDialogClosed")));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
     FileList, /* file_list.js */
     FilesAppBrowserTest,
-    ::testing::Values(
-        TestCase("fileListAriaAttributes").DisableFilesNg(),
-        TestCase("fileListAriaAttributes").FilesNg(),
-        TestCase("fileListFocusFirstItem").DisableFilesNg(),
-        TestCase("fileListFocusFirstItem").FilesNg(),
-        TestCase("fileListSelectLastFocusedItem").DisableFilesNg(),
-        TestCase("fileListSelectLastFocusedItem").FilesNg(),
-        TestCase("fileListKeyboardSelectionA11y").DisableFilesNg(),
-        TestCase("fileListKeyboardSelectionA11y").FilesNg(),
-        TestCase("fileListMouseSelectionA11y").DisableFilesNg(),
-        TestCase("fileListMouseSelectionA11y").FilesNg(),
-        TestCase("fileListDeleteMultipleFiles").DisableFilesNg(),
-        TestCase("fileListDeleteMultipleFiles").FilesNg(),
-        TestCase("fileListRenameFromSelectAll").FilesNg()));
+    ::testing::Values(TestCase("fileListAriaAttributes"),
+                      TestCase("fileListFocusFirstItem"),
+                      TestCase("fileListSelectLastFocusedItem"),
+                      TestCase("fileListKeyboardSelectionA11y"),
+                      TestCase("fileListMouseSelectionA11y"),
+                      TestCase("fileListDeleteMultipleFiles"),
+                      TestCase("fileListRenameFromSelectAll")));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
     Crostini, /* crostini.js */
@@ -987,13 +924,12 @@
     FilesAppBrowserTest,
     ::testing::Values(
         TestCase("directoryTreeRefresh"),
-        TestCase("showMyFiles").DisableFilesNg(),
+        TestCase("showMyFiles"),
         TestCase("myFilesDisplaysAndOpensEntries"),
         TestCase("myFilesFolderRename"),
         TestCase("myFilesUpdatesWhenAndroidVolumeMounts").DontMountVolumes(),
         TestCase("myFilesUpdatesChildren"),
-        TestCase("myFilesAutoExpandOnce").DisableFilesNg(),
-        TestCase("myFilesAutoExpandOnce").FilesNg(),
+        TestCase("myFilesAutoExpandOnce"),
         TestCase("myFilesToolbarDelete")));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
@@ -1039,10 +975,8 @@
     FilesAppBrowserTest,
     ::testing::Values(
         TestCase("metadataDocumentsProvider").EnableDocumentsProvider(),
-        TestCase("metadataDownloads").DisableFilesNg(),
-        TestCase("metadataDownloads").FilesNg(),
-        TestCase("metadataDrive").DisableFilesNg(),
-        TestCase("metadataDrive").FilesNg(),
+        TestCase("metadataDownloads"),
+        TestCase("metadataDrive"),
         TestCase("metadataTeamDrives"),
         TestCase("metadataLargeDrive")));
 
@@ -1063,25 +997,22 @@
     FilesAppBrowserTest,
     ::testing::Values(TestCase("metricsRecordEnum")));
 
-// TODO(adanilo) Remove 'breadcrumbsLeafNoFocus' when files-ng ships.
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
     Breadcrumbs, /* breadcrumbs.js */
     FilesAppBrowserTest,
-    ::testing::Values(TestCase("breadcrumbsNavigate").DisableFilesNg(),
-                      TestCase("breadcrumbsLeafNoFocus").DisableFilesNg(),
-                      TestCase("breadcrumbsTooltip").DisableFilesNg(),
+    ::testing::Values(TestCase("breadcrumbsNavigate"),
                       TestCase("breadcrumbsDownloadsTranslation"),
-                      TestCase("breadcrumbsRenderShortPath").FilesNg(),
-                      TestCase("breadcrumbsEliderButtonHidden").FilesNg(),
-                      TestCase("breadcrumbsRenderLongPath").FilesNg(),
-                      TestCase("breadcrumbsMainButtonClick").FilesNg(),
-                      TestCase("breadcrumbsMainButtonEnterKey").FilesNg(),
-                      TestCase("breadcrumbsEliderButtonClick").FilesNg(),
-                      TestCase("breadcrumbsEliderButtonKeyboard").FilesNg(),
-                      TestCase("breadcrumbsEliderMenuClickOutside").FilesNg(),
-                      TestCase("breadcrumbsEliderMenuItemClick").FilesNg(),
-                      TestCase("breadcrumbsEliderMenuItemTabLeft").FilesNg(),
-                      TestCase("breadcrumbsEliderMenuItemTabRight").FilesNg()));
+                      TestCase("breadcrumbsRenderShortPath"),
+                      TestCase("breadcrumbsEliderButtonHidden"),
+                      TestCase("breadcrumbsRenderLongPath"),
+                      TestCase("breadcrumbsMainButtonClick"),
+                      TestCase("breadcrumbsMainButtonEnterKey"),
+                      TestCase("breadcrumbsEliderButtonClick"),
+                      TestCase("breadcrumbsEliderButtonKeyboard"),
+                      TestCase("breadcrumbsEliderMenuClickOutside"),
+                      TestCase("breadcrumbsEliderMenuItemClick"),
+                      TestCase("breadcrumbsEliderMenuItemTabLeft"),
+                      TestCase("breadcrumbsEliderMenuItemTabRight")));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
     FormatDialog, /* format_dialog.js */
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
index 60a1061d..2230798f 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -729,7 +729,6 @@
   PRINT_IF_NOT_DEFAULT(arc)
   PRINT_IF_NOT_DEFAULT(browser)
   PRINT_IF_NOT_DEFAULT(documents_provider)
-  PRINT_IF_NOT_DEFAULT(files_ng)
   PRINT_IF_NOT_DEFAULT(files_swa)
   PRINT_IF_NOT_DEFAULT(media_swa)
   PRINT_IF_NOT_DEFAULT(mount_volumes)
@@ -1650,12 +1649,6 @@
   std::vector<base::Feature> enabled_features;
   std::vector<base::Feature> disabled_features;
 
-  if (options.files_ng) {
-    enabled_features.push_back(chromeos::features::kFilesNG);
-  } else {
-    disabled_features.push_back(chromeos::features::kFilesNG);
-  }
-
   if (options.files_swa) {
     enabled_features.push_back(chromeos::features::kFilesSWA);
   } else {
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
index 8335b03a..65dbe6b 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
@@ -79,9 +79,6 @@
     // Whether Drive should act as if offline.
     bool offline = false;
 
-    // Whether test needs the files-ng feature.
-    bool files_ng = true;
-
     // Whether test needs the files-swa feature.
     bool files_swa = false;
 
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_base.h b/chrome/browser/chromeos/input_method/input_method_engine_base.h
index cc19114..ecebca7 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_base.h
+++ b/chrome/browser/chromeos/input_method/input_method_engine_base.h
@@ -266,7 +266,6 @@
     ~PendingKeyEvent();
 
     std::string component_id;
-    KeyboardEvent key_event;
     ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback;
 
    private:
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
index e35aaa9..6130bdad 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
@@ -141,9 +141,23 @@
     std::vector<ComponentExtensionIME> ime_list;
     InitImeList(ime_list);
 
+    std::set<std::string> login_layout_set = {"us",
+                                              "us(intl)",
+                                              "us(altgr-intl)",
+                                              "us(dvorak)",
+                                              "us(dvp)",
+                                              "us(colemak)",
+                                              "us(workman)",
+                                              "us(workman-intl)",
+                                              "fr",
+                                              "se",
+                                              "jp",
+                                              "hu"};
+
     auto mock_delegate =
         std::make_unique<MockComponentExtensionIMEManagerDelegate>();
     mock_delegate->set_ime_list(ime_list);
+    mock_delegate->set_login_layout_set(login_layout_set);
 
     manager_ = std::make_unique<InputMethodManagerImpl>(
         std::make_unique<FakeInputMethodDelegate>(), std::move(mock_delegate),
diff --git a/chrome/browser/chromeos/net/network_diagnostics/README.md b/chrome/browser/chromeos/net/network_diagnostics/README.md
index ed2099d..69cd7510 100644
--- a/chrome/browser/chromeos/net/network_diagnostics/README.md
+++ b/chrome/browser/chromeos/net/network_diagnostics/README.md
@@ -168,26 +168,6 @@
 * `kHighLatency`: HTTPS request latency is high.
 * `kVeryHighLatency`: HTTPS request latency is very high.
 
-#### VideoConferencing
-
-Tests the device's video conferencing capabalities by testing whether the device
-can:
-1. Contact either a default or specified STUN server via UDP.
-2. Contact either a default or specified STUN server via TCP.
-3. Reach common media endpoints.
-
-Problems:
-* `kPotentialProblemUdpFailure`: Failed requests to a STUN server via UDP.
-* `kPotentialProblemTcpFailure`: Failed requests to a STUN server via TCP.
-* `kPotentialProblemMediaFailure`: Failed to establish a TLS connection to media hostnames.
-* `kPotentialProblemUdpAndMediaFailure`: Failed requests to a STUN server via
-UDP and failed to establish a TLS connection to media hostnames.
-* `kUdpAndTcpFailure`: Failed requests to a STUN server via UDP and TCP.
-* `kTcpAndMediaFailure`: Failed requests to a STUN server via TCP and failed to
-established a TLS connection to media hostnames.
-* `kUdpAndTcpAndMediaFailure`: Failed requests to a STUN server via UDP and TCP,
-and failed to establish a TLS connection to media hostnames.
-
 [Network Health and Configuration]: https://docs.google.com/document/d/10DSy-jZXaRo9I9aq1UqERy76t7HkgGvInWk57pHEkzg
 [network_diagnostics.mojom]: https://source.chromium.org/chromium/chromium/src/+/master:chromeos/services/network_health/public/mojom/network_diagnostics.mojom?originalUrl=https:%2F%2Fcs.chromium.org%2F
 [NetworkHealthService]: https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/chromeos/net/network_health/network_health_service.h?originalUrl=https:%2F%2Fcs.chromium.org%2F
diff --git a/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.cc b/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.cc
index abb553c..99c49fa1 100644
--- a/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.cc
+++ b/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.cc
@@ -8,7 +8,6 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/optional.h"
 #include "chrome/browser/chromeos/net/network_diagnostics/captive_portal_routine.h"
 #include "chrome/browser/chromeos/net/network_diagnostics/dns_latency_routine.h"
 #include "chrome/browser/chromeos/net/network_diagnostics/dns_resolution_routine.h"
@@ -20,7 +19,6 @@
 #include "chrome/browser/chromeos/net/network_diagnostics/https_latency_routine.h"
 #include "chrome/browser/chromeos/net/network_diagnostics/lan_connectivity_routine.h"
 #include "chrome/browser/chromeos/net/network_diagnostics/signal_strength_routine.h"
-#include "chrome/browser/chromeos/net/network_diagnostics/video_conferencing_routine.h"
 #include "chromeos/dbus/debug_daemon/debug_daemon_client.h"
 #include "components/device_event_log/device_event_log.h"
 
@@ -211,26 +209,5 @@
       std::move(routine), std::move(callback)));
 }
 
-void NetworkDiagnostics::VideoConferencing(
-    const base::Optional<std::string>& stun_server_name,
-    VideoConferencingCallback callback) {
-  auto routine = std::make_unique<VideoConferencingRoutine>();
-  if (stun_server_name.has_value()) {
-    routine =
-        std::make_unique<VideoConferencingRoutine>(stun_server_name.value());
-  }
-  // RunRoutine() takes a lambda callback that takes ownership of the routine.
-  // This ensures that the routine stays alive when it makes asynchronous mojo
-  // calls. The routine will be destroyed when the lambda exits.
-  routine->RunRoutine(base::BindOnce(
-      [](std::unique_ptr<VideoConferencingRoutine> routine,
-         VideoConferencingCallback callback, mojom::RoutineVerdict verdict,
-         const std::vector<mojom::VideoConferencingProblem>& problems,
-         const base::Optional<std::string>& support_details) {
-        std::move(callback).Run(verdict, problems, support_details);
-      },
-      std::move(routine), std::move(callback)));
-}
-
 }  // namespace network_diagnostics
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.h b/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.h
index ce17a7d..04352ef 100644
--- a/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.h
+++ b/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.h
@@ -5,10 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_NET_NETWORK_DIAGNOSTICS_NETWORK_DIAGNOSTICS_H_
 #define CHROME_BROWSER_CHROMEOS_NET_NETWORK_DIAGNOSTICS_NETWORK_DIAGNOSTICS_H_
 
-#include <string>
-
 #include "base/memory/weak_ptr.h"
-#include "base/optional.h"
 #include "chromeos/services/network_health/public/mojom/network_diagnostics.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
@@ -42,8 +39,6 @@
   void DnsResolution(DnsResolutionCallback callback) override;
   void CaptivePortal(CaptivePortalCallback callback) override;
   void HttpsLatency(HttpsLatencyCallback callback) override;
-  void VideoConferencing(const base::Optional<std::string>& stun_server_name,
-                         VideoConferencingCallback callback) override;
 
  private:
   // An unowned pointer to the DebugDaemonClient instance.
diff --git a/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_util.cc b/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_util.cc
index 118d6bb..c138b64 100644
--- a/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_util.cc
+++ b/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_util.cc
@@ -182,35 +182,6 @@
   )");
 }
 
-std::vector<int> GetUdpPortsForGoogleStunServer() {
-  return {19302, 19303, 19304, 19305, 19306, 19307, 19308, 19309};
-}
-
-std::vector<int> GetUdpPortsForCustomStunServer() {
-  return {3478};
-}
-
-std::vector<int> GetTcpPortsForGoogleStunServer() {
-  return {19305, 19306, 19307, 19308};
-}
-
-std::vector<int> GetTcpPortsForCustomStunServer() {
-  return {3478};
-}
-
-std::vector<GURL> GetDefaultMediaUrls() {
-  const char* const kHostnames[] = {
-      "https://apis.google.com",           "https://talkgadget.google.com",
-      "https://clients6.google.com",       "https://hangouts.google.com",
-      "https://client-channel.google.com", "https://googleapis.com",
-      "https://accounts.google.com",       "https://clients4.google.com"};
-  std::vector<GURL> hostnames;
-  for (auto* const& hostname : kHostnames) {
-    hostnames.push_back(GURL(hostname));
-  }
-  return hostnames;
-}
-
 }  // namespace util
 
 }  // namespace network_diagnostics
diff --git a/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_util.h b/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_util.h
index d2419f77..850c67a 100644
--- a/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_util.h
+++ b/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_util.h
@@ -90,21 +90,6 @@
 // Returns the traffic annotation tag for STUN traffic.
 net::NetworkTrafficAnnotationTag GetStunNetworkAnnotationTag();
 
-// Returns the ports used to speak to Google's STUN server over UDP.
-std::vector<int> GetUdpPortsForGoogleStunServer();
-
-// Returns the ports used to speak to a custom STUN server over UDP.
-std::vector<int> GetUdpPortsForCustomStunServer();
-
-// Returns the ports used to speak to Google's STUN server over TCP.
-std::vector<int> GetTcpPortsForGoogleStunServer();
-
-// Returns the ports used to speak to a custom STUN server over TCP.
-std::vector<int> GetTcpPortsForCustomStunServer();
-
-// Returns the list of urls related to Google media.
-std::vector<GURL> GetDefaultMediaUrls();
-
 }  // namespace util
 
 }  // namespace network_diagnostics
diff --git a/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_util_unittest.cc b/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_util_unittest.cc
index 1c57e32..47c1fb69 100644
--- a/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_util_unittest.cc
+++ b/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_util_unittest.cc
@@ -76,11 +76,5 @@
   }
 }
 
-TEST(NetworkDiagnosticsUtilTest, TestDefaultMediaHostnamesAreValidUrls) {
-  for (const GURL& url : util::GetDefaultMediaUrls()) {
-    EXPECT_TRUE(url.is_valid());
-  }
-}
-
 }  // namespace network_diagnostics
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/net/network_diagnostics/video_conferencing_routine.cc b/chrome/browser/chromeos/net/network_diagnostics/video_conferencing_routine.cc
deleted file mode 100644
index aeb9dcf81..0000000
--- a/chrome/browser/chromeos/net/network_diagnostics/video_conferencing_routine.cc
+++ /dev/null
@@ -1,215 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/net/network_diagnostics/video_conferencing_routine.h"
-
-#include <string>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/optional.h"
-#include "base/time/time.h"
-#include "chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_util.h"
-#include "chrome/browser/chromeos/net/network_diagnostics/udp_prober.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "content/public/browser/storage_partition.h"
-#include "net/base/net_errors.h"
-#include "services/network/public/mojom/network_context.mojom.h"
-
-namespace chromeos {
-namespace network_diagnostics {
-
-namespace {
-
-const char kDefaultStunServer[] = "stun.l.google.com";
-
-}  // namespace
-
-const char kSupportDetails[] = "https://support.google.com/a/answer/1279090";
-const base::TimeDelta kTimeoutAfterHostResolution =
-    base::TimeDelta::FromSeconds(10);
-
-VideoConferencingRoutine::VideoConferencingRoutine()
-    : stun_server_hostname_(kDefaultStunServer),
-      udp_prober_getter_callback_(base::BindRepeating(
-          &VideoConferencingRoutine::CreateAndExecuteUdpProber)),
-      tls_prober_getter_callback_(base::BindRepeating(
-          &VideoConferencingRoutine::CreateAndExecuteTlsProber)),
-      udp_ports_(util::GetUdpPortsForGoogleStunServer()),
-      tcp_ports_(util::GetTcpPortsForGoogleStunServer()),
-      media_hostnames_(util::GetDefaultMediaUrls()) {}
-
-VideoConferencingRoutine::VideoConferencingRoutine(
-    const std::string& stun_server_hostname)
-    : stun_server_hostname_(stun_server_hostname),
-      udp_prober_getter_callback_(base::BindRepeating(
-          &VideoConferencingRoutine::CreateAndExecuteUdpProber)),
-      tls_prober_getter_callback_(base::BindRepeating(
-          &VideoConferencingRoutine::CreateAndExecuteTlsProber)),
-      udp_ports_(util::GetUdpPortsForCustomStunServer()),
-      tcp_ports_(util::GetTcpPortsForCustomStunServer()),
-      media_hostnames_(util::GetDefaultMediaUrls()) {}
-
-VideoConferencingRoutine::~VideoConferencingRoutine() = default;
-
-void VideoConferencingRoutine::AnalyzeResultsAndExecuteCallback() {
-  base::Optional<std::string> support_details = kSupportDetails;
-  set_verdict(mojom::RoutineVerdict::kProblem);
-  if (!open_udp_port_found_) {
-    problems_.push_back(mojom::VideoConferencingProblem::kUdpFailure);
-  }
-  if (!open_tcp_port_found_) {
-    problems_.push_back(mojom::VideoConferencingProblem::kTcpFailure);
-  }
-  if (!media_hostnames_reachable_) {
-    problems_.push_back(mojom::VideoConferencingProblem::kMediaFailure);
-  }
-  if (problems_.empty()) {
-    set_verdict(mojom::RoutineVerdict::kNoProblem);
-    support_details = base::nullopt;
-  }
-  std::move(routine_completed_callback_)
-      .Run(verdict(), std::move(problems_), support_details);
-}
-
-void VideoConferencingRoutine::RunRoutine(
-    VideoConferencingRoutineCallback callback) {
-  if (!CanRun()) {
-    std::move(callback).Run(verdict(), std::move(problems_), base::nullopt);
-    return;
-  }
-  routine_completed_callback_ = std::move(callback);
-  ProbeStunServerOverUdp();
-}
-
-void VideoConferencingRoutine::ProbeStunServerOverUdp() {
-  if (udp_ports_.empty()) {
-    ProbeStunServerOverTcp();
-    return;
-  }
-  int port = udp_ports_.back();
-  udp_ports_.pop_back();
-  AttemptUdpProbe(net::HostPortPair(stun_server_hostname_, port));
-}
-
-void VideoConferencingRoutine::ProbeStunServerOverTcp() {
-  if (tcp_ports_.empty()) {
-    ProbeMediaHostnames();
-    return;
-  }
-  int port = tcp_ports_.back();
-  tcp_ports_.pop_back();
-  AttemptTcpProbe(net::HostPortPair(stun_server_hostname_, port));
-}
-
-void VideoConferencingRoutine::ProbeMediaHostnames() {
-  if (media_hostnames_.empty()) {
-    AnalyzeResultsAndExecuteCallback();
-    return;
-  }
-  const GURL& url = media_hostnames_.back();
-  media_hostnames_.pop_back();
-  AttemptTlsProbe(net::HostPortPair::FromURL(url));
-}
-
-network::mojom::NetworkContext* VideoConferencingRoutine::GetNetworkContext() {
-  Profile* profile = util::GetUserProfile();
-  DCHECK(profile);
-
-  return content::BrowserContext::GetDefaultStoragePartition(profile)
-      ->GetNetworkContext();
-}
-
-std::unique_ptr<UdpProber> VideoConferencingRoutine::CreateAndExecuteUdpProber(
-    UdpProber::NetworkContextGetter network_context_getter,
-    net::HostPortPair host_port_pair,
-    base::span<const uint8_t> data,
-    net::NetworkTrafficAnnotationTag tag,
-    base::TimeDelta timeout_after_host_resolution,
-    UdpProber::UdpProbeCompleteCallback callback) {
-  return UdpProber::Start(std::move(network_context_getter), host_port_pair,
-                          std::move(data), tag, timeout_after_host_resolution,
-                          std::move(callback));
-}
-
-std::unique_ptr<TlsProber> VideoConferencingRoutine::CreateAndExecuteTlsProber(
-    TlsProber::NetworkContextGetter network_context_getter,
-    net::HostPortPair host_port_pair,
-    bool negotiate_tls,
-    TlsProber::TlsProbeCompleteCallback callback) {
-  return std::make_unique<TlsProber>(std::move(network_context_getter),
-                                     host_port_pair, negotiate_tls,
-                                     std::move(callback));
-}
-
-void VideoConferencingRoutine::AttemptUdpProbe(
-    net::HostPortPair host_port_pair) {
-  // Store the instance of UdpProber.
-  udp_prober_ = udp_prober_getter_callback_.Run(
-      base::BindRepeating(&VideoConferencingRoutine::GetNetworkContext),
-      host_port_pair, util::GetStunHeader(),
-      util::GetStunNetworkAnnotationTag(), kTimeoutAfterHostResolution,
-      base::BindOnce(&VideoConferencingRoutine::OnUdpProbeComplete,
-                     weak_ptr()));
-}
-
-void VideoConferencingRoutine::AttemptTcpProbe(
-    net::HostPortPair host_port_pair) {
-  tls_prober_ = tls_prober_getter_callback_.Run(
-      base::BindRepeating(&VideoConferencingRoutine::GetNetworkContext),
-      host_port_pair,
-      /*negotiate_tls=*/false,
-      base::BindOnce(&VideoConferencingRoutine::OnTcpProbeComplete,
-                     weak_ptr()));
-}
-
-void VideoConferencingRoutine::AttemptTlsProbe(
-    net::HostPortPair host_port_pair) {
-  // Store the instance of TlsProber.
-  tls_prober_ = tls_prober_getter_callback_.Run(
-      base::BindRepeating(&VideoConferencingRoutine::GetNetworkContext),
-      host_port_pair,
-      /*negotiate_tls=*/true,
-      base::BindOnce(&VideoConferencingRoutine::OnTlsProbeComplete,
-                     weak_ptr()));
-}
-
-void VideoConferencingRoutine::OnUdpProbeComplete(
-    int result,
-    UdpProber::ProbeExitEnum probe_exit_enum) {
-  if (result == net::OK) {
-    open_udp_port_found_ = true;
-    // Only one open UDP port needs to be detected.
-    ProbeStunServerOverTcp();
-    return;
-  }
-  ProbeStunServerOverUdp();
-}
-
-void VideoConferencingRoutine::OnTcpProbeComplete(
-    int result,
-    TlsProber::ProbeExitEnum probe_exit_enum) {
-  if (result == net::OK) {
-    open_tcp_port_found_ = true;
-    // Only one open TCP port needs to be detected.
-    ProbeMediaHostnames();
-    return;
-  }
-  ProbeStunServerOverTcp();
-}
-
-void VideoConferencingRoutine::OnTlsProbeComplete(
-    int result,
-    TlsProber::ProbeExitEnum probe_exit_enum) {
-  if (result != net::OK) {
-    media_hostnames_reachable_ = false;
-    // All media hostnames must be reachable.
-    AnalyzeResultsAndExecuteCallback();
-    return;
-  }
-  ProbeMediaHostnames();
-}
-
-}  // namespace network_diagnostics
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/net/network_diagnostics/video_conferencing_routine.h b/chrome/browser/chromeos/net/network_diagnostics/video_conferencing_routine.h
deleted file mode 100644
index 68e64bf..0000000
--- a/chrome/browser/chromeos/net/network_diagnostics/video_conferencing_routine.h
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_NET_NETWORK_DIAGNOSTICS_VIDEO_CONFERENCING_ROUTINE_H_
-#define CHROME_BROWSER_CHROMEOS_NET_NETWORK_DIAGNOSTICS_VIDEO_CONFERENCING_ROUTINE_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/containers/span.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_routine.h"
-#include "chrome/browser/chromeos/net/network_diagnostics/tls_prober.h"
-#include "chrome/browser/chromeos/net/network_diagnostics/udp_prober.h"
-#include "net/base/net_errors.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "url/gurl.h"
-
-namespace chromeos {
-namespace network_diagnostics {
-
-extern const char kSupportDetails[];
-extern const base::TimeDelta kTimeoutAfterHostResolution;
-
-// Tests the device's video conferencing capabilities by testing the connection
-// to a sample of Google servers used in various GVC offerings. See the
-// README.md file for more details.
-class VideoConferencingRoutine : public NetworkDiagnosticsRoutine {
- public:
-  using VideoConferencingRoutineCallback =
-      mojom::NetworkDiagnosticsRoutines::VideoConferencingCallback;
-  using UdpProberGetterCallback =
-      base::RepeatingCallback<std::unique_ptr<UdpProber>(
-          UdpProber::NetworkContextGetter network_context_getter,
-          net::HostPortPair host_port_pair,
-          base::span<const uint8_t> data,
-          net::NetworkTrafficAnnotationTag tag,
-          base::TimeDelta timeout_after_host_resolution,
-          UdpProber::UdpProbeCompleteCallback callback)>;
-  using TlsProberGetterCallback =
-      base::RepeatingCallback<std::unique_ptr<TlsProber>(
-          TlsProber::NetworkContextGetter network_context_getter,
-          net::HostPortPair host_port_pair,
-          bool negotiate_tls,
-          TlsProber::TlsProbeCompleteCallback callback)>;
-
-  // Creates a routine using a default STUN server.
-  VideoConferencingRoutine();
-  // Creates a routine using a custom STUN server.
-  explicit VideoConferencingRoutine(const std::string& stun_server_hostname);
-  VideoConferencingRoutine(const VideoConferencingRoutine&) = delete;
-  VideoConferencingRoutine& operator=(const VideoConferencingRoutine&) = delete;
-  ~VideoConferencingRoutine() override;
-
-  // NetworkDiagnosticsRoutine:
-  void AnalyzeResultsAndExecuteCallback() override;
-
-  // Run the core logic of this routine. Set |callback| to
-  // |routine_completed_callback_|, which is to be executed in
-  // AnalyzeResultsAndExecuteCallback().
-  void RunRoutine(VideoConferencingRoutineCallback callback);
-
-  void set_udp_prober_getter_callback_for_testing(
-      UdpProberGetterCallback udp_prober_getter_callback) {
-    udp_prober_getter_callback_ = std::move(udp_prober_getter_callback);
-  }
-
-  void set_tls_prober_getter_callback_for_testing(
-      TlsProberGetterCallback tls_prober_getter_callback) {
-    tls_prober_getter_callback_ = std::move(tls_prober_getter_callback);
-  }
-
- private:
-  // Probes the STUN server over UDP to determine whether an open port
-  // connection exists.
-  void ProbeStunServerOverUdp();
-
-  // Probes the STUN server over TCP to determine whether an open port
-  // connection exists.
-  void ProbeStunServerOverTcp();
-
-  // Probes media endpoints over TCP with TLS.
-  void ProbeMediaHostnames();
-
-  // Returns the network context.
-  static network::mojom::NetworkContext* GetNetworkContext();
-
-  // Creates and instance of UdpProber.
-  static std::unique_ptr<UdpProber> CreateAndExecuteUdpProber(
-      UdpProber::NetworkContextGetter network_context_getter,
-      net::HostPortPair host_port_pair,
-      base::span<const uint8_t> data,
-      net::NetworkTrafficAnnotationTag tag,
-      base::TimeDelta timeout_after_host_resolution,
-      UdpProber::UdpProbeCompleteCallback callback);
-
-  // Creates an instance of TlsProber.
-  static std::unique_ptr<TlsProber> CreateAndExecuteTlsProber(
-      TlsProber::NetworkContextGetter network_context_getter,
-      net::HostPortPair host_port_pair,
-      bool negotiate_tls,
-      TlsProber::TlsProbeCompleteCallback callback);
-
-  // Launches a UDP probe.
-  void AttemptUdpProbe(net::HostPortPair host_port_pair);
-
-  // Launches a TCP probe.
-  void AttemptTcpProbe(net::HostPortPair host_port_pair);
-
-  // Launches a TLS probe.
-  void AttemptTlsProbe(net::HostPortPair host_port_pair);
-
-  // Handles UDP probe completion.
-  void OnUdpProbeComplete(int result, UdpProber::ProbeExitEnum probe_exit_enum);
-
-  // Handles TCP probe completion.
-  void OnTcpProbeComplete(int result, TlsProber::ProbeExitEnum probe_exit_enum);
-
-  // Handles TLS probe completion.
-  void OnTlsProbeComplete(int result, TlsProber::ProbeExitEnum probe_exit_enum);
-
-  // Returns the weak pointer to |this|.
-  base::WeakPtr<VideoConferencingRoutine> weak_ptr() {
-    return weak_factory_.GetWeakPtr();
-  }
-
-  std::vector<mojom::VideoConferencingProblem> problems_;
-  VideoConferencingRoutineCallback routine_completed_callback_;
-  std::string stun_server_hostname_;
-  bool open_udp_port_found_ = false;
-  bool open_tcp_port_found_ = false;
-  bool media_hostnames_reachable_ = true;
-  UdpProberGetterCallback udp_prober_getter_callback_;
-  TlsProberGetterCallback tls_prober_getter_callback_;
-  std::unique_ptr<UdpProber> udp_prober_;
-  std::unique_ptr<TlsProber> tls_prober_;
-  std::vector<int> udp_ports_;
-  std::vector<int> tcp_ports_;
-  std::vector<GURL> media_hostnames_;
-
-  base::WeakPtrFactory<VideoConferencingRoutine> weak_factory_{this};
-};
-
-}  // namespace network_diagnostics
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_NET_NETWORK_DIAGNOSTICS_VIDEO_CONFERENCING_ROUTINE_H_
diff --git a/chrome/browser/chromeos/net/network_diagnostics/video_conferencing_routine_unittest.cc b/chrome/browser/chromeos/net/network_diagnostics/video_conferencing_routine_unittest.cc
deleted file mode 100644
index bc09d5e..0000000
--- a/chrome/browser/chromeos/net/network_diagnostics/video_conferencing_routine_unittest.cc
+++ /dev/null
@@ -1,542 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/net/network_diagnostics/video_conferencing_routine.h"
-
-#include <deque>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/optional.h"
-#include "base/run_loop.h"
-#include "base/time/time.h"
-#include "chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_util.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "chrome/test/base/testing_profile.h"
-#include "chrome/test/base/testing_profile_manager.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/test/browser_task_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace chromeos {
-namespace network_diagnostics {
-
-namespace {
-
-// Test implementation of UdpProber.
-class TestUdpProber final : public UdpProber {
- public:
-  TestUdpProber(UdpProber::UdpProbeCompleteCallback callback,
-                int result,
-                UdpProber::ProbeExitEnum probe_exit_enum) {
-    // Post an asynchronus task simulating a completed probe. This mimics the
-    // behavior of the production UdpProber constructor since the TestUdpProber
-    // instance will be complete before FinishProbe is invoked. In the
-    // production UdpProber, the constructor completes before DNS host
-    // resolution is complete.
-    content::GetUIThreadTaskRunner({})->PostTask(
-        FROM_HERE,
-        base::BindOnce(&TestUdpProber::FinishProbe, weak_factory_.GetWeakPtr(),
-                       std::move(callback), result, probe_exit_enum));
-  }
-
-  TestUdpProber(const TestUdpProber&) = delete;
-  TestUdpProber& operator=(const TestUdpProber&) = delete;
-  ~TestUdpProber() override = default;
-
- private:
-  void FinishProbe(UdpProber::UdpProbeCompleteCallback callback,
-                   int result,
-                   UdpProber::ProbeExitEnum probe_exit_enum) {
-    std::move(callback).Run(result, probe_exit_enum);
-  }
-
-  base::WeakPtrFactory<TestUdpProber> weak_factory_{this};
-};
-
-// Test implementation of TlsProber.
-class TestTlsProber final : public TlsProber {
- public:
-  TestTlsProber(TlsProber::TlsProbeCompleteCallback callback,
-                int result,
-                TlsProber::ProbeExitEnum probe_exit_enum) {
-    // Post an asynchronus task simulating a completed probe. This mimics the
-    // behavior of the production TlsProber constructor since the TestTlsProber
-    // instance will be complete before FinishProbe is invoked. In the
-    // production TlsProber, the constructor completes before DNS host
-    // resolution is complete.
-    content::GetUIThreadTaskRunner({})->PostTask(
-        FROM_HERE,
-        base::BindOnce(&TestTlsProber::FinishProbe, weak_factory_.GetWeakPtr(),
-                       std::move(callback), result, probe_exit_enum));
-  }
-
-  TestTlsProber(const TestTlsProber&) = delete;
-  TestTlsProber& operator=(const TestTlsProber&) = delete;
-  ~TestTlsProber() override = default;
-
- private:
-  void FinishProbe(TlsProber::TlsProbeCompleteCallback callback,
-                   int result,
-                   TlsProber::ProbeExitEnum probe_exit_enum) {
-    std::move(callback).Run(result, probe_exit_enum);
-  }
-
-  base::WeakPtrFactory<TestTlsProber> weak_factory_{this};
-};
-
-}  // namespace
-
-class VideoConferencingRoutineTest : public ::testing::Test {
- public:
-  struct UdpProberReturnValue {
-    net::Error result;
-    UdpProber::ProbeExitEnum probe_exit_enum;
-  };
-  struct TlsProberReturnValue {
-    net::Error result;
-    TlsProber::ProbeExitEnum probe_exit_enum;
-  };
-
-  VideoConferencingRoutineTest() = default;
-  VideoConferencingRoutineTest(const VideoConferencingRoutineTest&) = delete;
-  VideoConferencingRoutineTest& operator=(const VideoConferencingRoutineTest&) =
-      delete;
-  ~VideoConferencingRoutineTest() override = default;
-
-  void CompareVerdict(
-      mojom::RoutineVerdict expected_verdict,
-      const std::vector<mojom::VideoConferencingProblem>& expected_problems,
-      const base::Optional<std::string>& expected_support_details,
-      mojom::RoutineVerdict actual_verdict,
-      const std::vector<mojom::VideoConferencingProblem>& actual_problems,
-      const base::Optional<std::string>& actual_support_details) {
-    EXPECT_EQ(expected_verdict, actual_verdict);
-    EXPECT_EQ(expected_problems, actual_problems);
-    EXPECT_EQ(expected_support_details.has_value(),
-              actual_support_details.has_value());
-    if (expected_support_details.has_value() &&
-        actual_support_details.has_value()) {
-      EXPECT_EQ(expected_support_details.has_value(),
-                actual_support_details.has_value());
-    }
-    run_loop_.Quit();
-  }
-
-  std::unique_ptr<UdpProber> CreateAndExecuteUdpProber(
-      UdpProber::NetworkContextGetter network_context_getter,
-      net::HostPortPair host_port_pair,
-      base::span<const uint8_t> data,
-      net::NetworkTrafficAnnotationTag tag,
-      base::TimeDelta timeout_after_host_resolution,
-      UdpProber::UdpProbeCompleteCallback callback) {
-    DCHECK(fake_udp_probe_results_.size() > 0);
-
-    auto value = fake_udp_probe_results_.front();
-    fake_udp_probe_results_.pop_front();
-    auto test_udp_prober = std::make_unique<TestUdpProber>(
-        std::move(callback), value.result, value.probe_exit_enum);
-    return std::move(test_udp_prober);
-  }
-
-  std::unique_ptr<TlsProber> CreateAndExecuteTlsProber(
-      TlsProber::NetworkContextGetter network_context_getter,
-      net::HostPortPair host_port_pair,
-      bool negotiate_tls,
-      TlsProber::TlsProbeCompleteCallback callback) {
-    DCHECK(fake_tls_probe_results_.size() > 0);
-
-    auto value = fake_tls_probe_results_.front();
-    fake_tls_probe_results_.pop_front();
-    auto test_tls_prober = std::make_unique<TestTlsProber>(
-        std::move(callback), value.result, value.probe_exit_enum);
-    return std::move(test_tls_prober);
-  }
-
- protected:
-  void RunRoutine(
-      mojom::RoutineVerdict expected_routine_verdict,
-      const std::vector<mojom::VideoConferencingProblem>& expected_problems,
-      const base::Optional<std::string>& expected_support_details) {
-    video_conferencing_routine_->RunRoutine(base::BindOnce(
-        &VideoConferencingRoutineTest::CompareVerdict, weak_ptr(),
-        expected_routine_verdict, expected_problems, expected_support_details));
-    run_loop_.Run();
-  }
-
-  void SetUpRoutine(std::deque<UdpProberReturnValue> fake_udp_probe_results,
-                    std::deque<TlsProberReturnValue> fake_tls_probe_results) {
-    fake_udp_probe_results_ = std::move(fake_udp_probe_results);
-    fake_tls_probe_results_ = std::move(fake_tls_probe_results);
-    video_conferencing_routine_ = std::make_unique<VideoConferencingRoutine>();
-    video_conferencing_routine_->set_udp_prober_getter_callback_for_testing(
-        base::BindRepeating(
-            &VideoConferencingRoutineTest::CreateAndExecuteUdpProber,
-            base::Unretained(this)));
-    video_conferencing_routine_->set_tls_prober_getter_callback_for_testing(
-        base::BindRepeating(
-            &VideoConferencingRoutineTest::CreateAndExecuteTlsProber,
-            base::Unretained(this)));
-  }
-
-  // Sets up required properties (via fakes) and runs the test.
-  //
-  // Parameters:
-  // |fake_udp_probe_results|: Represents the results of UDP probes.
-  // |fake_tls_probe_results|: Represents the results of TCP and TLS probes.
-  // |expected_routine_verdict|: Represents the expected verdict
-  // reported by this test.
-  // |expected_problems|: Represents the expected problem
-  // reported by this test.
-  void SetUpAndRunRoutine(
-      std::deque<UdpProberReturnValue> fake_udp_probe_results,
-      std::deque<TlsProberReturnValue> fake_tls_probe_results,
-      mojom::RoutineVerdict expected_routine_verdict,
-      const std::vector<mojom::VideoConferencingProblem>& expected_problems,
-      const base::Optional<std::string>& expected_support_details) {
-    SetUpRoutine(std::move(fake_udp_probe_results),
-                 std::move(fake_tls_probe_results));
-    RunRoutine(expected_routine_verdict, expected_problems,
-               expected_support_details);
-  }
-
-  base::WeakPtr<VideoConferencingRoutineTest> weak_ptr() {
-    return weak_factory_.GetWeakPtr();
-  }
-
- private:
-  content::BrowserTaskEnvironment task_environment_;
-  base::RunLoop run_loop_;
-  std::deque<UdpProberReturnValue> fake_udp_probe_results_;
-  std::deque<TlsProberReturnValue> fake_tls_probe_results_;
-  std::unique_ptr<VideoConferencingRoutine> video_conferencing_routine_;
-  base::WeakPtrFactory<VideoConferencingRoutineTest> weak_factory_{this};
-};
-
-// Tests the scenario where:
-// (1) An open port to the STUN server is found via UDP and TCP.
-// (2) All media hostnames are reachable.
-TEST_F(VideoConferencingRoutineTest, TestSuccessfulPath) {
-  // Results corresponding to UDP requests to the STUN server.
-  int num_udp_ports_tested = util::GetUdpPortsForGoogleStunServer().size();
-  std::deque<UdpProberReturnValue> fake_udp_probe_results;
-  for (int i = 0; i < num_udp_ports_tested; i++) {
-    if (i < num_udp_ports_tested - 1) {
-      fake_udp_probe_results.push_back(UdpProberReturnValue{
-          net::ERR_FAILED, UdpProber::ProbeExitEnum::kNoDataReceivedFailure});
-      continue;
-    }
-    fake_udp_probe_results.push_back(
-        UdpProberReturnValue{net::OK, UdpProber::ProbeExitEnum::kSuccess});
-  }
-
-  // Tracks the results corresponding to TCP requests to the STUN server and
-  // TLS requests to media hostnames.
-  std::deque<TlsProberReturnValue> fake_tls_probe_results;
-
-  // Results corresponding to the STUN server via TCP.
-  int num_tcp_ports_tested = util::GetTcpPortsForGoogleStunServer().size();
-  for (int i = 0; i < num_tcp_ports_tested; i++) {
-    if (i < num_tcp_ports_tested - 1) {
-      fake_tls_probe_results.push_back(TlsProberReturnValue{
-          net::ERR_FAILED, TlsProber::ProbeExitEnum::kTcpConnectionFailure});
-      continue;
-    }
-    fake_tls_probe_results.push_back(
-        TlsProberReturnValue{net::OK, TlsProber::ProbeExitEnum::kSuccess});
-  }
-
-  // Results corresponding to the TLS requests to media hostnames.
-  int num_media_hostnames_tested = util::GetDefaultMediaUrls().size();
-  for (int i = 0; i < num_media_hostnames_tested; i++) {
-    fake_tls_probe_results.push_back(
-        TlsProberReturnValue{net::OK, TlsProber::ProbeExitEnum::kSuccess});
-  }
-
-  SetUpAndRunRoutine(
-      std::move(fake_udp_probe_results), std::move(fake_tls_probe_results),
-      mojom::RoutineVerdict::kNoProblem,
-      /*expected_problems=*/{}, /*expected_support_problems=*/base::nullopt);
-}
-
-// Tests the scenario where:
-// (1) No open port to the STUN server is found via UDP.
-TEST_F(VideoConferencingRoutineTest, TestUdpFailure) {
-  // Results corresponding to UDP requests to the STUN server.
-  int num_udp_ports_tested = util::GetUdpPortsForGoogleStunServer().size();
-  std::deque<UdpProberReturnValue> fake_udp_probe_results;
-  for (int i = 0; i < num_udp_ports_tested; i++) {
-    fake_udp_probe_results.push_back(UdpProberReturnValue{
-        net::ERR_FAILED, UdpProber::ProbeExitEnum::kNoDataReceivedFailure});
-  }
-
-  // Tracks the results corresponding to TCP requests to the STUN server and
-  // TLS requests to media hostnames.
-  std::deque<TlsProberReturnValue> fake_tls_probe_results;
-
-  // Results corresponding to the STUN server via TCP.
-  int num_tcp_ports_tested = util::GetTcpPortsForGoogleStunServer().size();
-  for (int i = 0; i < num_tcp_ports_tested; i++) {
-    if (i < num_tcp_ports_tested - 1) {
-      fake_tls_probe_results.push_back(TlsProberReturnValue{
-          net::ERR_FAILED, TlsProber::ProbeExitEnum::kTcpConnectionFailure});
-      continue;
-    }
-    fake_tls_probe_results.push_back(
-        TlsProberReturnValue{net::OK, TlsProber::ProbeExitEnum::kSuccess});
-  }
-
-  // Results corresponding to the TLS requests to media hostnames.
-  int num_media_hostnames_tested = util::GetDefaultMediaUrls().size();
-  for (int i = 0; i < num_media_hostnames_tested; i++) {
-    fake_tls_probe_results.push_back(
-        TlsProberReturnValue{net::OK, TlsProber::ProbeExitEnum::kSuccess});
-  }
-
-  SetUpAndRunRoutine(
-      std::move(fake_udp_probe_results), std::move(fake_tls_probe_results),
-      mojom::RoutineVerdict::kProblem,
-      {mojom::VideoConferencingProblem::kUdpFailure}, kSupportDetails);
-}
-
-// Tests the scenario where:
-// (1) No open port to the STUN server is found via TCP.
-TEST_F(VideoConferencingRoutineTest, TestTcpFailure) {
-  // Results corresponding to UDP requests to the STUN server.
-  int num_udp_ports_tested = util::GetUdpPortsForGoogleStunServer().size();
-  std::deque<UdpProberReturnValue> fake_udp_probe_results;
-  for (int i = 0; i < num_udp_ports_tested; i++) {
-    if (i < num_udp_ports_tested - 1) {
-      fake_udp_probe_results.push_back(UdpProberReturnValue{
-          net::ERR_FAILED, UdpProber::ProbeExitEnum::kNoDataReceivedFailure});
-      continue;
-    }
-    fake_udp_probe_results.push_back(
-        UdpProberReturnValue{net::OK, UdpProber::ProbeExitEnum::kSuccess});
-  }
-
-  // Tracks the results corresponding to TCP requests to the STUN server and
-  // TLS requests to media hostnames.
-  std::deque<TlsProberReturnValue> fake_tls_probe_results;
-
-  // Results corresponding to the STUN server via TCP.
-  int num_tcp_ports_tested = util::GetTcpPortsForGoogleStunServer().size();
-  for (int i = 0; i < num_tcp_ports_tested; i++) {
-    fake_tls_probe_results.push_back(TlsProberReturnValue{
-        net::ERR_FAILED, TlsProber::ProbeExitEnum::kTcpConnectionFailure});
-  }
-
-  // Results corresponding to the TLS requests to media hostnames.
-  int num_media_hostnames_tested = util::GetDefaultMediaUrls().size();
-  for (int i = 0; i < num_media_hostnames_tested; i++) {
-    fake_tls_probe_results.push_back(
-        TlsProberReturnValue{net::OK, TlsProber::ProbeExitEnum::kSuccess});
-  }
-
-  SetUpAndRunRoutine(
-      std::move(fake_udp_probe_results), std::move(fake_tls_probe_results),
-      mojom::RoutineVerdict::kProblem,
-      {mojom::VideoConferencingProblem::kTcpFailure}, kSupportDetails);
-}
-
-// Tests the scenario where:
-// (1) Requests to one or more media hostnames failed.
-TEST_F(VideoConferencingRoutineTest, TestMediaFailure) {
-  // Results corresponding to UDP requests to the STUN server.
-  int num_udp_ports_tested = util::GetUdpPortsForGoogleStunServer().size();
-  std::deque<UdpProberReturnValue> fake_udp_probe_results;
-  for (int i = 0; i < num_udp_ports_tested; i++) {
-    if (i < num_udp_ports_tested - 1) {
-      fake_udp_probe_results.push_back(UdpProberReturnValue{
-          net::ERR_FAILED, UdpProber::ProbeExitEnum::kNoDataReceivedFailure});
-      continue;
-    }
-    fake_udp_probe_results.push_back(
-        UdpProberReturnValue{net::OK, UdpProber::ProbeExitEnum::kSuccess});
-  }
-
-  // Tracks the results corresponding to TCP requests to the STUN server and
-  // TLS requests to media hostnames.
-  std::deque<TlsProberReturnValue> fake_tls_probe_results;
-
-  // Results corresponding to the STUN server via TCP.
-  int num_tcp_ports_tested = util::GetTcpPortsForGoogleStunServer().size();
-  for (int i = 0; i < num_tcp_ports_tested; i++) {
-    if (i < num_tcp_ports_tested - 1) {
-      fake_tls_probe_results.push_back(TlsProberReturnValue{
-          net::ERR_FAILED, TlsProber::ProbeExitEnum::kTcpConnectionFailure});
-      continue;
-    }
-    fake_tls_probe_results.push_back(
-        TlsProberReturnValue{net::OK, TlsProber::ProbeExitEnum::kSuccess});
-  }
-
-  // Results corresponding to the TLS requests to media hostnames.
-  fake_tls_probe_results.push_back(TlsProberReturnValue{
-      net::ERR_FAILED, TlsProber::ProbeExitEnum::kTlsUpgradeFailure});
-
-  SetUpAndRunRoutine(
-      std::move(fake_udp_probe_results), std::move(fake_tls_probe_results),
-      mojom::RoutineVerdict::kProblem,
-      {mojom::VideoConferencingProblem::kMediaFailure}, kSupportDetails);
-}
-
-// Tests the scenario where:
-// (1) No open port to the STUN server is found via UDP.
-// (2) No open port to the STUN server is found via TCP.
-TEST_F(VideoConferencingRoutineTest, TestUdpAndTcpFailure) {
-  // Results corresponding to UDP requests to the STUN server.
-  int num_udp_ports_tested = util::GetUdpPortsForGoogleStunServer().size();
-  std::deque<UdpProberReturnValue> fake_udp_probe_results;
-  for (int i = 0; i < num_udp_ports_tested; i++) {
-    fake_udp_probe_results.push_back(UdpProberReturnValue{
-        net::ERR_FAILED, UdpProber::ProbeExitEnum::kNoDataReceivedFailure});
-  }
-
-  // Tracks the results corresponding to TCP requests to the STUN server and
-  // TLS requests to media hostnames.
-  std::deque<TlsProberReturnValue> fake_tls_probe_results;
-
-  // Results corresponding to the STUN server via TCP.
-  int num_tcp_ports_tested = util::GetTcpPortsForGoogleStunServer().size();
-  for (int i = 0; i < num_tcp_ports_tested; i++) {
-    fake_tls_probe_results.push_back(TlsProberReturnValue{
-        net::ERR_FAILED, TlsProber::ProbeExitEnum::kTcpConnectionFailure});
-  }
-
-  // Results corresponding to the TLS requests to media hostnames.
-  int num_media_hostnames_tested = util::GetDefaultMediaUrls().size();
-  for (int i = 0; i < num_media_hostnames_tested; i++) {
-    fake_tls_probe_results.push_back(
-        TlsProberReturnValue{net::OK, TlsProber::ProbeExitEnum::kSuccess});
-  }
-
-  SetUpAndRunRoutine(std::move(fake_udp_probe_results),
-                     std::move(fake_tls_probe_results),
-                     mojom::RoutineVerdict::kProblem,
-                     {mojom::VideoConferencingProblem::kUdpFailure,
-                      mojom::VideoConferencingProblem::kTcpFailure},
-                     kSupportDetails);
-}
-
-// Tests the scenario where:
-// (1) No open port to the STUN server is found via UDP.
-// (2) Requests to one or more media hostnames failed.
-TEST_F(VideoConferencingRoutineTest, TestUdpAndMediaFailure) {
-  // Results corresponding to UDP requests to the STUN server.
-  int num_udp_ports_tested = util::GetUdpPortsForGoogleStunServer().size();
-  std::deque<UdpProberReturnValue> fake_udp_probe_results;
-  for (int i = 0; i < num_udp_ports_tested; i++) {
-    fake_udp_probe_results.push_back(UdpProberReturnValue{
-        net::ERR_FAILED, UdpProber::ProbeExitEnum::kNoDataReceivedFailure});
-  }
-
-  // Tracks the results corresponding to TCP requests to the STUN server and
-  // TLS requests to media hostnames.
-  std::deque<TlsProberReturnValue> fake_tls_probe_results;
-
-  // Results corresponding to the STUN server via TCP.
-  int num_tcp_ports_tested = util::GetTcpPortsForGoogleStunServer().size();
-  for (int i = 0; i < num_tcp_ports_tested; i++) {
-    if (i < num_tcp_ports_tested - 1) {
-      fake_tls_probe_results.push_back(TlsProberReturnValue{
-          net::ERR_FAILED, TlsProber::ProbeExitEnum::kTcpConnectionFailure});
-      continue;
-    }
-    fake_tls_probe_results.push_back(
-        TlsProberReturnValue{net::OK, TlsProber::ProbeExitEnum::kSuccess});
-  }
-
-  // Results corresponding to the TLS requests to media hostnames.
-  fake_tls_probe_results.push_back(TlsProberReturnValue{
-      net::ERR_FAILED, TlsProber::ProbeExitEnum::kTlsUpgradeFailure});
-
-  SetUpAndRunRoutine(std::move(fake_udp_probe_results),
-                     std::move(fake_tls_probe_results),
-                     mojom::RoutineVerdict::kProblem,
-                     {mojom::VideoConferencingProblem::kUdpFailure,
-                      mojom::VideoConferencingProblem::kMediaFailure},
-                     kSupportDetails);
-}
-
-// Tests the scenario where:
-// (1) No open port to the STUN server is found via TCP.
-// (2) Requests to one or more media hostnames failed.
-TEST_F(VideoConferencingRoutineTest, TestTcpAndMediaFailure) {
-  // Results corresponding to UDP requests to the STUN server.
-  int num_udp_ports_tested = util::GetUdpPortsForGoogleStunServer().size();
-  std::deque<UdpProberReturnValue> fake_udp_probe_results;
-  for (int i = 0; i < num_udp_ports_tested; i++) {
-    if (i < num_udp_ports_tested - 1) {
-      fake_udp_probe_results.push_back(UdpProberReturnValue{
-          net::ERR_FAILED, UdpProber::ProbeExitEnum::kNoDataReceivedFailure});
-      continue;
-    }
-    fake_udp_probe_results.push_back(
-        UdpProberReturnValue{net::OK, UdpProber::ProbeExitEnum::kSuccess});
-  }
-
-  // Tracks the results corresponding to TCP requests to the STUN server and
-  // TLS requests to media hostnames.
-  std::deque<TlsProberReturnValue> fake_tls_probe_results;
-
-  // Results corresponding to the STUN server via TCP.
-  int num_tcp_ports_tested = util::GetTcpPortsForGoogleStunServer().size();
-  for (int i = 0; i < num_tcp_ports_tested; i++) {
-    fake_tls_probe_results.push_back(TlsProberReturnValue{
-        net::ERR_FAILED, TlsProber::ProbeExitEnum::kTcpConnectionFailure});
-  }
-
-  // Results corresponding to the TLS requests to media hostnames.
-  fake_tls_probe_results.push_back(TlsProberReturnValue{
-      net::ERR_FAILED, TlsProber::ProbeExitEnum::kTlsUpgradeFailure});
-
-  SetUpAndRunRoutine(std::move(fake_udp_probe_results),
-                     std::move(fake_tls_probe_results),
-                     mojom::RoutineVerdict::kProblem,
-                     {mojom::VideoConferencingProblem::kTcpFailure,
-                      mojom::VideoConferencingProblem::kMediaFailure},
-                     kSupportDetails);
-}
-
-// Tests the scenario where:
-// (1) No open port to the STUN server is found via UDP.
-// (2) No open port to the STUN server is found via TCP.
-// (3) Requests to one or more media hostnames failed.
-TEST_F(VideoConferencingRoutineTest, TestTcpAndUdpAndMediaFailure) {
-  // Results corresponding to UDP requests to the STUN server.
-  int num_udp_ports_tested = util::GetUdpPortsForGoogleStunServer().size();
-  std::deque<UdpProberReturnValue> fake_udp_probe_results;
-  for (int i = 0; i < num_udp_ports_tested; i++) {
-    fake_udp_probe_results.push_back(UdpProberReturnValue{
-        net::ERR_FAILED, UdpProber::ProbeExitEnum::kNoDataReceivedFailure});
-  }
-
-  // Tracks the results corresponding to TCP requests to the STUN server and
-  // TLS requests to media hostnames.
-  std::deque<TlsProberReturnValue> fake_tls_probe_results;
-
-  // Results corresponding to the STUN server via TCP.
-  int num_tcp_ports_tested = util::GetTcpPortsForGoogleStunServer().size();
-  for (int i = 0; i < num_tcp_ports_tested; i++) {
-    fake_tls_probe_results.push_back(TlsProberReturnValue{
-        net::ERR_FAILED, TlsProber::ProbeExitEnum::kTcpConnectionFailure});
-  }
-
-  // Results corresponding to the TLS requests to media hostnames.
-  fake_tls_probe_results.push_back(TlsProberReturnValue{
-      net::ERR_FAILED, TlsProber::ProbeExitEnum::kTlsUpgradeFailure});
-
-  SetUpAndRunRoutine(std::move(fake_udp_probe_results),
-                     std::move(fake_tls_probe_results),
-                     mojom::RoutineVerdict::kProblem,
-                     {mojom::VideoConferencingProblem::kUdpFailure,
-                      mojom::VideoConferencingProblem::kTcpFailure,
-                      mojom::VideoConferencingProblem::kMediaFailure},
-                     kSupportDetails);
-}
-
-}  // namespace network_diagnostics
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/policy/status_collector/app_info_generator.cc b/chrome/browser/chromeos/policy/status_collector/app_info_generator.cc
index 9986949..e35d2e7 100644
--- a/chrome/browser/chromeos/policy/status_collector/app_info_generator.cc
+++ b/chrome/browser/chromeos/policy/status_collector/app_info_generator.cc
@@ -23,6 +23,7 @@
   switch (readiness) {
     case apps::mojom::Readiness::kReady:
       return em::AppInfo::Status::AppInfo_Status_STATUS_INSTALLED;
+    case apps::mojom::Readiness::kRemoved:
     case apps::mojom::Readiness::kUninstalledByUser:
       return em::AppInfo::Status::AppInfo_Status_STATUS_UNINSTALLED;
     case apps::mojom::Readiness::kDisabledByBlocklist:
diff --git a/chrome/browser/chromeos/scanning/scan_service.cc b/chrome/browser/chromeos/scanning/scan_service.cc
index 176f532..c44eba6 100644
--- a/chrome/browser/chromeos/scanning/scan_service.cc
+++ b/chrome/browser/chromeos/scanning/scan_service.cc
@@ -376,6 +376,10 @@
 }
 
 void ScanService::OnCancelCompleted(bool success) {
+  if (success) {
+    save_failed_ = false;
+    last_scanned_file_path_.clear();
+  }
   scan_job_observer_->OnCancelComplete(success);
 }
 
diff --git a/chrome/browser/chromeos/scanning/scan_service_unittest.cc b/chrome/browser/chromeos/scanning/scan_service_unittest.cc
index 8393337..ce347a9 100644
--- a/chrome/browser/chromeos/scanning/scan_service_unittest.cc
+++ b/chrome/browser/chromeos/scanning/scan_service_unittest.cc
@@ -95,6 +95,15 @@
   return std::string(bytes.begin(), bytes.end());
 }
 
+// Returns scan settings with the given path and file type.
+mojo_ipc::ScanSettings CreateScanSettings(const base::FilePath& scan_to_path,
+                                          const mojo_ipc::FileType& file_type) {
+  mojo_ipc::ScanSettings settings;
+  settings.scan_to_path = scan_to_path;
+  settings.file_type = file_type;
+  return settings;
+}
+
 }  // namespace
 
 class FakeScanJobObserver : public mojo_ipc::ScanJobObserver {
@@ -187,10 +196,10 @@
     return caps;
   }
 
-  // Performs a scan with the scanner identified by |scanner_id| with the given
+  // Starts a scan with the scanner identified by |scanner_id| with the given
   // |settings| by calling ScanService::StartScan() via the mojo::Remote.
-  bool Scan(const base::UnguessableToken& scanner_id,
-            mojo_ipc::ScanSettingsPtr settings) {
+  bool StartScan(const base::UnguessableToken& scanner_id,
+                 mojo_ipc::ScanSettingsPtr settings) {
     bool success;
     mojo_ipc::ScanServiceAsyncWaiter(scan_service_remote_.get())
         .StartScan(scanner_id, std::move(settings),
@@ -294,8 +303,8 @@
 // Test that attempting to scan with a scanner ID that doesn't correspond to a
 // scanner results in a failed scan.
 TEST_F(ScanServiceTest, ScanWithBadScannerId) {
-  EXPECT_FALSE(
-      Scan(base::UnguessableToken::Create(), mojo_ipc::ScanSettings::New()));
+  EXPECT_FALSE(StartScan(base::UnguessableToken::Create(),
+                         mojo_ipc::ScanSettings::New()));
 }
 
 // Test that attempting to scan with an unsupported file path fails.
@@ -311,10 +320,9 @@
 
   const base::FilePath my_files_path(kMyFilesPath);
   scan_service_.SetMyFilesPathForTesting(my_files_path);
-  mojo_ipc::ScanSettings settings;
-  settings.scan_to_path = my_files_path.Append("../../../var/log");
-  settings.file_type = mojo_ipc::FileType::kPng;
-  EXPECT_FALSE(Scan(scanners[0]->id, settings.Clone()));
+  const mojo_ipc::ScanSettings settings = CreateScanSettings(
+      my_files_path.Append("../../../var/log"), mojo_ipc::FileType::kPng);
+  EXPECT_FALSE(StartScan(scanners[0]->id, settings.Clone()));
 }
 
 // Test that a scan can be performed successfully.
@@ -332,8 +340,8 @@
   base::Time::Now().LocalExplode(&scan_time);
 
   scan_service_.SetMyFilesPathForTesting(temp_dir_.GetPath());
-  mojo_ipc::ScanSettings settings;
-  settings.scan_to_path = temp_dir_.GetPath();
+  mojo_ipc::ScanSettings settings =
+      CreateScanSettings(temp_dir_.GetPath(), mojo_ipc::FileType::kPng);
   std::map<std::string, mojo_ipc::FileType> file_types = {
       {"png", mojo_ipc::FileType::kPng},
       {"jpg", mojo_ipc::FileType::kJpg},
@@ -345,7 +353,7 @@
       EXPECT_FALSE(base::PathExists(saved_scan_path));
 
     settings.file_type = type.second;
-    EXPECT_TRUE(Scan(scanners[0]->id, settings.Clone()));
+    EXPECT_TRUE(StartScan(scanners[0]->id, settings.Clone()));
     for (const auto& saved_scan_path : saved_scan_paths)
       EXPECT_TRUE(base::PathExists(saved_scan_path));
 
@@ -355,6 +363,123 @@
   }
 }
 
+// Test that when a scan fails, the scan job is marked as failed.
+TEST_F(ScanServiceTest, ScanFails) {
+  // Skip setting the scan data in FakeLorgnetteScannerManager so the scan will
+  // fail.
+  fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse(
+      {kFirstTestScannerName});
+  auto scanners = GetScanners();
+  ASSERT_EQ(scanners.size(), 1u);
+
+  scan_service_.SetMyFilesPathForTesting(temp_dir_.GetPath());
+  const mojo_ipc::ScanSettings settings =
+      CreateScanSettings(temp_dir_.GetPath(), mojo_ipc::FileType::kPng);
+
+  EXPECT_TRUE(StartScan(scanners[0]->id, settings.Clone()));
+  EXPECT_FALSE(fake_scan_job_observer_.scan_success());
+  EXPECT_TRUE(fake_scan_job_observer_.last_scanned_file_path().empty());
+}
+
+// Test that when a page fails to save during the scan, the scan job is marked
+// as failed.
+TEST_F(ScanServiceTest, PageSaveFails) {
+  fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse(
+      {kFirstTestScannerName});
+  // Sending an empty string in test data simulates a page saving to fail.
+  const std::vector<std::string> scan_data = {"TestData1", "", "TestData3"};
+  fake_lorgnette_scanner_manager_.SetScanResponse(scan_data);
+  auto scanners = GetScanners();
+  ASSERT_EQ(scanners.size(), 1u);
+
+  scan_service_.SetMyFilesPathForTesting(temp_dir_.GetPath());
+  const mojo_ipc::ScanSettings settings =
+      CreateScanSettings(temp_dir_.GetPath(), mojo_ipc::FileType::kJpg);
+
+  EXPECT_TRUE(StartScan(scanners[0]->id, settings.Clone()));
+  EXPECT_FALSE(fake_scan_job_observer_.scan_success());
+  EXPECT_TRUE(fake_scan_job_observer_.last_scanned_file_path().empty());
+}
+
+// Tests that a new scan job can succeed after the previous scan failed.
+TEST_F(ScanServiceTest, ScanAfterFailedScan) {
+  // Skip setting the scan data in FakeLorgnetteScannerManager so the scan will
+  // fail.
+  fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse(
+      {kFirstTestScannerName});
+  auto scanners = GetScanners();
+  ASSERT_EQ(scanners.size(), 1u);
+
+  scan_service_.SetMyFilesPathForTesting(temp_dir_.GetPath());
+  const mojo_ipc::ScanSettings settings =
+      CreateScanSettings(temp_dir_.GetPath(), mojo_ipc::FileType::kPng);
+
+  EXPECT_TRUE(StartScan(scanners[0]->id, settings.Clone()));
+  EXPECT_FALSE(fake_scan_job_observer_.scan_success());
+  EXPECT_TRUE(fake_scan_job_observer_.last_scanned_file_path().empty());
+
+  // Set scan data so next scan is successful.
+  const std::vector<std::string> scan_data = {"TestData1", "TestData2",
+                                              "TestData3"};
+  fake_lorgnette_scanner_manager_.SetScanResponse(scan_data);
+  base::Time::Exploded scan_time;
+  // Since we're using mock time, this is deterministic.
+  base::Time::Now().LocalExplode(&scan_time);
+
+  const std::vector<base::FilePath> saved_scan_paths = CreateSavedScanPaths(
+      temp_dir_.GetPath(), scan_time, "png", scan_data.size());
+  for (const auto& saved_scan_path : saved_scan_paths)
+    EXPECT_FALSE(base::PathExists(saved_scan_path));
+
+  EXPECT_TRUE(StartScan(scanners[0]->id, settings.Clone()));
+  for (const auto& saved_scan_path : saved_scan_paths)
+    EXPECT_TRUE(base::PathExists(saved_scan_path));
+
+  EXPECT_TRUE(fake_scan_job_observer_.scan_success());
+  EXPECT_EQ(saved_scan_paths.back(),
+            fake_scan_job_observer_.last_scanned_file_path());
+}
+
+// Tests that a failed scan does not retain values from the previous successful
+// scan.
+TEST_F(ScanServiceTest, FailedScanAfterSuccessfulScan) {
+  fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse(
+      {kFirstTestScannerName});
+  const std::vector<std::string> scan_data = {"TestData1", "TestData2",
+                                              "TestData3"};
+  fake_lorgnette_scanner_manager_.SetScanResponse(scan_data);
+  auto scanners = GetScanners();
+  ASSERT_EQ(scanners.size(), 1u);
+
+  base::Time::Exploded scan_time;
+  // Since we're using mock time, this is deterministic.
+  base::Time::Now().LocalExplode(&scan_time);
+
+  scan_service_.SetMyFilesPathForTesting(temp_dir_.GetPath());
+  const mojo_ipc::ScanSettings settings =
+      CreateScanSettings(temp_dir_.GetPath(), mojo_ipc::FileType::kPng);
+  const std::vector<base::FilePath> saved_scan_paths = CreateSavedScanPaths(
+      temp_dir_.GetPath(), scan_time, "png", scan_data.size());
+  for (const auto& saved_scan_path : saved_scan_paths)
+    EXPECT_FALSE(base::PathExists(saved_scan_path));
+
+  EXPECT_TRUE(StartScan(scanners[0]->id, settings.Clone()));
+  for (const auto& saved_scan_path : saved_scan_paths)
+    EXPECT_TRUE(base::PathExists(saved_scan_path));
+
+  EXPECT_TRUE(fake_scan_job_observer_.scan_success());
+  EXPECT_EQ(saved_scan_paths.back(),
+            fake_scan_job_observer_.last_scanned_file_path());
+
+  // Remove the scan data from FakeLorgnetteScannerManager so the scan will
+  // fail.
+  fake_lorgnette_scanner_manager_.SetScanResponse({});
+
+  EXPECT_TRUE(StartScan(scanners[0]->id, settings.Clone()));
+  EXPECT_FALSE(fake_scan_job_observer_.scan_success());
+  EXPECT_TRUE(fake_scan_job_observer_.last_scanned_file_path().empty());
+}
+
 // Test that canceling sends an update to the observer OnCancelComplete().
 TEST_F(ScanServiceTest, CancelScanBeforeScanCompletes) {
   fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse(
@@ -365,10 +490,10 @@
   ASSERT_EQ(scanners.size(), 1u);
 
   scan_service_.SetMyFilesPathForTesting(temp_dir_.GetPath());
-  mojo_ipc::ScanSettings settings;
-  settings.scan_to_path = temp_dir_.GetPath();
+  const mojo_ipc::ScanSettings settings =
+      CreateScanSettings(temp_dir_.GetPath(), mojo_ipc::FileType::kPng);
 
-  Scan(scanners[0]->id, settings.Clone());
+  StartScan(scanners[0]->id, settings.Clone());
   CancelScan();
   EXPECT_TRUE(fake_scan_job_observer_.cancel_scan_success());
 }
diff --git a/chrome/browser/chromeos/secure_channel/nearby_connection_broker_impl.cc b/chrome/browser/chromeos/secure_channel/nearby_connection_broker_impl.cc
index 61615fc..d0bdfe2a 100644
--- a/chrome/browser/chromeos/secure_channel/nearby_connection_broker_impl.cc
+++ b/chrome/browser/chromeos/secure_channel/nearby_connection_broker_impl.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/secure_channel/nearby_connection_broker_impl.h"
 
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/rand_util.h"
 #include "chrome/browser/chromeos/secure_channel/nearby_endpoint_finder.h"
 #include "chromeos/components/multidevice/logging/logging.h"
@@ -196,6 +197,9 @@
   bool success = status == Status::kSuccess;
   std::move(callback).Run(success);
 
+  base::UmaHistogramBoolean(
+      "MultiDevice.SecureChannel.Nearby.SendMessageResult", success);
+
   if (success)
     return;
 
diff --git a/chrome/browser/installable/installable_manager.cc b/chrome/browser/installable/installable_manager.cc
index f57fc63..acc0233 100644
--- a/chrome/browser/installable/installable_manager.cc
+++ b/chrome/browser/installable/installable_manager.cc
@@ -14,8 +14,8 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/browser/installable/installable_metrics.h"
-#include "chrome/browser/ssl/security_state_tab_helper.h"
 #include "components/security_state/core/security_state.h"
+#include "components/webapps/webapps_client.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/manifest_icon_downloader.h"
@@ -280,9 +280,13 @@
   if (IsOriginConsideredSecure(url))
     return true;
 
+  // This can be null in unit tests but should be non-null in production.
+  if (!webapps::WebappsClient::Get())
+    return false;
+
   return security_state::IsSslCertificateValid(
-      SecurityStateTabHelper::FromWebContents(web_contents)
-          ->GetSecurityLevel());
+      webapps::WebappsClient::Get()->GetSecurityLevelForWebContents(
+          web_contents));
 }
 
 // static
diff --git a/chrome/browser/media/router/discovery/dial/safe_dial_device_description_parser_unittest.cc b/chrome/browser/media/router/discovery/dial/safe_dial_device_description_parser_unittest.cc
index 038d99d..97975d7 100644
--- a/chrome/browser/media/router/discovery/dial/safe_dial_device_description_parser_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/safe_dial_device_description_parser_unittest.cc
@@ -90,7 +90,7 @@
     parser.Parse(
         xml, app_url,
         base::BindOnce(
-            [](base::Closure quit_loop,
+            [](base::RepeatingClosure quit_loop,
                ParsedDialDeviceDescription* out_device_description,
                SafeDialDeviceDescriptionParser::ParsingError* out_error,
                const ParsedDialDeviceDescription& device_description,
diff --git a/chrome/browser/navigation_predictor/navigation_predictor.h b/chrome/browser/navigation_predictor/navigation_predictor.h
index 7eac609..bb772c5 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor.h
+++ b/chrome/browser/navigation_predictor/navigation_predictor.h
@@ -114,10 +114,6 @@
 
   // prerender::PrerenderHandle::Observer:
   void OnPrerenderStop(prerender::PrerenderHandle* handle) override;
-  void OnPrerenderStart(prerender::PrerenderHandle* handle) override {}
-  void OnPrerenderStopLoading(prerender::PrerenderHandle* handle) override {}
-  void OnPrerenderDomContentLoaded(
-      prerender::PrerenderHandle* handle) override {}
   void OnPrerenderNetworkBytesChanged(
       prerender::PrerenderHandle* handle) override {}
 
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
index 032e49e..da35f7e 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -767,7 +767,7 @@
     bool write_cancel_frame) {
   ShareTargetInfo* info = GetShareTargetInfo(share_target);
 
-  if (!info || !info->connection() || !info->endpoint_id()) {
+  if (!info || !info->endpoint_id()) {
     NS_LOG(ERROR) << __func__
                   << ": Cancel invoked for unknown share target, returning "
                      "kOutOfOrderApiCall";
@@ -777,20 +777,10 @@
     return;
   }
 
-  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE,
-      base::BindOnce(&NearbySharingServiceImpl::CloseConnection,
-                     weak_ptr_factory_.GetWeakPtr(), share_target),
-      kIncomingCancelDelay);
-
-  info->connection()->SetDisconnectionListener(
-      base::BindOnce(&NearbySharingServiceImpl::UnregisterShareTarget,
-                     weak_ptr_factory_.GetWeakPtr(), share_target));
-
-  if (write_cancel_frame) {
-    WriteCancel(*info->connection());
-  }
-
+  // We immediately inform the user that the transfer has been cancelled because
+  // subsequent disconnections might be interpreted as failure. The
+  // TransferUpdateDecorator will ignore subsequent statuses in favor of this
+  // cancelled status.
   if (info->transfer_update_callback()) {
     info->transfer_update_callback()->OnTransferUpdate(
         share_target, TransferMetadataBuilder()
@@ -798,6 +788,36 @@
                           .build());
   }
 
+  // Before disconnecting, cancel all ongoing payloads.
+  for (int64_t attachment_id : share_target.GetAttachmentIds()) {
+    base::Optional<int64_t> payload_id = GetAttachmentPayloadId(attachment_id);
+    if (payload_id) {
+      nearby_connections_manager_->Cancel(*payload_id);
+    }
+  }
+
+  // If a connection exists, close the connection. Otherwise disconnect from
+  // endpoint id directly. Note: A share attempt can be cancelled by the user
+  // before a connection is fully established, so info->connection() might be
+  // null.
+  if (info->connection()) {
+    info->connection()->SetDisconnectionListener(
+        base::BindOnce(&NearbySharingServiceImpl::UnregisterShareTarget,
+                       weak_ptr_factory_.GetWeakPtr(), share_target));
+
+    base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE,
+        base::BindOnce(&NearbySharingServiceImpl::CloseConnection,
+                       weak_ptr_factory_.GetWeakPtr(), share_target),
+        kIncomingCancelDelay);
+
+    if (write_cancel_frame) {
+      WriteCancel(*info->connection());
+    }
+  } else {
+    nearby_connections_manager_->Disconnect(*info->endpoint_id());
+  }
+
   std::move(status_codes_callback).Run(StatusCodes::kOk);
 }
 
diff --git a/chrome/browser/nearby_sharing/sharesheet/nearby_share_action.cc b/chrome/browser/nearby_sharing/sharesheet/nearby_share_action.cc
index d340629c..fd2996f 100644
--- a/chrome/browser/nearby_sharing/sharesheet/nearby_share_action.cc
+++ b/chrome/browser/nearby_sharing/sharesheet/nearby_share_action.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
 #include "chrome/browser/nearby_sharing/attachment.h"
 #include "chrome/browser/nearby_sharing/file_attachment.h"
+#include "chrome/browser/nearby_sharing/sharesheet/nearby_share_web_view.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/sharesheet/sharesheet_types.h"
 #include "chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.h"
@@ -93,7 +94,7 @@
   controller->SetSharesheetSize(size.width(), size.height());
 
   auto* profile = controller->GetProfile();
-  auto view = std::make_unique<views::WebView>(profile);
+  auto view = std::make_unique<NearbyShareWebView>(profile);
   // If this is not done, we don't see anything in our view.
   view->SetPreferredSize(size);
   views::WebView* web_view = root_view->AddChildView(std::move(view));
diff --git a/chrome/browser/nearby_sharing/sharesheet/nearby_share_web_view.cc b/chrome/browser/nearby_sharing/sharesheet/nearby_share_web_view.cc
new file mode 100644
index 0000000..17291d1
--- /dev/null
+++ b/chrome/browser/nearby_sharing/sharesheet/nearby_share_web_view.cc
@@ -0,0 +1,27 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/nearby_sharing/sharesheet/nearby_share_web_view.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/browser_navigator_params.h"
+#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
+
+NearbyShareWebView::NearbyShareWebView(content::BrowserContext* browser_context)
+    : WebView(browser_context) {}
+
+void NearbyShareWebView::WebContentsCreated(
+    content::WebContents* source_contents,
+    int opener_render_process_id,
+    int opener_render_frame_id,
+    const std::string& frame_name,
+    const GURL& target_url,
+    content::WebContents* new_contents) {
+  chrome::ScopedTabbedBrowserDisplayer displayer(
+      Profile::FromBrowserContext(GetBrowserContext()));
+  NavigateParams nav_params(displayer.browser(), target_url,
+                            ui::PageTransition::PAGE_TRANSITION_LINK);
+  Navigate(&nav_params);
+}
diff --git a/chrome/browser/nearby_sharing/sharesheet/nearby_share_web_view.h b/chrome/browser/nearby_sharing/sharesheet/nearby_share_web_view.h
new file mode 100644
index 0000000..70768cb
--- /dev/null
+++ b/chrome/browser/nearby_sharing/sharesheet/nearby_share_web_view.h
@@ -0,0 +1,32 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NEARBY_SHARING_SHARESHEET_NEARBY_SHARE_WEB_VIEW_H_
+#define CHROME_BROWSER_NEARBY_SHARING_SHARESHEET_NEARBY_SHARE_WEB_VIEW_H_
+
+#include "ui/views/controls/webview/webview.h"
+
+namespace content {
+class BrowserContext;
+class WebContents;
+}  // namespace content
+
+// NearbyShareWebView is used in place of the general views::WebView when
+// creating the UI for the sharesheet action so that we can handle navigation
+// to open a new tab when a link is clicked.
+class NearbyShareWebView : public views::WebView {
+ public:
+  explicit NearbyShareWebView(content::BrowserContext* browser_context);
+  ~NearbyShareWebView() override = default;
+
+  // content::WebContentsDelegate:
+  void WebContentsCreated(content::WebContents* source_contents,
+                          int opener_render_process_id,
+                          int opener_render_frame_id,
+                          const std::string& frame_name,
+                          const GURL& target_url,
+                          content::WebContents* new_contents) override;
+};
+
+#endif  // CHROME_BROWSER_NEARBY_SHARING_SHARESHEET_NEARBY_SHARE_WEB_VIEW_H_
diff --git a/chrome/browser/performance_manager/policies/policy_features.cc b/chrome/browser/performance_manager/policies/policy_features.cc
index fb9ba1d..ba62f68 100644
--- a/chrome/browser/performance_manager/policies/policy_features.cc
+++ b/chrome/browser/performance_manager/policies/policy_features.cc
@@ -125,7 +125,7 @@
 
 const base::Feature kUrgentDiscardingFromPerformanceManager{
   "UrgentDiscardingFromPerformanceManager",
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_LINUX)
       base::FEATURE_DISABLED_BY_DEFAULT
 #else
       base::FEATURE_ENABLED_BY_DEFAULT
diff --git a/chrome/browser/predictors/loading_predictor_browsertest.cc b/chrome/browser/predictors/loading_predictor_browsertest.cc
index a36cb97..c36d940 100644
--- a/chrome/browser/predictors/loading_predictor_browsertest.cc
+++ b/chrome/browser/predictors/loading_predictor_browsertest.cc
@@ -800,10 +800,6 @@
     }
   }
 
-  void OnPrerenderStart(prerender::PrerenderHandle* handle) override {}
-  void OnPrerenderStopLoading(prerender::PrerenderHandle* handle) override {}
-  void OnPrerenderDomContentLoaded(
-      prerender::PrerenderHandle* handle) override {}
   void OnPrerenderNetworkBytesChanged(
       prerender::PrerenderHandle* handle) override {}
 
diff --git a/chrome/browser/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc b/chrome/browser/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc
index fe879203..2290733c 100644
--- a/chrome/browser/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc
+++ b/chrome/browser/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc
@@ -325,31 +325,19 @@
         NavigateWithPrerenders(loader_url, expected_final_status_queue);
     prerenders[0]->WaitForLoads(0);
 
-    // Ensure that the referring page receives the right start and load events.
-    WaitForPrerenderStartEventForLinkNumber(0);
-    if (check_load_events_) {
-      WaitForPrerenderEventCount(0, "webkitprerenderload",
-                                 expected_number_of_loads);
-    }
-
     if (ShouldAbortPrerenderBeforeSwap(expected_final_status_queue.front())) {
       // The prerender will abort on its own. Assert it does so correctly.
       prerenders[0]->WaitForStop();
       EXPECT_FALSE(prerenders[0]->contents());
-      WaitForPrerenderStopEventForLinkNumber(0);
     } else {
       // Otherwise, check that it prerendered correctly.
       test_utils::TestPrerenderContents* prerender_contents =
           prerenders[0]->contents();
       if (prerender_contents) {
         EXPECT_EQ(FINAL_STATUS_UNKNOWN, prerender_contents->final_status());
-        EXPECT_FALSE(DidReceivePrerenderStopEventForLinkNumber(0));
       }
     }
 
-    // Test for proper event ordering.
-    EXPECT_FALSE(HadPrerenderEventErrors());
-
     return std::move(prerenders[0]);
   }
 
@@ -370,8 +358,6 @@
     }
   }
 
-  void DisableLoadEventCheck() { check_load_events_ = false; }
-
   std::unique_ptr<TestPrerender> PrefetchFromFile(
       const std::string& html_file,
       FinalStatus expected_final_status,
@@ -404,68 +390,6 @@
     // BrowsingDataRemover deletes itself.
   }
 
-  // Synchronization note: The IPCs used to communicate DOM events back to the
-  // referring web page (see blink::mojom::PrerenderProcessorClient) may race w/
-  // the IPCs used here to inject script. The WaitFor* variants should be used
-  // when an event was expected to happen or to happen soon.
-
-  int GetPrerenderEventCount(int index, const std::string& type) const {
-    int event_count;
-    std::string expression = base::StringPrintf(
-        "window.domAutomationController.send("
-        "    GetPrerenderEventCount(%d, '%s'))",
-        index, type.c_str());
-
-    CHECK(content::ExecuteScriptAndExtractInt(GetActiveWebContents(),
-                                              expression, &event_count));
-    return event_count;
-  }
-
-  bool DidReceivePrerenderStartEventForLinkNumber(int index) const {
-    return GetPrerenderEventCount(index, "webkitprerenderstart") > 0;
-  }
-
-  int GetPrerenderLoadEventCountForLinkNumber(int index) const {
-    return GetPrerenderEventCount(index, "webkitprerenderload");
-  }
-
-  bool DidReceivePrerenderStopEventForLinkNumber(int index) const {
-    return GetPrerenderEventCount(index, "webkitprerenderstop") > 0;
-  }
-
-  void WaitForPrerenderEventCount(int index,
-                                  const std::string& type,
-                                  int count) const {
-    int dummy;
-    std::string expression = base::StringPrintf(
-        "WaitForPrerenderEventCount(%d, '%s', %d,"
-        "    window.domAutomationController.send.bind("
-        "        window.domAutomationController, 0))",
-        index, type.c_str(), count);
-
-    CHECK(content::ExecuteScriptAndExtractInt(GetActiveWebContents(),
-                                              expression, &dummy));
-    CHECK_EQ(0, dummy);
-  }
-
-  void WaitForPrerenderStartEventForLinkNumber(int index) const {
-    WaitForPrerenderEventCount(index, "webkitprerenderstart", 1);
-  }
-
-  void WaitForPrerenderStopEventForLinkNumber(int index) const {
-    WaitForPrerenderEventCount(index, "webkitprerenderstart", 1);
-  }
-
-  bool HadPrerenderEventErrors() const {
-    bool had_prerender_event_errors;
-    CHECK(content::ExecuteScriptAndExtractBool(
-        GetActiveWebContents(),
-        "window.domAutomationController.send(Boolean("
-        "    hadPrerenderEventErrors))",
-        &had_prerender_event_errors));
-    return had_prerender_event_errors;
-  }
-
   // Opens the prerendered page using javascript functions in the loader
   // page. |javascript_function_name| should be a 0 argument function which is
   // invoked. |new_web_contents| is true if the navigation is expected to
@@ -507,7 +431,6 @@
 #endif
   }
 
-  bool check_load_events_ = true;
   base::SimpleTestTickClock clock_;
 
  private:
@@ -1763,7 +1686,6 @@
 
 // Checks shutdown code while a prerender is active.
 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, PrerenderQuickQuit) {
-  DisableLoadEventCheck();
   GURL url = src_server()->GetURL(kHungPrerenderPage);
   std::unique_ptr<TestPrerender> prerender =
       PrefetchFromURL(url, FINAL_STATUS_APP_TERMINATING);
@@ -1789,12 +1711,6 @@
 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, PrerenderExcessiveMemory) {
   ASSERT_TRUE(GetPrerenderManager());
   GetPrerenderManager()->mutable_config().max_bytes = 100;
-  // The excessive memory kill may happen before or after the load event as it
-  // happens asynchronously with IPC calls. Even if the test does not start
-  // allocating until after load, the browser process might notice before the
-  // message gets through. This happens on XP debug bots because they're so
-  // slow. Instead, don't bother checking the load event count.
-  DisableLoadEventCheck();
   PrefetchFromURL(
       src_server()->GetURL("/prerender/prerender_excessive_memory.html"),
       FINAL_STATUS_MEMORY_LIMIT_EXCEEDED);
diff --git a/chrome/browser/prefetch/no_state_prefetch/prerender_unittest.cc b/chrome/browser/prefetch/no_state_prefetch/prerender_unittest.cc
index 34a93e2..e351843 100644
--- a/chrome/browser/prefetch/no_state_prefetch/prerender_unittest.cc
+++ b/chrome/browser/prefetch/no_state_prefetch/prerender_unittest.cc
@@ -69,19 +69,6 @@
 
 namespace {
 
-class DummyPrerenderProcessorClient
-    : public blink::mojom::PrerenderProcessorClient {
- public:
-  DummyPrerenderProcessorClient() = default;
-  ~DummyPrerenderProcessorClient() override = default;
-
-  // blink::mojom::PrerenderProcessorClient implementation
-  void OnPrerenderStart() override {}
-  void OnPrerenderStopLoading() override {}
-  void OnPrerenderDomContentLoaded() override {}
-  void OnPrerenderStop() override {}
-};
-
 class DummyPrerenderContents : public PrerenderContents {
  public:
   DummyPrerenderContents(UnitTestPrerenderManager* test_prerender_manager,
@@ -116,10 +103,6 @@
   TestNetworkBytesChangedObserver() : network_bytes_changed_(false) {}
 
   // prerender::PrerenderHandle::Observer
-  void OnPrerenderStart(PrerenderHandle* prerender_handle) override {}
-  void OnPrerenderStopLoading(PrerenderHandle* prerender_handle) override {}
-  void OnPrerenderDomContentLoaded(PrerenderHandle* prerender_handle) override {
-  }
   void OnPrerenderStop(PrerenderHandle* prerender_handle) override {}
   void OnPrerenderNetworkBytesChanged(
       PrerenderHandle* prerender_handle) override {
@@ -393,16 +376,11 @@
         initiator_url, network::mojom::ReferrerPolicy::kDefault);
     attributes->view_size = kDefaultViewSize;
 
-    mojo::PendingRemote<blink::mojom::PrerenderProcessorClient>
-        processor_client;
-    clients_.Add(std::make_unique<DummyPrerenderProcessorClient>(),
-                 processor_client.InitWithNewPipeAndPassReceiver());
-
     // This could delete an existing prerender as a side-effect.
     base::Optional<int> prerender_id =
         prerender_link_manager()->OnStartPrerender(
             render_process_id, render_view_id, std::move(attributes),
-            url::Origin::Create(initiator_url), std::move(processor_client));
+            url::Origin::Create(initiator_url));
 
     // Check if the new prerender request was added and running.
     return prerender_id && LastPrerenderIsRunning();
@@ -461,8 +439,6 @@
         chrome_browser_net::NETWORK_PREDICTION_ALWAYS);
   }
 
-  void DisconnectAllPrerenderProcessorClients() { clients_.Clear(); }
-
   const base::HistogramTester& histogram_tester() { return histogram_tester_; }
 
  private:
@@ -474,7 +450,6 @@
   std::unique_ptr<UnitTestPrerenderManager> prerender_manager_;
   std::unique_ptr<PrerenderLinkManager> prerender_link_manager_;
   base::HistogramTester histogram_tester_;
-  mojo::UniqueReceiverSet<blink::mojom::PrerenderProcessorClient> clients_;
 };
 
 TEST_F(PrerenderTest, RespectsThirdPartyCookiesPref) {
diff --git a/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_browsertest.cc b/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_browsertest.cc
index 2265a8e..70a692a 100644
--- a/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_browsertest.cc
+++ b/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_browsertest.cc
@@ -873,10 +873,6 @@
   }
 
   // prerender::PrerenderHandle::Observer:
-  void OnPrerenderStart(prerender::PrerenderHandle* handle) override {}
-  void OnPrerenderStopLoading(prerender::PrerenderHandle* handle) override {}
-  void OnPrerenderDomContentLoaded(
-      prerender::PrerenderHandle* handle) override {}
   void OnPrerenderNetworkBytesChanged(
       prerender::PrerenderHandle* handle) override {}
   void OnPrerenderStop(prerender::PrerenderHandle* handle) override {}
diff --git a/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_subresource_manager.h b/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_subresource_manager.h
index 998ece0..29ced59 100644
--- a/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_subresource_manager.h
+++ b/chrome/browser/prefetch/prefetch_proxy/prefetch_proxy_subresource_manager.h
@@ -95,10 +95,6 @@
   void NotifyProbeFailed();
 
   // prerender::PrerenderHandle::Observer:
-  void OnPrerenderStart(prerender::PrerenderHandle* handle) override {}
-  void OnPrerenderStopLoading(prerender::PrerenderHandle* handle) override {}
-  void OnPrerenderDomContentLoaded(
-      prerender::PrerenderHandle* handle) override {}
   void OnPrerenderStop(prerender::PrerenderHandle* handle) override;
   void OnPrerenderNetworkBytesChanged(
       prerender::PrerenderHandle* handle) override {}
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index b07bc3b..5b01482 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -634,6 +634,10 @@
   return std::move(profile);
 }
 
+bool OffTheRecordProfileImpl::IsSignedIn() {
+  return false;
+}
+
 #if !defined(OS_ANDROID)
 void OffTheRecordProfileImpl::OnParentZoomLevelChanged(
     const HostZoomMap::ZoomLevelChange& change) {
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.h b/chrome/browser/profiles/off_the_record_profile_impl.h
index c297116..4d082f9 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.h
+++ b/chrome/browser/profiles/off_the_record_profile_impl.h
@@ -133,6 +133,10 @@
   GetNativeFileSystemPermissionContext() override;
   void RecordMainFrameNavigation() override;
 
+ protected:
+  // Profile implementation.
+  bool IsSignedIn() override;
+
  private:
 #if !defined(OS_ANDROID)
   // Allows a profile to track changes in zoom levels in its parent profile.
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index f55fb19..e46c975 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -12,7 +12,6 @@
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h"
 #include "chrome/browser/profiles/profile_observer.h"
-#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h"
@@ -21,7 +20,6 @@
 #include "components/media_router/common/pref_names.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
-#include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/sync/driver/sync_driver_switches.h"
 #include "components/variations/variations.mojom.h"
 #include "components/variations/variations_client.h"
@@ -79,34 +77,6 @@
 
 namespace {
 
-class ChromeVariationsClient : public variations::VariationsClient {
- public:
-  explicit ChromeVariationsClient(content::BrowserContext* browser_context)
-      : browser_context_(browser_context) {}
-
-  ~ChromeVariationsClient() override = default;
-
-  bool IsOffTheRecord() const override {
-    return browser_context_->IsOffTheRecord();
-  }
-
-  variations::mojom::VariationsHeadersPtr GetVariationsHeaders()
-      const override {
-    return variations::VariationsIdsProvider::GetInstance()
-        ->GetClientDataHeaders(IsSignedIn());
-  }
-
- private:
-  bool IsSignedIn() const {
-    Profile* profile = Profile::FromBrowserContext(browser_context_);
-    signin::IdentityManager* identity_manager =
-        IdentityManagerFactory::GetForProfile(profile);
-    return identity_manager && identity_manager->HasPrimaryAccount();
-  }
-
-  content::BrowserContext* browser_context_;
-};
-
 const char kDevToolsOTRProfileIDPrefix[] = "Devtools::BrowserContext";
 const char kMediaRouterOTRProfileIDPrefix[] = "MediaRouter::Presentation";
 
@@ -514,6 +484,24 @@
   return HasOffTheRecordProfile(OTRProfileID::PrimaryID());
 }
 
+class Profile::ChromeVariationsClient : public variations::VariationsClient {
+ public:
+  explicit ChromeVariationsClient(Profile* profile) : profile_(profile) {}
+
+  ~ChromeVariationsClient() override = default;
+
+  bool IsOffTheRecord() const override { return profile_->IsOffTheRecord(); }
+
+  variations::mojom::VariationsHeadersPtr GetVariationsHeaders()
+      const override {
+    return variations::VariationsIdsProvider::GetInstance()
+        ->GetClientDataHeaders(profile_->IsSignedIn());
+  }
+
+ private:
+  Profile* profile_;
+};
+
 variations::VariationsClient* Profile::GetVariationsClient() {
   if (!chrome_variations_client_)
     chrome_variations_client_ = std::make_unique<ChromeVariationsClient>(this);
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index 648d716..1b86592a 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -537,6 +537,9 @@
 
   void NotifyOffTheRecordProfileCreated(Profile* off_the_record);
 
+  // Returns whether the user has signed in this profile to an account.
+  virtual bool IsSignedIn() = 0;
+
  private:
   bool restored_last_session_ = false;
 
@@ -557,6 +560,7 @@
 
   base::ObserverList<ProfileObserver> observers_;
 
+  class ChromeVariationsClient;
   std::unique_ptr<variations::VariationsClient> chrome_variations_client_;
 };
 
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 767fc355..49dc59f 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -1534,6 +1534,12 @@
   prefs_->SetTime(prefs::kProfileCreationTime, creation_time);
 }
 
+bool ProfileImpl::IsSignedIn() {
+  signin::IdentityManager* identity_manager =
+      IdentityManagerFactory::GetForProfile(this);
+  return identity_manager && identity_manager->HasPrimaryAccount();
+}
+
 GURL ProfileImpl::GetHomePage() {
   // --homepage overrides any preferences.
   const base::CommandLine& command_line =
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 6ed3d1cc..dbb5a05b 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -176,6 +176,10 @@
   void SetCreationTimeForTesting(base::Time creation_time) override;
   void RecordMainFrameNavigation() override {}
 
+ protected:
+  // Profile implementation.
+  bool IsSignedIn() override;
+
  private:
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   friend class chromeos::KioskTest;
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/mock_tts.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/mock_tts.js
index 55b94b9..2206501 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/mock_tts.js
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/mock_tts.js
@@ -53,6 +53,13 @@
       this.speechCallbackStack_.pop()(utterance);
     }
   },
+  finishPendingUtterance() {
+    this.pendingUtterances_ = [];
+    this.currentlySpeaking_ = false;
+    if (this.options_) {
+      this.options_.onEvent({type: 'end'});
+    }
+  },
   stop() {
     this.pendingUtterances_ = [];
     this.currentlySpeaking_ = false;
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js
index 5d6b2b4..fbca576 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js
@@ -117,6 +117,54 @@
      */
     this.currentNodeWord_ = null;
 
+    /**
+     * There are five navigation state variables: |currentNodes|,
+     * |currentNodeGroupStartNodeIndex|, |currentCharIndex|,
+     * |currentStartCharIndex|, |currentEndCharIndex|. These variables enable
+     * us to separate the functionalities of node enqueuing, navigation
+     * control, and TTS playing.
+     * @private {!{currentNodes:!Array<AutomationNode>,
+     *             currentNodeGroupStartNodeIndex: number,
+     *             currentCharIndex: number,
+     *             currentStartCharIndex: (number|undefined),
+     *             currentEndCharIndex: (number|undefined)}}
+     */
+    this.navigationState_ = {
+      /**
+       * The current enqueued Automation nodes.
+       */
+      currentNodes: [],
+
+      /**
+       * The index indicating which node in |currentNodes| is used as the start
+       * of the current NodeGroup. STS will select a few nodes from
+       * |currentNodes| to form a NodeGroup, which is the basic unit for a
+       * TTS utterance. A NodeGroup could be a paragraph and a block of text.
+       * This number is used to generate a NodeGroup from |currentNodes|.
+       */
+      currentNodeGroupStartNodeIndex: -1,
+
+      /**
+       * The start char index of the word to be spoken. The index is relative
+       * to the NodeGroup.
+       */
+      currentCharIndex: -1,
+
+      /**
+       * The current start offset. The index is relative to the Automation node.
+       * When a user selects text, they could start from the middle of a node.
+       * This variable indicates where the user selection starts from within
+       * the first node of |currentNodes|. If set to undefined, we will use the
+       * entire first node.
+       */
+      currentStartCharIndex: undefined,
+
+      /**
+       * The current end offset - see currentStartCharIndex, above.
+       */
+      currentEndCharIndex: undefined,
+    };
+
     /** @private {?AutomationNode} */
     this.currentBlockParent_ = null;
 
@@ -229,7 +277,7 @@
         // more items are being read.
         return;
       }
-      this.startSpeechQueue_(nodes);
+      this.startSpeechQueue_(nodes, {clearFocusRing: true});
       MetricsUtils.recordStartEvent(
           MetricsUtils.StartSpeechMethod.MOUSE, this.prefsManager_);
     }.bind(this));
@@ -387,10 +435,15 @@
         // The node at the last position was not added to the list, perhaps it
         // was whitespace or invisible. Clear the ending offset because it
         // relates to a node that doesn't exist.
-        this.startSpeechQueue_(nodes, firstPosition.offset);
-      } else {
         this.startSpeechQueue_(
-            nodes, firstPosition.offset, lastPosition.offset);
+            nodes,
+            {clearFocusRing: true, startCharIndex: firstPosition.offset});
+      } else {
+        this.startSpeechQueue_(nodes, {
+          clearFocusRing: true,
+          startCharIndex: firstPosition.offset,
+          endCharIndex: lastPosition.offset
+        });
       }
       this.initializeScrollingToOffscreenNodes_(focusedNode.root);
       MetricsUtils.recordStartEvent(
@@ -506,10 +559,25 @@
   stopAll_() {
     chrome.tts.stop();
     this.clearFocusRing_();
+    this.clearNavigationStateVariables_();
     this.onStateChanged_(SelectToSpeakState.INACTIVE);
   }
 
   /**
+   * Clears the member variables for the navigation state.
+   * @private
+   */
+  clearNavigationStateVariables_() {
+    this.navigationState_ = {
+      currentNodes: [],
+      currentNodeGroupStartNodeIndex: -1,
+      currentCharIndex: -1,
+      currentStartCharIndex: undefined,
+      currentEndCharIndex: undefined,
+    };
+  }
+
+  /**
    * Clears the current focus ring and node, but does
    * not stop the speech.
    * @private
@@ -723,7 +791,7 @@
    * @private
    */
   startSpeech_(text) {
-    this.prepareForSpeech_();
+    this.prepareForSpeech_(true /* clearFocusRing */);
     const options = this.prefsManager_.speechOptions();
     options.onEvent = (event) => {
       if (event.type === 'start') {
@@ -742,131 +810,294 @@
   }
 
   /**
-   * Enqueue speech commands for all of the given nodes.
+   * Enqueue nodes to TTS queue and start TTS. This function can be used for
+   * adding nodes, either from user selection (e.g., mouse selection) or
+   * navigation control (e.g., next paragraph). This function will overwrite
+   * |currentNodes| and start TTS according to the offsets.
    * @param {Array<AutomationNode>} nodes The nodes to speak.
-   * @param {number=} opt_startIndex The index into the first node's text
-   * at which to start speaking. If this is not passed, will start at 0.
-   * @param {number=} opt_endIndex The index into the last node's text
-   * at which to end speech. If this is not passed, will stop at the end.
+   * @param {{clearFocusRing: (boolean|undefined),
+   *          startCharIndex: (number|undefined),
+   *          endCharIndex: (number|undefined)}=} opt_params
+   *    clearFocusRing: Whether to clear the focus ring or not. For example, we
+   * need to clear the focus ring when starting from scratch but we do not need
+   * to clear the focus ring when resuming from a previous pause. If this is not
+   * passed, will default to false.
+   *    startCharIndex: The index into the first node's text at which to start
+   * speaking. If this is not passed, will start at 0.
+   *    endCharIndex: The index into the last node's text at which to end
+   * speech. If this is not passed, will stop at the end.
    * @private
    */
-  startSpeechQueue_(nodes, opt_startIndex, opt_endIndex) {
-    this.prepareForSpeech_();
+  startSpeechQueue_(nodes, opt_params) {
+    const params = opt_params || {};
+    const clearFocusRing = params.clearFocusRing || false;
+    let startCharIndex = params.startCharIndex;
+    let endCharIndex = params.endCharIndex;
+
+    this.prepareForSpeech_(clearFocusRing /* clear the focus ring */);
 
     if (nodes.length === 0) {
       return;
     }
 
     // Remember the original first and last node in the given list, as
-    // opt_startIndex and opt_endIndex pertain to them. If, after SVG
+    // |startCharIndex| and |endCharIndex| pertain to them. If, after SVG
     // resorting, the first or last nodes are re-ordered, do not clip them.
     const originalFirstNode = nodes[0];
     const originalLastNode = nodes[nodes.length - 1];
-
     // Sort any SVG child nodes, if present, by visual reading order.
     NodeUtils.sortSvgNodesByReadingOrder(nodes);
-
     // Override start or end index if original nodes were sorted.
     if (originalFirstNode !== nodes[0]) {
-      opt_startIndex = undefined;
+      startCharIndex = undefined;
     }
     if (originalLastNode !== nodes[nodes.length - 1]) {
-      opt_endIndex = undefined;
+      endCharIndex = undefined;
     }
 
-    for (var i = 0; i < nodes.length; i++) {
-      const nodeGroup = ParagraphUtils.buildNodeGroup(
-          nodes, i, this.enableLanguageDetectionIntegration_);
+    // Update the navigation state variables.
+    this.navigationState_ = {
+      currentNodes: nodes,
+      currentNodeGroupStartNodeIndex: 0,
+      currentCharIndex: 0,
+      currentStartCharIndex: startCharIndex,
+      currentEndCharIndex: endCharIndex,
+    };
 
-      if (i === 0) {
-        // We need to start in the middle of a node. Remove all text before
-        // the start index so that it is not spoken.
-        // Backfill with spaces so that index counting functions don't get
-        // confused.
-        if (opt_startIndex !== undefined && nodeGroup.nodes.length > 0 &&
-            nodeGroup.nodes[0].hasInlineText) {
-          // The first node is inlineText type. Find the start index in
-          // its staticText parent.
-          const startIndexInParent =
-              ParagraphUtils.getStartCharIndexInParent(nodes[0]);
-          opt_startIndex += startIndexInParent;
-          nodeGroup.text = ' '.repeat(opt_startIndex) +
-              nodeGroup.text.substr(opt_startIndex);
+    // Play TTS according to the current state variables.
+    this.startCurrentNodeGroup_();
+  }
+
+  /**
+   * Start TTS according to the five variables in |this.navigationState_|. This
+   * function will first construct a NodeGroup based on |currentNodes| and
+   * |currentNodeGroupStartNodeIndex|. Then, it will clip texts based on
+   * |currentCharIndex|, |currentStartCharIndex|, and |currentEndCharIndex|.
+   * Lastly, it will start TTS using the processed text.
+   * @private
+   */
+  startCurrentNodeGroup_() {
+    const currentNodes = this.navigationState_.currentNodes;
+    const currentNodeGroupStartNodeIndex =
+        this.navigationState_.currentNodeGroupStartNodeIndex;
+    const currentCharIndex = this.navigationState_.currentCharIndex;
+    const currentStartCharIndex = this.navigationState_.currentStartCharIndex;
+    const currentEndCharIndex = this.navigationState_.currentEndCharIndex;
+
+    // Reaches to the end of the current nodes.
+    if (currentNodeGroupStartNodeIndex >= currentNodes.length) {
+      return;
+    }
+    const nodeGroup = ParagraphUtils.buildNodeGroup(
+        currentNodes, currentNodeGroupStartNodeIndex,
+        this.enableLanguageDetectionIntegration_);
+
+    // |currentCharIndex| is the start char index of the word to be spoken in
+    // the nodeGroup text. If the |currentCharIndex| is non-zero, that means we
+    // are resuming from prior TTS. We trim the text regardless which NodeGroup
+    // we are, as a user could possibly pause at any NodeGroup.
+    this.applyOffset(nodeGroup, currentCharIndex, true /* isStartOffset */);
+
+    const isFirstNodeGroup = currentNodeGroupStartNodeIndex === 0;
+    const shouldApplyStartOffset =
+        isFirstNodeGroup && currentStartCharIndex !== undefined;
+    const firstNodeHasInlineText =
+        nodeGroup.nodes.length > 0 && nodeGroup.nodes[0].hasInlineText;
+    if (shouldApplyStartOffset && firstNodeHasInlineText) {
+      // We assume that the start offset will only be applied to the first node
+      // in the first NodeGroup. The |currentStartCharIndex| needs to be
+      // adjusted. The first node of the NodeGroup may not be at the beginning
+      // of the parent of the NodeGroup. (e.g., an inlineText in its staticText
+      // parent). Thus, we need to adjust the start index.
+      const startIndexInNodeParent =
+          ParagraphUtils.getStartCharIndexInParent(currentNodes[0]);
+      const startIndexInNodeGroup = currentStartCharIndex +
+          startIndexInNodeParent + nodeGroup.nodes[0].startChar;
+      this.applyOffset(
+          nodeGroup, startIndexInNodeGroup, true /* isStartOffset */);
+    }
+
+    const isLastNodeGroup = (nodeGroup.endIndex === currentNodes.length - 1);
+    const shouldApplyEndOffset =
+        isLastNodeGroup && currentEndCharIndex !== undefined;
+    const lastNodeHasInlineText = nodeGroup.nodes.length > 0 &&
+        nodeGroup.nodes[nodeGroup.nodes.length - 1].hasInlineText;
+    if (shouldApplyEndOffset && lastNodeHasInlineText) {
+      // We assume that the end offset will only be applied to the last node in
+      // the last NodeGroup. Similarly, |currentEndCharIndex| needs to be
+      // adjusted.
+      const startIndexInNodeParent = ParagraphUtils.getStartCharIndexInParent(
+          currentNodes[nodeGroup.endIndex]);
+      const endIndexInNodeGroup = currentEndCharIndex + startIndexInNodeParent +
+          nodeGroup.nodes[nodeGroup.nodes.length - 1].startChar;
+      this.applyOffset(
+          nodeGroup, endIndexInNodeGroup, false /* isStartOffset */);
+    }
+
+    if (nodeGroup.nodes.length === 0 && !isLastNodeGroup) {
+      // If the current nodeGroup is empty, we start the next nodeGroup after
+      // the current start node index.
+      this.startNodeGroupAfter_(
+          currentNodeGroupStartNodeIndex /* currentNodeGroupEndIndex */);
+    }
+
+    const options = {};
+    // Copy options so we can add lang below
+    Object.assign(options, this.prefsManager_.speechOptions());
+    if (this.enableLanguageDetectionIntegration_ &&
+        nodeGroup.detectedLanguage) {
+      options.lang = nodeGroup.detectedLanguage;
+    }
+
+    const nodeGroupText = nodeGroup.text || '';
+
+    options.onEvent = (event) => {
+      if (event.type === 'start' && nodeGroup.nodes.length > 0) {
+        this.onStateChanged_(SelectToSpeakState.SPEAKING);
+        this.currentBlockParent_ = nodeGroup.blockParent;
+
+        // Update |currentCharIndex|. Find the first non-space char index in
+        // nodeGroup text, or 0 if the text is undefined or the first char is
+        // non-space.
+        this.navigationState_.currentCharIndex = nodeGroupText.search(/\S|$/);
+
+        this.syncCurrentNodeWithCharIndex_(
+            nodeGroup, this.navigationState_.currentCharIndex /* charIndex */);
+        if (this.prefsManager_.wordHighlightingEnabled()) {
+          // At 'start', find the first word and highlight that. Clear the
+          // previous word in the node.
+          this.currentNodeWord_ = null;
+          // If |currentCharIndex| is not 0, that means we have applied a start
+          // offset. Thus, we need to pass startIndexInNodeGroup to
+          // opt_startIndex and overwrite the word boundaries in the original
+          // node.
+          this.updateNodeHighlight_(
+              nodeGroupText, this.navigationState_.currentCharIndex,
+              this.navigationState_.currentCharIndex !== 0 ?
+                  this.navigationState_.currentCharIndex :
+                  undefined);
+        } else {
+          this.testCurrentNode_();
         }
-      }
-      const isFirst = i === 0;
-      // Advance i to the end of this group, to skip all nodes it contains.
-      i = nodeGroup.endIndex;
-      const isLast = (i === nodes.length - 1);
-      if (isLast && opt_endIndex !== undefined && nodeGroup.nodes.length > 0) {
-        // We need to stop in the middle of a node. Remove all text after
-        // the end index so it is not spoken. Backfill with spaces so that
-        // index counting functions don't get confused.
-        // This only applies to inlineText nodes.
-        if (nodeGroup.nodes[nodeGroup.nodes.length - 1].hasInlineText) {
-          const startIndexInParent =
-              ParagraphUtils.getStartCharIndexInParent(nodes[i]);
-          opt_endIndex += startIndexInParent;
-          nodeGroup.text = nodeGroup.text.substr(
-              0,
-              nodeGroup.nodes[nodeGroup.nodes.length - 1].startChar +
-                  opt_endIndex);
-        }
-      }
-      if (nodeGroup.nodes.length === 0 && !isLast) {
-        continue;
-      }
-
-      const options = {};
-      /* Copy options so we can add lang below */
-      Object.assign(options, this.prefsManager_.speechOptions());
-      if (this.enableLanguageDetectionIntegration_ &&
-          nodeGroup.detectedLanguage) {
-        options.lang = nodeGroup.detectedLanguage;
-      }
-
-      options.onEvent = (event) => {
-        if (event.type === 'start' && nodeGroup.nodes.length > 0) {
-          this.onStateChanged_(SelectToSpeakState.SPEAKING);
-          this.currentBlockParent_ = nodeGroup.blockParent;
-          this.currentNodeGroupIndex_ = 0;
-          this.currentNode_ = nodeGroup.nodes[this.currentNodeGroupIndex_];
-          if (this.prefsManager_.wordHighlightingEnabled()) {
-            // At 'start', find the first word and highlight that.
-            // Clear the previous word in the node.
-            this.currentNodeWord_ = null;
-            // If this is the first nodeGroup, pass the opt_startIndex.
-            // If this is the last nodeGroup, pass the opt_endIndex.
-            this.updateNodeHighlight_(
-                nodeGroup.text, event.charIndex,
-                isFirst ? opt_startIndex : undefined,
-                isLast ? opt_endIndex : undefined);
-          } else {
-            this.testCurrentNode_();
-          }
-        } else if (event.type === 'interrupted' || event.type === 'cancelled') {
+      } else if (event.type === 'interrupted' || event.type === 'cancelled') {
+        if (!this.shouldShowNavigationControls_()) {
+          // Auto dismiss when navigation control is not enabled.
           this.onStateChanged_(SelectToSpeakState.INACTIVE);
-        } else if (event.type === 'end') {
-          if (isLast && !this.shouldShowNavigationControls_()) {
-            // Auto dismiss when we're at the end, unless navigation control
-            // is enabled.
-            this.onStateChanged_(SelectToSpeakState.INACTIVE);
-          }
-        } else if (event.type === 'word') {
-          this.onTtsWordEvent_(
-              event, nodeGroup, isLast ? opt_endIndex : undefined);
         }
-      };
-      chrome.tts.speak(nodeGroup.text || '', options);
+      } else if (event.type === 'end') {
+        this.startNodeGroupAfter_(
+            nodeGroup.endIndex /* currentNodeGroupEndIndex */);
+      } else if (event.type === 'word') {
+        this.onTtsWordEvent_(event, nodeGroup);
+      }
+    };
+    chrome.tts.speak(nodeGroupText, options);
+  }
+
+  /**
+   * Start speaking the next node group indicated by the end index.
+   * @param {number} currentNodeGroupEndIndex the index of the last node in the
+   *     current node group. The index is relative to
+   *     |this.navigationState_.currentNodes|.
+   */
+  startNodeGroupAfter_(currentNodeGroupEndIndex) {
+    const isLastNodeGroup =
+        (currentNodeGroupEndIndex ===
+         this.navigationState_.currentNodes.length - 1);
+    if (isLastNodeGroup) {
+      // TODO (leileilei): If the navigation control is enabled, we need to
+      // enqueue the content between the end of the user's selection to the end
+      // of the paragraph. If there are no nodes in the current NodeGroup.
+      // navigate to the next paragraph.
+      if (!this.shouldShowNavigationControls_()) {
+        this.onStateChanged_(SelectToSpeakState.INACTIVE);
+      }
+    }
+
+    // Navigate to the next NodeGroup. Don't change |currentNodes|,
+    // |currentStartCharIndex|, or |currentEndCharIndex|.
+    this.navigationState_.currentCharIndex = 0;
+    this.navigationState_.currentNodeGroupStartNodeIndex =
+        currentNodeGroupEndIndex + 1;
+    // Play TTS.
+    this.startCurrentNodeGroup_();
+  }
+
+  /**
+   * Update |this.currentNode_|, the current speaking or the node to be spoken
+   * in the node group.
+   * @param {ParagraphUtils.NodeGroup} nodeGroup the current nodeGroup.
+   * @param {number} charIndex the start char index of the word to be spoken.
+   *    The index is relative to the entire NodeGroup.
+   * @param {number=} opt_startFromNodeGroupIndex the NodeGroupIndex to start
+   *    with. If undefined, search from 0.
+   * @return {boolean} if the found NodeGroupIndex is different from the
+   *    |opt_startFromNodeGroupIndex|.
+   */
+  syncCurrentNodeWithCharIndex_(
+      nodeGroup, charIndex, opt_startFromNodeGroupIndex) {
+    if (opt_startFromNodeGroupIndex === undefined) {
+      opt_startFromNodeGroupIndex = 0;
+    }
+
+    // There is no speaking word, set the NodeGroupIndex to 0.
+    if (charIndex <= 0) {
+      this.currentNodeGroupIndex_ = 0;
+      this.currentNode_ = nodeGroup.nodes[this.currentNodeGroupIndex_];
+      return this.currentNodeGroupIndex_ === opt_startFromNodeGroupIndex;
+    }
+
+    // Sets the this.currentNodeGroupIndex_ to |opt_startFromNodeGroupIndex|
+    this.currentNodeGroupIndex_ = opt_startFromNodeGroupIndex;
+    this.currentNode_ = nodeGroup.nodes[this.currentNodeGroupIndex_];
+
+    if (this.currentNodeGroupIndex_ + 1 < nodeGroup.nodes.length) {
+      let next = nodeGroup.nodes[this.currentNodeGroupIndex_ + 1];
+      let nodeUpdated = false;
+      // TODO(katie): For something like a date, the start and end
+      // node group nodes can actually be different. Example:
+      // "<span>Tuesday,</span> December 18, 2018".
+
+      // Check if we've reached this next node yet. Since charIndex is the
+      // start char index of the target word, we just need to make sure the
+      // next.startchar is bigger than it.
+      while (next && charIndex >= next.startChar &&
+             this.currentNodeGroupIndex_ + 1 < nodeGroup.nodes.length) {
+        next = this.incrementCurrentNodeAndGetNext_(nodeGroup);
+        nodeUpdated = true;
+      }
+      return nodeUpdated;
+    }
+
+    return false;
+  }
+
+  /**
+   * Apply start or end offset to the text of the |nodeGroup|.
+   * @param {ParagraphUtils.NodeGroup} nodeGroup the input nodeGroup.
+   * @param {number} offset the size of offset.
+   * @param {boolean} isStartOffset whether to apply a startOffset or an
+   *     endOffset.
+   */
+  applyOffset(nodeGroup, offset, isStartOffset) {
+    if (isStartOffset) {
+      // Applying start offset. Remove all text before the start index so that
+      // it is not spoken. Backfill with spaces so that index counting
+      // functions don't get confused.
+      nodeGroup.text = ' '.repeat(offset) + nodeGroup.text.substr(offset);
+    } else {
+      // Remove all text after the end index so it is not spoken.
+      nodeGroup.text = nodeGroup.text.substr(0, offset);
     }
   }
 
   /**
    * Prepares for speech. Call once before chrome.tts.speak is called.
+   * @param {boolean} clearFocusRing Whether to clear the focus ring.
    * @private
    */
-  prepareForSpeech_() {
-    this.cancelIfSpeaking_(true /* clear the focus ring */);
+  prepareForSpeech_(clearFocusRing) {
+    this.cancelIfSpeaking_(clearFocusRing /* clear the focus ring */);
     if (this.intervalRef_ !== undefined) {
       clearInterval(this.intervalRef_);
     }
@@ -881,14 +1112,15 @@
    * @param {!TtsEvent} event The event to use for updates.
    * @param {ParagraphUtils.NodeGroup} nodeGroup The node group for this
    *     utterance.
-   * @param {number=} opt_endIndex The last index for speech, if applicable.
    * @private
    */
-  onTtsWordEvent_(event, nodeGroup, opt_endIndex) {
-    // Not all speech engines include length in the ttsEvent object. If the
-    // engine does have it, it makes word highlighting easier and more
-    // accurate.
+  onTtsWordEvent_(event, nodeGroup) {
+    // Not all speech engines include length in the ttsEvent object. .
     const hasLength = event.length !== undefined && event.length >= 0;
+    // Only update the currentCharIndex if event has a higher charIndex. TTS
+    // sometimes will report an incorrect number at the end of an utterance.
+    this.navigationState_.currentCharIndex =
+        Math.max(event.charIndex, this.navigationState_.currentCharIndex);
     console.debug(nodeGroup.text + ' (index ' + event.charIndex + ')');
     let debug = '-'.repeat(event.charIndex);
     if (hasLength) {
@@ -901,46 +1133,14 @@
     // First determine which node contains the word currently being spoken,
     // and update this.currentNode_, this.currentNodeWord_, and
     // this.currentNodeGroupIndex_ to match.
-    if (this.currentNodeGroupIndex_ + 1 < nodeGroup.nodes.length) {
-      let next = nodeGroup.nodes[this.currentNodeGroupIndex_ + 1];
-      let nodeUpdated = false;
-      // TODO(katie): For something like a date, the start and end
-      // node group nodes can actually be different. Example:
-      // "<span>Tuesday,</span> December 18, 2018".
-      if (hasLength) {
-        while (next && event.charIndex >= next.startChar &&
-               this.currentNodeGroupIndex_ + 1 < nodeGroup.nodes.length) {
-          next = this.incrementCurrentNodeAndGetNext_(nodeGroup);
-          nodeUpdated = true;
-        }
-
-        // Check if we've reached this next node yet using the
-        // character index of the event. Add 1 for the space character
-        // between node names, and another to make it to the start of the
-        // next node name.
-        // TODO: Do not use next.name.length instead use the next-next
-        // startChar
-        while (next &&
-               event.charIndex + event.length + 2 >=
-                   next.startChar + next.node.name.length &&
-               this.currentNodeGroupIndex_ + 1 < nodeGroup.nodes.length) {
-          next = this.incrementCurrentNodeAndGetNext_(nodeGroup);
-          nodeUpdated = true;
-        }
-      } else {
-        while (next && event.charIndex + 2 >= next.startChar &&
-               this.currentNodeGroupIndex_ + 1 < nodeGroup.nodes.length) {
-          next = this.incrementCurrentNodeAndGetNext_(nodeGroup);
-          nodeUpdated = true;
-        }
-      }
-      if (nodeUpdated) {
-        if (!this.prefsManager_.wordHighlightingEnabled()) {
-          // If we are doing a per-word highlight, we will test the
-          // node after figuring out what the currently highlighted
-          // word is. Otherwise, test it now.
-          this.testCurrentNode_();
-        }
+    const nodeUpdated = this.syncCurrentNodeWithCharIndex_(
+        nodeGroup, event.charIndex, this.currentNodeGroupIndex_);
+    if (nodeUpdated) {
+      if (!this.prefsManager_.wordHighlightingEnabled()) {
+        // If we are doing a per-word highlight, we will test the
+        // node after figuring out what the currently highlighted
+        // word is. Otherwise, test it now.
+        this.testCurrentNode_();
       }
     }
 
@@ -953,8 +1153,7 @@
         };
         this.testCurrentNode_();
       } else {
-        this.updateNodeHighlight_(
-            nodeGroup.text, event.charIndex, undefined, opt_endIndex);
+        this.updateNodeHighlight_(nodeGroup.text, event.charIndex);
       }
     } else {
       this.currentNodeWord_ = null;
@@ -1179,14 +1378,10 @@
    * @param {string} text The current text
    * @param {number} charIndex The index of a current event in the text.
    * @param {number=} opt_startIndex The index at which to start the
-   *     highlight.
-   * This takes precedence over the charIndex.
-   * @param {number=} opt_endIndex The index at which to end the highlight.
-   *     This
-   * takes precedence over the next word end.
+   *     highlight. This takes precedence over the charIndex.
    * @private
    */
-  updateNodeHighlight_(text, charIndex, opt_startIndex, opt_endIndex) {
+  updateNodeHighlight_(text, charIndex, opt_startIndex) {
     if (charIndex >= text.length) {
       // No need to do work if we are at the end of the paragraph.
       return;
@@ -1194,6 +1389,9 @@
     // Get the next word based on the event's charIndex.
     const nextWordStart =
         WordUtils.getNextWordStart(text, charIndex, this.currentNode_);
+    // The |WordUtils.getNextWordEnd| will find the correct end based on the
+    // trimmed text, so there is no need to provide additional input like
+    // opt_startIndex.
     const nextWordEnd = WordUtils.getNextWordEnd(
         text, opt_startIndex === undefined ? nextWordStart : opt_startIndex,
         this.currentNode_);
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_keystroke_selection_test.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_keystroke_selection_test.js
index 9e7b772..c3dd794 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_keystroke_selection_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_keystroke_selection_test.js
@@ -179,9 +179,11 @@
                   assertTrue(this.mockTts.currentlySpeaking());
                   this.assertEqualsCollapseWhitespace(
                       this.mockTts.pendingUtterances()[0], 'Selected text');
-                  if (this.mockTts.pendingUtterances().length === 2) {
+
+                  this.mockTts.finishPendingUtterance();
+                  if (this.mockTts.pendingUtterances().length === 1) {
                     this.assertEqualsCollapseWhitespace(
-                        this.mockTts.pendingUtterances()[1], '');
+                        this.mockTts.pendingUtterances()[0], '');
                   }
                 }),
                 false);
@@ -321,11 +323,14 @@
           function() {
             this.triggerReadSelectedText();
             assertTrue(this.mockTts.currentlySpeaking());
-            assertEquals(this.mockTts.pendingUtterances().length, 2);
+            assertEquals(this.mockTts.pendingUtterances().length, 1);
             this.assertEqualsCollapseWhitespace(
                 this.mockTts.pendingUtterances()[0], 'paragraph');
+
+            this.mockTts.finishPendingUtterance();
+            assertEquals(this.mockTts.pendingUtterances().length, 1);
             this.assertEqualsCollapseWhitespace(
-                this.mockTts.pendingUtterances()[1], 'text field');
+                this.mockTts.pendingUtterances()[0], 'text field');
           });
     });
 
@@ -343,11 +348,14 @@
           function() {
             this.triggerReadSelectedText();
             assertTrue(this.mockTts.currentlySpeaking());
-            assertEquals(this.mockTts.pendingUtterances().length, 2);
+            assertEquals(this.mockTts.pendingUtterances().length, 1);
             this.assertEqualsCollapseWhitespace(
                 this.mockTts.pendingUtterances()[0], 'one');
+
+            this.mockTts.finishPendingUtterance();
+            assertEquals(this.mockTts.pendingUtterances().length, 1);
             this.assertEqualsCollapseWhitespace(
-                this.mockTts.pendingUtterances()[1], 'two three');
+                this.mockTts.pendingUtterances()[0], 'two three');
           });
     });
 
@@ -470,9 +478,11 @@
             assertTrue(this.mockTts.pendingUtterances().length > 0);
             this.assertEqualsCollapseWhitespace(
                 this.mockTts.pendingUtterances()[0], 'Some text');
-            if (this.mockTts.pendingUtterances().length > 1) {
+
+            this.mockTts.finishPendingUtterance();
+            if (this.mockTts.pendingUtterances().length > 0) {
               this.assertEqualsCollapseWhitespace(
-                  this.mockTts.pendingUtterances()[1], '');
+                  this.mockTts.pendingUtterances()[0], '');
             }
           });
     });
@@ -542,11 +552,14 @@
       this.runWithLoadedTree(html, function() {
         this.triggerReadSelectedText();
         assertTrue(this.mockTts.currentlySpeaking());
-        assertEquals(this.mockTts.pendingUtterances().length, 2);
+        assertEquals(this.mockTts.pendingUtterances().length, 1);
         this.assertEqualsCollapseWhitespace(
             this.mockTts.pendingUtterances()[0], 'b c');
+
+        this.mockTts.finishPendingUtterance();
+        assertEquals(this.mockTts.pendingUtterances().length, 1);
         this.assertEqualsCollapseWhitespace(
-            this.mockTts.pendingUtterances()[1], 'd e');
+            this.mockTts.pendingUtterances()[0], 'd e');
       });
     });
 
@@ -567,8 +580,10 @@
             assertTrue(this.mockTts.currentlySpeaking());
             this.assertEqualsCollapseWhitespace(
                 this.mockTts.pendingUtterances()[0], 'a b c');
+
+            this.mockTts.finishPendingUtterance();
             this.assertEqualsCollapseWhitespace(
-                this.mockTts.pendingUtterances()[1], 'd e f');
+                this.mockTts.pendingUtterances()[0], 'd e f');
           });
     });
 
@@ -619,12 +634,18 @@
             assertTrue(this.mockTts.currentlySpeaking());
             this.assertEqualsCollapseWhitespace(
                 this.mockTts.pendingUtterances()[0], 'Column 1, Text 1');
+
+            this.mockTts.finishPendingUtterance();
             this.assertEqualsCollapseWhitespace(
-                this.mockTts.pendingUtterances()[1], 'Column 1, Text 2');
+                this.mockTts.pendingUtterances()[0], 'Column 1, Text 2');
+
+            this.mockTts.finishPendingUtterance();
             this.assertEqualsCollapseWhitespace(
-                this.mockTts.pendingUtterances()[2], 'Column 2, Text 1');
+                this.mockTts.pendingUtterances()[0], 'Column 2, Text 1');
+
+            this.mockTts.finishPendingUtterance();
             this.assertEqualsCollapseWhitespace(
-                this.mockTts.pendingUtterances()[3], 'Column 2, Text 2');
+                this.mockTts.pendingUtterances()[0], 'Column 2, Text 2');
           });
     });
 TEST_F(
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_mouse_selection_test.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_mouse_selection_test.js
index 7ef7836..94aaf89 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_mouse_selection_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_mouse_selection_test.js
@@ -83,6 +83,7 @@
                 assertEquals(this.mockTts.pendingUtterances().length, 1);
                 this.assertEqualsCollapseWhitespace(
                     utterance, 'This is some text');
+                this.mockTts.finishPendingUtterance();
               }),
               this.newCallback(function(utterance) {
                 this.assertEqualsCollapseWhitespace(
diff --git a/chrome/browser/resources/extensions/BUILD.gn b/chrome/browser/resources/extensions/BUILD.gn
index 74f5e0dc..ab35681b 100644
--- a/chrome/browser/resources/extensions/BUILD.gn
+++ b/chrome/browser/resources/extensions/BUILD.gn
@@ -302,7 +302,6 @@
     "//ui/webui/resources/cr_elements/cr_toast:cr_toast_manager.m",
     "//ui/webui/resources/js:assert.m",
     "//ui/webui/resources/js:i18n_behavior.m",
-    "//ui/webui/resources/js:load_time_data.m",
   ]
   externs_list = [ "$externs_path/developer_private.js" ]
 }
diff --git a/chrome/browser/resources/extensions/detail_view.html b/chrome/browser/resources/extensions/detail_view.html
index 2313f2f..dbbc9cd5 100644
--- a/chrome/browser/resources/extensions/detail_view.html
+++ b/chrome/browser/resources/extensions/detail_view.html
@@ -125,6 +125,7 @@
           aria-label="$i18n{back}" on-click="onCloseButtonTap_">
       </cr-icon-button>
       <img id="icon" src="[[data.iconUrl]]"
+          aria-label$="[[a11yAssociation(data.name)]]"
           alt$="[[appOrExtension(
               data.type,
               '$i18nPolymer{appIcon}',
diff --git a/chrome/browser/resources/extensions/item.html b/chrome/browser/resources/extensions/item.html
index fb2f6d20..ee4785fc 100644
--- a/chrome/browser/resources/extensions/item.html
+++ b/chrome/browser/resources/extensions/item.html
@@ -168,7 +168,7 @@
   element that's hidden when referenced by an aria label.  Unfortunately,
   this text can be found by Ctrl + F because it isn't hidden. -->
 <div id="a11yAssociation" aria-hidden="true">
-  [[a11yAssociation_(data.name)]]
+  [[a11yAssociation(data.name)]]
 </div>
 <div id="card" class$="[[computeClasses_(data.state, inDevMode)]]">
   <div id="main">
diff --git a/chrome/browser/resources/extensions/item.js b/chrome/browser/resources/extensions/item.js
index e5e8c74..1bf7fd1 100644
--- a/chrome/browser/resources/extensions/item.js
+++ b/chrome/browser/resources/extensions/item.js
@@ -23,7 +23,6 @@
 import {getToastManager} from 'chrome://resources/cr_elements/cr_toast/cr_toast_manager.m.js';
 import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
 import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
-import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {flush, html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {ItemBehavior} from './item_behavior.js';
@@ -168,15 +167,6 @@
     return /** @type {?HTMLElement} */ (this.$$('#errors-button'));
   },
 
-  /** @private string */
-  a11yAssociation_() {
-    // Don't use I18nBehavior.i18n because of additional checks it performs.
-    // Polymer ensures that this string is not stamped into arbitrary HTML.
-    // |this.data.name| can contain any data including html tags.
-    // ex: "My <video> download extension!"
-    return loadTimeData.getStringF('extensionA11yAssociation', this.data.name);
-  },
-
   /** @private */
   observeIdVisibility_(inDevMode, showingDetails, id) {
     flush();
diff --git a/chrome/browser/resources/extensions/item_behavior.js b/chrome/browser/resources/extensions/item_behavior.js
index 984ab93c..bbe73808 100644
--- a/chrome/browser/resources/extensions/item_behavior.js
+++ b/chrome/browser/resources/extensions/item_behavior.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import {assertNotReached} from 'chrome://resources/js/assert.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 
 /** @polymerBehavior */
 export const ItemBehavior = {
@@ -25,4 +26,17 @@
     }
     assertNotReached('Item type is not App or Extension.');
   },
+
+  /**
+   * @param {string} name
+   * @return {string} The a11y association descriptor, e.g. "Related to <ext>".
+   */
+  a11yAssociation(name) {
+    // Don't use I18nBehavior.i18n because of additional checks it performs.
+    // Polymer ensures that this string is not stamped into arbitrary HTML.
+    // `name` can contain any data including html tags, e.g.
+    // "My <video> download extension!"
+    return loadTimeData.getStringF('extensionA11yAssociation', name);
+  },
+
 };
diff --git a/chrome/browser/resources/new_tab_page/BUILD.gn b/chrome/browser/resources/new_tab_page/BUILD.gn
index ab61075..c36bab5bd 100644
--- a/chrome/browser/resources/new_tab_page/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/BUILD.gn
@@ -26,7 +26,6 @@
     ":one_google_bar_api",
     ":promo_browser_command_proxy",
     ":realbox",
-    ":realbox_button",
     ":realbox_dropdown",
     ":realbox_icon",
     ":realbox_match",
@@ -194,21 +193,15 @@
 js_library("realbox_dropdown") {
   deps = [
     ":browser_proxy",
-    ":realbox_button",
     ":realbox_match",
     ":utils",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/cr_elements/cr_icon_button:cr_icon_button.m",
     "//ui/webui/resources/js:assert.m",
     "//ui/webui/resources/js:load_time_data.m",
   ]
 }
 
-js_library("realbox_button") {
-  deps = [
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-}
-
 js_library("realbox_icon") {
   deps = [
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
@@ -217,10 +210,10 @@
 
 js_library("realbox_match") {
   deps = [
-    ":realbox_button",
     ":realbox_icon",
     ":utils",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/cr_elements/cr_icon_button:cr_icon_button.m",
     "//ui/webui/resources/js:load_time_data.m",
   ]
 }
@@ -265,7 +258,6 @@
     "middle_slot_promo.js",
     "mini_page.js",
     "most_visited.js",
-    "realbox_button.js",
     "realbox_dropdown.js",
     "realbox_icon.js",
     "realbox_match.js",
@@ -323,7 +315,6 @@
       "logo.js",
       "doodle_share_dialog.js",
       "realbox.js",
-      "realbox_button.js",
       "realbox_dropdown.js",
       "realbox_icon.js",
       "realbox_match.js",
diff --git a/chrome/browser/resources/new_tab_page/customize_modules.html b/chrome/browser/resources/new_tab_page/customize_modules.html
index 81f71816..67adf0f 100644
--- a/chrome/browser/resources/new_tab_page/customize_modules.html
+++ b/chrome/browser/resources/new_tab_page/customize_modules.html
@@ -37,6 +37,10 @@
     font-weight: bold;
   }
 
+  #hideDescription {
+    color: var(--cr-secondary-text-color);
+  }
+
   cr-policy-indicator {
     margin-inline-end: 24px;
   }
@@ -49,7 +53,7 @@
   <div id="hideIcon" class="cr-icon icon-visibility-off"></div>
   <div id="hideTitleContainer">
     <div id="hideTitle">$i18n{hideModules}</div>
-    $i18n{hideModulesDesc}
+    <div id="hideDescription">$i18n{hideModulesDesc}</div>
   </div>
   <cr-policy-indicator indicator-type="devicePolicy"
       hidden="[[!hideManagedByPolicy_]]">
diff --git a/chrome/browser/resources/new_tab_page/customize_shortcuts.html b/chrome/browser/resources/new_tab_page/customize_shortcuts.html
index d3a645c9..c2f587b 100644
--- a/chrome/browser/resources/new_tab_page/customize_shortcuts.html
+++ b/chrome/browser/resources/new_tab_page/customize_shortcuts.html
@@ -132,6 +132,10 @@
     margin: 8px 0;
   }
 
+  .option-description {
+    color: var(--cr-secondary-text-color);
+  }
+
   #hide {
     align-items: center;
     border: 1px solid var(--ntp-border-color);
@@ -245,7 +249,7 @@
       <div class="selected-check"></div>
     </cr-button>
     <div class="option-title">$i18n{myShortcuts}</div>
-    $i18n{shortcutsCurated}
+    <div class="option-description">$i18n{shortcutsCurated}</div>
   </div>
   <div id="optionMostVisited"
       class$="option [[getMostVisitedSelected_(customLinksEnabled_, hide_)]]">
@@ -262,14 +266,14 @@
       <div class="selected-check"></div>
     </cr-button>
     <div class="option-title">$i18n{mostVisited}</div>
-    $i18n{shortcutsSuggested}
+    <div class="option-description">$i18n{shortcutsSuggested}</div>
   </div>
 </div>
 <div id="hide" class$="[[getHideClass_(hide_)]]">
   <div id="hideIcon" class="cr-icon icon-visibility-off"></div>
   <div id="hideTitleContainer">
     <div id="hideTitle">$i18n{hideShortcuts}</div>
-    $i18n{hideShortcutsDesc}
+    <div class="option-description">$i18n{hideShortcutsDesc}</div>
   </div>
   <cr-toggle id="hideToggle" title="$i18n{hideShortcuts}" checked="[[hide_]]"
       on-change="onHideChange_"></cr-toggle>
diff --git a/chrome/browser/resources/new_tab_page/most_visited.html b/chrome/browser/resources/new_tab_page/most_visited.html
index 21ebb56..62b2026d 100644
--- a/chrome/browser/resources/new_tab_page/most_visited.html
+++ b/chrome/browser/resources/new_tab_page/most_visited.html
@@ -235,7 +235,7 @@
           value="{{dialogTileTitle_}}" spellcheck="false" autofocus></cr-input>
       <cr-input id="dialogInputUrl" label="$i18n{urlField}"
           value="{{dialogTileUrl_}}" invalid="[[dialogTileUrlInvalid_]]"
-          error-message="$i18n{invalidUrl}" spellcheck="false" type="url"
+          error-message="[[dialogTileUrlError_]]" spellcheck="false" type="url"
           on-blur="onDialogTileUrlBlur_">
       </cr-input>
     </div>
diff --git a/chrome/browser/resources/new_tab_page/most_visited.js b/chrome/browser/resources/new_tab_page/most_visited.js
index 0d30802a..d56309c 100644
--- a/chrome/browser/resources/new_tab_page/most_visited.js
+++ b/chrome/browser/resources/new_tab_page/most_visited.js
@@ -148,7 +148,21 @@
       /** @private */
       dialogSaveDisabled_: {
         type: Boolean,
-        computed: 'computeDialogSaveDisabled_(dialogTitle_, dialogTileUrl_)',
+        computed: `computeDialogSaveDisabled_(dialogTitle_, dialogTileUrl_,
+            dialogShortcutAlreadyExists_)`,
+      },
+
+      /** @private */
+      dialogShortcutAlreadyExists_: {
+        type: Boolean,
+        computed: 'computeDialogShortcutAlreadyExists_(tiles_, dialogTileUrl_)',
+      },
+
+      /** @private */
+      dialogTileUrlError_: {
+        type: String,
+        computed: `computeDialogTileUrlError_(dialogTileUrl_,
+            dialogShortcutAlreadyExists_)`,
       },
 
       /**
@@ -370,7 +384,36 @@
    * @private
    */
   computeDialogSaveDisabled_() {
-    return !this.dialogTileUrl_ || normalizeUrl(this.dialogTileUrl_) === null;
+    return !this.dialogTileUrl_ || normalizeUrl(this.dialogTileUrl_) === null ||
+        this.dialogShortcutAlreadyExists_;
+  }
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  computeDialogShortcutAlreadyExists_() {
+    const dialogTileHref = (normalizeUrl(this.dialogTileUrl_) || {}).href;
+    if (!dialogTileHref) {
+      return false;
+    }
+    return (this.tiles_ || []).some(({url: {url}}, index) => {
+      if (index === this.actionMenuTargetIndex_) {
+        return false;
+      }
+      const otherUrl = normalizeUrl(url);
+      return otherUrl && otherUrl.href === dialogTileHref;
+    });
+  }
+
+  /**
+   * @return {string}
+   * @private
+   */
+  computeDialogTileUrlError_() {
+    return loadTimeData.getString(
+        this.dialogShortcutAlreadyExists_ ? 'shortcutAlreadyExists' :
+                                            'invalidUrl');
   }
 
   /**
@@ -593,7 +636,8 @@
   /** @private */
   onDialogTileUrlBlur_() {
     if (this.dialogTileUrl_.length > 0 &&
-        normalizeUrl(this.dialogTileUrl_) === null) {
+        (normalizeUrl(this.dialogTileUrl_) === null ||
+         this.dialogShortcutAlreadyExists_)) {
       this.dialogTileUrlInvalid_ = true;
     }
   }
diff --git a/chrome/browser/resources/new_tab_page/new_tab_page_resources.grd b/chrome/browser/resources/new_tab_page/new_tab_page_resources.grd
index 85a4fdf..27f593e 100644
--- a/chrome/browser/resources/new_tab_page/new_tab_page_resources.grd
+++ b/chrome/browser/resources/new_tab_page/new_tab_page_resources.grd
@@ -60,9 +60,6 @@
       <include name="IDR_NEW_TAB_PAGE_REALBOX_JS"
           file="${root_gen_dir}/chrome/browser/resources/new_tab_page/realbox.js"
           use_base_dir="false" type="BINDATA" />
-      <include name="IDR_NEW_TAB_PAGE_REALBOX_BUTTON_JS"
-          file="${root_gen_dir}/chrome/browser/resources/new_tab_page/realbox_button.js"
-          use_base_dir="false" type="BINDATA" />
       <include name="IDR_NEW_TAB_PAGE_REALBOX_DROPDOWN_JS"
           file="${root_gen_dir}/chrome/browser/resources/new_tab_page/realbox_dropdown.js"
           use_base_dir="false" type="BINDATA" />
diff --git a/chrome/browser/resources/new_tab_page/realbox.html b/chrome/browser/resources/new_tab_page/realbox.html
index 41746f8..ea2e7207 100644
--- a/chrome/browser/resources/new_tab_page/realbox.html
+++ b/chrome/browser/resources/new_tab_page/realbox.html
@@ -4,6 +4,7 @@
     border-radius: calc(0.5 * var(--ntp-realbox-height));
     box-shadow: 0 1px 6px 0 rgba(32, 33, 36, .28);
     height: var(--ntp-realbox-height);
+    user-select: none;
   }
 
   :host([matches-are-visible]) {
diff --git a/chrome/browser/resources/new_tab_page/realbox_button.html b/chrome/browser/resources/new_tab_page/realbox_button.html
deleted file mode 100644
index b25540e4..0000000
--- a/chrome/browser/resources/new_tab_page/realbox_button.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<style>
-  :host {
-    align-items: center;
-    border-radius: 50%;
-    display: flex;
-    flex-shrink: 0;
-    height: 24px;
-    justify-content: center;
-    outline: none;
-    width: 24px;
-  }
-
-  :host([hidden]) {
-    display: none;
-  }
-
-  :host(:hover) {
-    background-color: var(--search-box-icon-bg-hovered, rgba(var(--google-grey-refresh-700-rgb), .16));
-  }
-
-  :host(:focus-within) {
-    background-color: var(--search-box-icon-bg-focused, rgba(var(--google-grey-refresh-700-rgb), .32));
-  }
-
-  #icon {
-    -webkit-mask-image: url(chrome://resources/images/icon_clear.svg);
-    -webkit-mask-position: center;
-    -webkit-mask-repeat: no-repeat;
-    -webkit-mask-size: 16px;
-    height: 100%;
-    width: 100%;
-  }
-
-  :host-context(.header) #icon {
-    -webkit-mask-image: url(icons/chevron.svg);
-    -webkit-transform: rotate(180deg);
-    background-color: var(--search-box-icon, var(--google-grey-refresh-700));
-  }
-
-  :host-context(.header[group-is-hidden]) #icon {
-    -webkit-transform: none;
-  }
-
-  :host-context(ntp-realbox-match:hover) #icon {
-    background-color: var(--search-box-icon, var(--google-grey-refresh-700));
-  }
-
-  :host-context(ntp-realbox-match:-webkit-any(:focus-within, .selected)) #icon,
-  :host-context(.header:focus-within) #icon {
-    background-color: var(--search-box-icon-selected, var(--google-grey-refresh-700));
-  }
-</style>
-<div id="icon"></div>
-
diff --git a/chrome/browser/resources/new_tab_page/realbox_button.js b/chrome/browser/resources/new_tab_page/realbox_button.js
deleted file mode 100644
index e15cea1..0000000
--- a/chrome/browser/resources/new_tab_page/realbox_button.js
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import './strings.m.js';
-
-import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-// The RHS action button. Used on autocomplete matches as the remove button as
-// well as on suggestion group headers as the toggle button.
-class RealboxButtonElement extends PolymerElement {
-  static get is() {
-    return 'ntp-realbox-button';
-  }
-
-  static get template() {
-    return html`{__html_template__}`;
-  }
-
-  ready() {
-    super.ready();
-
-    this.addEventListener('mousedown', this.onMouseDown_.bind(this));
-  }
-
-  //============================================================================
-  // Event handlers
-  //============================================================================
-
-  /**
-   * @param {!Event} e
-   */
-  onMouseDown_(e) {
-    e.preventDefault();  // Prevents default browser action (focus).
-  }
-}
-
-customElements.define(RealboxButtonElement.is, RealboxButtonElement);
diff --git a/chrome/browser/resources/new_tab_page/realbox_dropdown.html b/chrome/browser/resources/new_tab_page/realbox_dropdown.html
index d23b78c..1b9e31f 100644
--- a/chrome/browser/resources/new_tab_page/realbox_dropdown.html
+++ b/chrome/browser/resources/new_tab_page/realbox_dropdown.html
@@ -1,7 +1,6 @@
 <style>
   :host {
     font-size: 16px;
-    user-select: none;
   }
 
   #selector {
@@ -41,6 +40,23 @@
     white-space: nowrap;
   }
 
+  .header cr-icon-button {
+    --cr-icon-button-fill-color: var(--search-box-icon, var(--google-grey-refresh-700));
+    --cr-icon-button-icon-size: 16px;
+    --cr-icon-button-margin-start: 0;
+    --cr-icon-button-size: 24px;
+    --cr-icon-image: url(icons/chevron.svg);
+    --cr-icon-image-transform: rotate(180deg);
+  }
+
+  .header[group-is-hidden] cr-icon-button {
+    --cr-icon-image-transform: none;
+  }
+
+  .header:focus-within:not(:focus) cr-icon-button {
+    --cr-icon-button-fill-color: var(--search-box-icon-selected, var(--google-grey-refresh-700));
+  }
+
   ntp-realbox-match:hover,
   .header:hover {
     background-color: var(--search-box-results-bg-hovered, rgba(var(--google-grey-900-rgb), .1));
@@ -64,11 +80,11 @@
           aria-hidden="true"
           group-is-hidden$="[[groupIsHidden_(groupId, hiddenGroupIds_.*)]]">
         <span class="text">[[headerForGroup_(groupId)]]</span>
-        <ntp-realbox-button tabindex="0" role="button"
+        <cr-icon-button class="icon-clear"
             title="[[toggleButtonTitleForGroup_(groupId, hiddenGroupIds_.*)]]"
             aria-label$="[[toggleButtonA11yLabelForGroup_(groupId, hiddenGroupIds_.*)]]"
-            on-keydown="onToggleButtonKeydown_">
-        </ntp-realbox-button>
+            on-mousedown="onToggleButtonMouseDown_">
+        </cr-icon-button>
       </div>
     </template>
     <template is="dom-if" if="[[!groupIsHidden_(groupId, hiddenGroupIds_.*)]]"
diff --git a/chrome/browser/resources/new_tab_page/realbox_dropdown.js b/chrome/browser/resources/new_tab_page/realbox_dropdown.js
index f8898b67..c91655b 100644
--- a/chrome/browser/resources/new_tab_page/realbox_dropdown.js
+++ b/chrome/browser/resources/new_tab_page/realbox_dropdown.js
@@ -3,9 +3,10 @@
 // found in the LICENSE file.
 
 import './strings.m.js';
-import './realbox_button.js';
 import './realbox_match.js';
 import 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
+import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
+import 'chrome://resources/cr_elements/cr_icons_css.m.js';
 
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {skColorToRgba} from 'chrome://resources/js/color_utils.js';
@@ -229,21 +230,8 @@
       return;
     }
 
-    const icon = assert(this.theme.icon);
-    // Icon's background color in a hovered context (0x29 == .16).
-    // TODO(crbug.com/1041129): Share this with the Omnibox.
-    const iconBgHovered = {value: icon.value & 0x29ffffff};
-
-    const iconSelected = assert(this.theme.iconSelected);
-    // Icon's background color in a focused context (0x52 == .32).
-    // TODO(crbug.com/1041129): Share this with the Omnibox.
-    const iconBgFocused = {value: iconSelected.value & 0x52ffffff};
-
     this.updateStyles({
-      '--search-box-icon-bg-focused': skColorToRgba(iconBgFocused),
-      '--search-box-icon-bg-hovered': skColorToRgba(iconBgHovered),
-      '--search-box-icon-selected': skColorToRgba(iconSelected),
-      '--search-box-icon': skColorToRgba(icon),
+      '--search-box-icon': skColorToRgba(this.theme.icon),
       '--search-box-results-bg-hovered':
           skColorToRgba(assert(this.theme.resultsBgHovered)),
       '--search-box-results-bg-selected':
@@ -299,14 +287,8 @@
    * @param {!Event} e
    * @private
    */
-  onToggleButtonKeydown_(e) {
-    if (e.key !== 'Enter' && e.key !== ' ') {
-      return;
-    }
-
-    // Simulate a click so that it gets handled by |onHeaderClick_|.
-    e.target.click();
-    e.preventDefault();  // Prevents default browser action.
+  onToggleButtonMouseDown_(e) {
+    e.preventDefault();  // Prevents default browser action (focus).
   }
 
   //============================================================================
diff --git a/chrome/browser/resources/new_tab_page/realbox_match.html b/chrome/browser/resources/new_tab_page/realbox_match.html
index 5455eff..b3011f40 100644
--- a/chrome/browser/resources/new_tab_page/realbox_match.html
+++ b/chrome/browser/resources/new_tab_page/realbox_match.html
@@ -1,4 +1,4 @@
-<style>
+<style include="cr-hidden-style cr-icons">
   :host {
     align-items: center;
     cursor: default;
@@ -70,6 +70,24 @@
     color: var(--search-box-results-url-selected, var(--google-blue-refresh-700));
   }
 
+  #remove {
+    --cr-icon-button-fill-color: var(--search-box-icon, var(--google-grey-refresh-700));
+    --cr-icon-button-icon-size: 16px;
+    --cr-icon-button-margin-end: 0;
+    --cr-icon-button-margin-start: 0;
+    --cr-icon-button-size: 24px;
+    opacity: 0; /* Hides the button while keeping it in tab order. */
+  }
+
+  :host-context(ntp-realbox-match:hover) #remove {
+    opacity: 1;
+  }
+
+  :host-context(ntp-realbox-match:-webkit-any(:focus-within, .selected)) #remove {
+    --cr-icon-button-fill-color: var(--search-box-icon-selected, var(--google-grey-refresh-700));
+    opacity: 1;
+  }
+
 </style>
 <ntp-realbox-icon id="icon" match="[[match]]"></ntp-realbox-icon>
 <div id="container">
@@ -77,7 +95,7 @@
   <span id="separator" class="dim">[[separatorText_]]</span>
   <span id="description" inner-h-t-m-l="[[descriptionHtml_]]"></span>
 </div>
-<ntp-realbox-button id="remove" tabindex="0" role="button"
-    on-click="onRemoveButtonClick_" on-keydown="onRemoveButtonKeydown_"
-    title$="[[removeButtonTitle_]]" hidden$="[[!removeButtonIsVisible_]]">
-</ntp-realbox-button>
+<cr-icon-button id="remove" class="icon-clear"
+    on-click="onRemoveButtonClick_" on-mousedown="onRemoveButtonMouseDown_"
+    title="[[removeButtonTitle_]]" hidden$="[[!removeButtonIsVisible_]]">
+</cr-icon-button>
diff --git a/chrome/browser/resources/new_tab_page/realbox_match.js b/chrome/browser/resources/new_tab_page/realbox_match.js
index 666cfb4..bb5243a 100644
--- a/chrome/browser/resources/new_tab_page/realbox_match.js
+++ b/chrome/browser/resources/new_tab_page/realbox_match.js
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import './strings.m.js';
-import './realbox_button.js';
 import './realbox_icon.js';
+import './strings.m.js';
+import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
+import 'chrome://resources/cr_elements/cr_icons_css.m.js';
+import 'chrome://resources/cr_elements/hidden_style_css.m.js';
 
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
@@ -199,14 +201,8 @@
    * @param {!Event} e
    * @private
    */
-  onRemoveButtonKeydown_(e) {
-    if (e.key !== 'Enter' && e.key !== ' ') {
-      return;
-    }
-
-    // Simulate a click so that it gets handled by |onRemoveButtonClick_|.
-    e.target.click();
-    e.preventDefault();  // Prevents default browser action.
+  onRemoveButtonMouseDown_(e) {
+    e.preventDefault();  // Prevents default browser action (focus).
   }
 
   //============================================================================
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_page.html b/chrome/browser/resources/settings/chromeos/internet_page/internet_page.html
index 60f932f..a0ab4d6b 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/internet_page.html
+++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_page.html
@@ -170,6 +170,13 @@
           iccid="[[esimProfileIccid_]]">
       </esim-rename-dialog>
     </template>
+
+    <template is="dom-if" if="[[showESimRemoveProfileDialog_]]" restamp>
+      <esim-remove-profile-dialog id="esimRemoveProfileDialog"
+          on-close="onCloseESimRemoveProfileDialog_"
+          iccid="[[esimProfileIccid_]]">
+      </esim-remove-profile-dialog>
+    </template>
   </template>
   <script src="internet_page.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_page.js b/chrome/browser/resources/settings/chromeos/internet_page/internet_page.js
index a803df40..cede6b2 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/internet_page.js
+++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_page.js
@@ -137,6 +137,12 @@
       value: false,
     },
 
+    /** @private {boolean} */
+    showESimRemoveProfileDialog_: {
+      type: Boolean,
+      value: false,
+    },
+
     /**
      * Iccid of an esim profile, used in internet detail menu.
      * @private {string}
@@ -183,6 +189,7 @@
     'show-known-networks': 'onShowKnownNetworks_',
     'show-networks': 'onShowNetworks_',
     'show-esim-profile-rename-dialog': 'onShowESimProfileRenameDialog_',
+    'show-esim-remove-profile-dialog': 'onShowESimRemoveProfileDialog_'
   },
 
   /** @private  {?settings.InternetPageBrowserProxy} */
@@ -412,6 +419,20 @@
   },
 
   /**
+   * @param {!CustomEvent<!{iccid: string}>} event
+   * @private
+   */
+  onShowESimRemoveProfileDialog_(event) {
+    this.esimProfileIccid_ = event.detail.iccid;
+    this.showESimRemoveProfileDialog_ = true;
+  },
+
+  /** @private */
+  onCloseESimRemoveProfileDialog_() {
+    this.showESimRemoveProfileDialog_ = false;
+  },
+
+  /**
    * @param {!CustomEvent<chromeos.networkConfig.mojom.NetworkType>} event
    * @private
    */
diff --git a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_subpage.html b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_subpage.html
index ce4497ea..df05809 100644
--- a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_subpage.html
@@ -143,7 +143,7 @@
                 MultiDeviceFeature.WIFI_SYNC, pageContentData)]]"
             restamp>
           <settings-multidevice-wifi-sync-item id="wifiSyncItem"
-              page-content-data="[[pageContentData]]"">
+              page-content-data="[[pageContentData]]">
           </settings-multidevice-wifi-sync-item>
         </template>
       </div>
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.js b/chrome/browser/resources/settings/chromeos/os_settings.js
index 0b6317d4..754c28c 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings.js
+++ b/chrome/browser/resources/settings/chromeos/os_settings.js
@@ -9,6 +9,7 @@
 import './bluetooth_page/bluetooth_subpage.m.js';
 import './bluetooth_page/bluetooth_device_list_item.m.js';
 import './internet_page/cellular_setup_dialog.m.js';
+import './internet_page/esim_remove_profile_dialog.m.js';
 import './internet_page/internet_config.m.js';
 import './internet_page/internet_detail_page.m.js';
 import './internet_page/internet_known_networks_page.m.js';
@@ -34,7 +35,6 @@
 import './os_about_page/detailed_build_info.m.js';
 import './os_about_page/update_warning_dialog.m.js';
 import './os_search_page/os_search_page.m.js';
-import './internet_page/esim_remove_profile_dialog.m.js';
 
 export {AboutPageBrowserProxyImpl, BrowserChannel, UpdateStatus} from '../about_page/about_page_browser_proxy.m.js';
 export {LifetimeBrowserProxy, LifetimeBrowserProxyImpl} from '../lifetime_browser_proxy.m.js';
diff --git a/chrome/browser/ssl/captive_portal_blocking_page_browsertest.cc b/chrome/browser/ssl/captive_portal_blocking_page_browsertest.cc
index e809071..2dfa8d08 100644
--- a/chrome/browser/ssl/captive_portal_blocking_page_browsertest.cc
+++ b/chrome/browser/ssl/captive_portal_blocking_page_browsertest.cc
@@ -300,9 +300,9 @@
 
   std::unique_ptr<SSLCertReporter> ssl_cert_reporter =
       certificate_reporting_test_utils::CreateMockSSLCertReporter(
-          base::Bind(&certificate_reporting_test_utils::
-                         SSLCertReporterCallback::ReportSent,
-                     base::Unretained(&reporter_callback)),
+          base::BindRepeating(&certificate_reporting_test_utils::
+                                  SSLCertReporterCallback::ReportSent,
+                              base::Unretained(&reporter_callback)),
           opt_in == certificate_reporting_test_utils::EXTENDED_REPORTING_OPT_IN
               ? certificate_reporting_test_utils::CERT_REPORT_EXPECTED
               : certificate_reporting_test_utils::CERT_REPORT_NOT_EXPECTED);
diff --git a/chrome/browser/ssl/certificate_reporting_test_utils.cc b/chrome/browser/ssl/certificate_reporting_test_utils.cc
index f901a05..dc6d2051 100644
--- a/chrome/browser/ssl/certificate_reporting_test_utils.cc
+++ b/chrome/browser/ssl/certificate_reporting_test_utils.cc
@@ -35,12 +35,12 @@
 class MockSSLCertReporter : public SSLCertReporter {
  public:
   MockSSLCertReporter(
-      const base::Callback<
+      base::RepeatingCallback<
           void(const std::string&,
-               const chrome_browser_ssl::CertLoggerRequest_ChromeChannel)>&
+               const chrome_browser_ssl::CertLoggerRequest_ChromeChannel)>
           report_sent_callback,
       ExpectReport expect_report)
-      : report_sent_callback_(report_sent_callback),
+      : report_sent_callback_(std::move(report_sent_callback)),
         expect_report_(expect_report),
         reported_(false) {}
 
@@ -62,7 +62,7 @@
   }
 
  private:
-  const base::Callback<void(
+  base::RepeatingCallback<void(
       const std::string&,
       const chrome_browser_ssl::CertLoggerRequest_ChromeChannel)>
       report_sent_callback_;
@@ -104,13 +104,13 @@
 #endif
 
 std::unique_ptr<SSLCertReporter> CreateMockSSLCertReporter(
-    const base::Callback<
+    base::RepeatingCallback<
         void(const std::string&,
-             const chrome_browser_ssl::CertLoggerRequest_ChromeChannel)>&
+             const chrome_browser_ssl::CertLoggerRequest_ChromeChannel)>
         report_sent_callback,
     ExpectReport expect_report) {
   return std::unique_ptr<SSLCertReporter>(
-      new MockSSLCertReporter(report_sent_callback, expect_report));
+      new MockSSLCertReporter(std::move(report_sent_callback), expect_report));
 }
 
 ExpectReport GetReportExpectedFromFinch() {
diff --git a/chrome/browser/ssl/certificate_reporting_test_utils.h b/chrome/browser/ssl/certificate_reporting_test_utils.h
index e490d54..a618cea 100644
--- a/chrome/browser/ssl/certificate_reporting_test_utils.h
+++ b/chrome/browser/ssl/certificate_reporting_test_utils.h
@@ -66,9 +66,9 @@
 // |report_sent_callback| when a report is sent. It also checks that a
 // report is sent or not sent according to |expect_report|.
 std::unique_ptr<SSLCertReporter> CreateMockSSLCertReporter(
-    const base::Callback<
+    base::RepeatingCallback<
         void(const std::string&,
-             const chrome_browser_ssl::CertLoggerRequest_ChromeChannel)>&
+             const chrome_browser_ssl::CertLoggerRequest_ChromeChannel)>
         report_sent_callback,
     ExpectReport expect_report);
 
diff --git a/chrome/browser/ssl/chrome_expect_ct_reporter_browsertest.cc b/chrome/browser/ssl/chrome_expect_ct_reporter_browsertest.cc
index 137da394..1ee434b 100644
--- a/chrome/browser/ssl/chrome_expect_ct_reporter_browsertest.cc
+++ b/chrome/browser/ssl/chrome_expect_ct_reporter_browsertest.cc
@@ -129,15 +129,15 @@
 // of Expect-CT HTTP headers.
 IN_PROC_BROWSER_TEST_F(ExpectCTBrowserTest, TestDynamicExpectCTReporting) {
   net::EmbeddedTestServer report_server;
-  report_server.RegisterRequestHandler(base::Bind(
+  report_server.RegisterRequestHandler(base::BindRepeating(
       &ExpectCTBrowserTest::ReportRequestHandler, base::Unretained(this)));
   ASSERT_TRUE(report_server.Start());
   GURL report_url = report_server.GetURL("/");
 
   net::EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
   test_server.RegisterRequestHandler(
-      base::Bind(&ExpectCTBrowserTest::TestRequestHandler,
-                 base::Unretained(this), report_url));
+      base::BindRepeating(&ExpectCTBrowserTest::TestRequestHandler,
+                          base::Unretained(this), report_url));
   ASSERT_TRUE(test_server.Start());
 
   // Set up the mock cert verifier to accept |test_server|'s certificate as
@@ -172,12 +172,12 @@
                        TestDynamicExpectCTHeaderProcessing) {
   net::EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
   test_server.RegisterRequestHandler(
-      base::Bind(&ExpectCTBrowserTest::ExpectCTHeaderRequestHandler,
-                 base::Unretained(this)));
+      base::BindRepeating(&ExpectCTBrowserTest::ExpectCTHeaderRequestHandler,
+                          base::Unretained(this)));
   ASSERT_TRUE(test_server.Start());
 
   net::EmbeddedTestServer report_server;
-  report_server.RegisterRequestHandler(base::Bind(
+  report_server.RegisterRequestHandler(base::BindRepeating(
       &ExpectCTBrowserTest::ReportRequestHandler, base::Unretained(this)));
   ASSERT_TRUE(report_server.Start());
 
diff --git a/chrome/browser/ssl/sct_reporting_service_factory.h b/chrome/browser/ssl/sct_reporting_service_factory.h
index 1bfa0e4d..6339994 100644
--- a/chrome/browser/ssl/sct_reporting_service_factory.h
+++ b/chrome/browser/ssl/sct_reporting_service_factory.h
@@ -41,8 +41,6 @@
   content::BrowserContext* GetBrowserContextToUse(
       content::BrowserContext* context) const override;
   bool ServiceIsCreatedWithBrowserContext() const override;
-
-  base::Callback<void()> service_reset_callback_;
 };
 
 #endif  // CHROME_BROWSER_SSL_SCT_REPORTING_SERVICE_FACTORY_H_
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index afa8caab..a0c5248 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -242,8 +242,8 @@
  public:
   explicit SSLInterstitialTimerObserver(WebContents* web_contents)
       : web_contents_(web_contents), message_loop_runner_(new base::RunLoop) {
-    callback_ = base::Bind(&SSLInterstitialTimerObserver::OnTimerStarted,
-                           base::Unretained(this));
+    callback_ = base::BindRepeating(
+        &SSLInterstitialTimerObserver::OnTimerStarted, base::Unretained(this));
     SSLErrorHandler::SetInterstitialTimerStartedCallbackForTesting(&callback_);
   }
 
@@ -616,9 +616,9 @@
 
     std::unique_ptr<SSLCertReporter> ssl_cert_reporter =
         certificate_reporting_test_utils::CreateMockSSLCertReporter(
-            base::Bind(&certificate_reporting_test_utils::
-                           SSLCertReporterCallback::ReportSent,
-                       base::Unretained(&reporter_callback)),
+            base::BindRepeating(&certificate_reporting_test_utils::
+                                    SSLCertReporterCallback::ReportSent,
+                                base::Unretained(&reporter_callback)),
             expect_report);
 
     SSLBlockingPage* interstitial_page =
@@ -687,9 +687,9 @@
 
     std::unique_ptr<SSLCertReporter> ssl_cert_reporter =
         certificate_reporting_test_utils::CreateMockSSLCertReporter(
-            base::Bind(&certificate_reporting_test_utils::
-                           SSLCertReporterCallback::ReportSent,
-                       base::Unretained(&reporter_callback)),
+            base::BindRepeating(&certificate_reporting_test_utils::
+                                    SSLCertReporterCallback::ReportSent,
+                                base::Unretained(&reporter_callback)),
             expect_report);
 
     ASSERT_TRUE(
@@ -2441,9 +2441,9 @@
 
   std::unique_ptr<SSLCertReporter> ssl_cert_reporter =
       certificate_reporting_test_utils::CreateMockSSLCertReporter(
-          base::Bind(&certificate_reporting_test_utils::
-                         SSLCertReporterCallback::ReportSent,
-                     base::Unretained(&reporter_callback)),
+          base::BindRepeating(&certificate_reporting_test_utils::
+                                  SSLCertReporterCallback::ReportSent,
+                              base::Unretained(&reporter_callback)),
           certificate_reporting_test_utils::CERT_REPORT_EXPECTED);
 
   SSLBlockingPage* interstitial_page =
@@ -5067,8 +5067,8 @@
   // function does not support https to http redirects.
   // This must be done before ServeFilesFromSourceDirectory(), otherwise the
   // test server will serve files instead of redirecting requests to them.
-  https_server_example_domain.RegisterRequestHandler(
-      base::Bind(&HTTPSToHTTPRedirectHandler, &https_server_example_domain));
+  https_server_example_domain.RegisterRequestHandler(base::BindRepeating(
+      &HTTPSToHTTPRedirectHandler, &https_server_example_domain));
 
   https_server_example_domain.ServeFilesFromSourceDirectory(
       GetChromeTestDataDir());
diff --git a/chrome/browser/ssl/stateful_ssl_host_state_delegate_test.cc b/chrome/browser/ssl/stateful_ssl_host_state_delegate_test.cc
index 9f7da2af..c1c48da 100644
--- a/chrome/browser/ssl/stateful_ssl_host_state_delegate_test.cc
+++ b/chrome/browser/ssl/stateful_ssl_host_state_delegate_test.cc
@@ -181,8 +181,8 @@
   EXPECT_TRUE(state->HasAllowException(kExampleHost, tab));
 
   // Clear data for kWWWGoogleHost. kExampleHost will not be modified.
-  state->Clear(
-      base::Bind(&CStrStringMatcher, base::Unretained(kWWWGoogleHost)));
+  state->Clear(base::BindRepeating(&CStrStringMatcher,
+                                   base::Unretained(kWWWGoogleHost)));
 
   EXPECT_FALSE(state->HasAllowException(kWWWGoogleHost, tab));
   EXPECT_TRUE(state->HasAllowException(kExampleHost, tab));
@@ -190,7 +190,7 @@
   // Do a full clear, then make sure that both kWWWGoogleHost and kExampleHost,
   // which had a decision made, and kGoogleHost, which was untouched, are now
   // in a denied state.
-  state->Clear(base::Callback<bool(const std::string&)>());
+  state->Clear(base::RepeatingCallback<bool(const std::string&)>());
   EXPECT_FALSE(state->HasAllowException(kWWWGoogleHost, tab));
   EXPECT_EQ(content::SSLHostStateDelegate::DENIED,
             state->QueryPolicy(kWWWGoogleHost, *cert,
diff --git a/chrome/browser/supervised_user/supervised_user_allowlist_service.cc b/chrome/browser/supervised_user/supervised_user_allowlist_service.cc
index f03cf92..d0dcd25e 100644
--- a/chrome/browser/supervised_user/supervised_user_allowlist_service.cc
+++ b/chrome/browser/supervised_user/supervised_user_allowlist_service.cc
@@ -151,7 +151,7 @@
     const syncer::SyncDataList& initial_sync_data,
     std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
     std::unique_ptr<syncer::SyncErrorFactory> error_handler) {
-  DCHECK_EQ(syncer::SUPERVISED_USER_ALLOWLISTS, type);
+  DCHECK_EQ(syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS, type);
 
   syncer::SyncChangeList change_list;
 
@@ -160,7 +160,8 @@
   std::set<std::string> seen_ids;
 
   for (const syncer::SyncData& sync_data : initial_sync_data) {
-    DCHECK_EQ(syncer::SUPERVISED_USER_ALLOWLISTS, sync_data.GetDataType());
+    DCHECK_EQ(syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS,
+              sync_data.GetDataType());
     const sync_pb::ManagedUserWhitelistSpecifics& allowlist =
         sync_data.GetSpecifics().managed_user_whitelist();
     std::string id = allowlist.id();
@@ -201,7 +202,7 @@
 }
 
 void SupervisedUserAllowlistService::StopSyncing(syncer::ModelType type) {
-  DCHECK_EQ(syncer::SUPERVISED_USER_ALLOWLISTS, type);
+  DCHECK_EQ(syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS, type);
 }
 
 syncer::SyncDataList SupervisedUserAllowlistService::GetAllSyncDataForTesting(
@@ -236,7 +237,8 @@
   base::DictionaryValue* pref_dict = update.Get();
   for (const syncer::SyncChange& sync_change : change_list) {
     syncer::SyncData data = sync_change.sync_data();
-    DCHECK_EQ(syncer::SUPERVISED_USER_ALLOWLISTS, data.GetDataType());
+    DCHECK_EQ(syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS,
+              data.GetDataType());
     const sync_pb::ManagedUserWhitelistSpecifics& allowlist =
         data.GetSpecifics().managed_user_whitelist();
     std::string id = allowlist.id();
diff --git a/chrome/browser/supervised_user/supervised_user_allowlist_service_unittest.cc b/chrome/browser/supervised_user/supervised_user_allowlist_service_unittest.cc
index f6a6062..0201aea 100644
--- a/chrome/browser/supervised_user/supervised_user_allowlist_service_unittest.cc
+++ b/chrome/browser/supervised_user/supervised_user_allowlist_service_unittest.cc
@@ -169,16 +169,18 @@
 TEST_F(SupervisedUserAllowlistServiceTest, MergeEmpty) {
   service_->Init();
 
-  ASSERT_TRUE(
-      service_->GetAllSyncDataForTesting(syncer::SUPERVISED_USER_ALLOWLISTS)
-          .empty());
+  ASSERT_TRUE(service_
+                  ->GetAllSyncDataForTesting(
+                      syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS)
+                  .empty());
   base::Optional<syncer::ModelError> error = service_->MergeDataAndStartSyncing(
-      syncer::SUPERVISED_USER_ALLOWLISTS, syncer::SyncDataList(),
+      syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS, syncer::SyncDataList(),
       std::unique_ptr<syncer::SyncChangeProcessor>(),
       std::unique_ptr<syncer::SyncErrorFactory>());
-  EXPECT_TRUE(
-      service_->GetAllSyncDataForTesting(syncer::SUPERVISED_USER_ALLOWLISTS)
-          .empty());
+  EXPECT_TRUE(service_
+                  ->GetAllSyncDataForTesting(
+                      syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS)
+                  .empty());
   EXPECT_FALSE(error.has_value());
 
   EXPECT_EQ(0u, installer_->registered_allowlists().size());
@@ -215,16 +217,18 @@
   initial_data.push_back(
       SupervisedUserAllowlistService::CreateAllowlistSyncData("cccc",
                                                               "Allowlist C"));
-  ASSERT_EQ(
-      2u, service_->GetAllSyncDataForTesting(syncer::SUPERVISED_USER_ALLOWLISTS)
-              .size());
+  ASSERT_EQ(2u, service_
+                    ->GetAllSyncDataForTesting(
+                        syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS)
+                    .size());
   base::Optional<syncer::ModelError> error = service_->MergeDataAndStartSyncing(
-      syncer::SUPERVISED_USER_ALLOWLISTS, initial_data,
+      syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS, initial_data,
       std::unique_ptr<syncer::SyncChangeProcessor>(),
       std::unique_ptr<syncer::SyncErrorFactory>());
-  EXPECT_EQ(
-      2u, service_->GetAllSyncDataForTesting(syncer::SUPERVISED_USER_ALLOWLISTS)
-              .size());
+  EXPECT_EQ(2u, service_
+                    ->GetAllSyncDataForTesting(
+                        syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS)
+                    .size());
   EXPECT_FALSE(error.has_value());
 
   // Allowlist A (which was previously ready) should be removed now, and
diff --git a/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.cc b/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.cc
index 920c059..dc8c71c 100644
--- a/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.cc
+++ b/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.cc
@@ -22,7 +22,7 @@
           DelegateMode::kTransportModeWithSingleModel),
       profile_(profile) {
   DCHECK(type == syncer::SUPERVISED_USER_SETTINGS ||
-         type == syncer::SUPERVISED_USER_ALLOWLISTS);
+         type == syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS);
 }
 
 SupervisedUserSyncModelTypeController::
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index 8c62986..ba24ff2 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -383,9 +383,10 @@
       model_type_store_factory,
       GetSyncableServiceForType(syncer::SUPERVISED_USER_SETTINGS)));
   controllers.push_back(std::make_unique<SupervisedUserSyncModelTypeController>(
-      syncer::SUPERVISED_USER_ALLOWLISTS, profile_, dump_stack,
+      syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS, profile_, dump_stack,
       model_type_store_factory,
-      GetSyncableServiceForType(syncer::SUPERVISED_USER_ALLOWLISTS)));
+      GetSyncableServiceForType(
+          syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS)));
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
@@ -610,7 +611,7 @@
       return SupervisedUserSettingsServiceFactory::GetForKey(
                  profile_->GetProfileKey())
           ->AsWeakPtr();
-    case syncer::SUPERVISED_USER_ALLOWLISTS:
+    case syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS:
       return SupervisedUserServiceFactory::GetForProfile(profile_)
           ->GetAllowlistService()
           ->AsWeakPtr();
diff --git a/chrome/browser/sync/profile_sync_service_factory_unittest.cc b/chrome/browser/sync/profile_sync_service_factory_unittest.cc
index b9478d0..3925844 100644
--- a/chrome/browser/sync/profile_sync_service_factory_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_factory_unittest.cc
@@ -92,7 +92,7 @@
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
     datatypes.push_back(syncer::SUPERVISED_USER_SETTINGS);
-    datatypes.push_back(syncer::SUPERVISED_USER_ALLOWLISTS);
+    datatypes.push_back(syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS);
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/sync/test/integration/migration_test.cc b/chrome/browser/sync/test/integration/migration_test.cc
index 1e8ed2b7..2171094 100644
--- a/chrome/browser/sync/test/integration/migration_test.cc
+++ b/chrome/browser/sync/test/integration/migration_test.cc
@@ -110,7 +110,7 @@
     // Supervised user data types will be "unready" during this test, so we
     // should not request that they be migrated.
     preferred_data_types.Remove(syncer::SUPERVISED_USER_SETTINGS);
-    preferred_data_types.Remove(syncer::SUPERVISED_USER_ALLOWLISTS);
+    preferred_data_types.Remove(syncer::DEPRECATED_SUPERVISED_USER_ALLOWLISTS);
 
     // Autofill wallet will be unready during this test, so we should not
     // request that it be migrated.
diff --git a/chrome/browser/translate/translate_model_service_browsertest.cc b/chrome/browser/translate/translate_model_service_browsertest.cc
new file mode 100644
index 0000000..82f41e3
--- /dev/null
+++ b/chrome/browser/translate/translate_model_service_browsertest.cc
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/translate/translate_model_service_factory.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "components/translate/core/common/translate_util.h"
+#include "content/public/test/browser_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using TranslateModelServiceDisabledBrowserTest = InProcessBrowserTest;
+
+IN_PROC_BROWSER_TEST_F(TranslateModelServiceDisabledBrowserTest,
+                       TranslateModelServiceDisabled) {
+  EXPECT_FALSE(
+      TranslateModelServiceFactory::GetForProfile(browser()->profile()));
+}
+
+class TranslateModelServiceBrowserTest
+    : public TranslateModelServiceDisabledBrowserTest {
+ public:
+  TranslateModelServiceBrowserTest() {
+    scoped_feature_list_.InitAndEnableFeature(
+        translate::kTFLiteLanguageDetectionEnabled);
+  }
+
+  ~TranslateModelServiceBrowserTest() override = default;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(TranslateModelServiceBrowserTest,
+                       TranslateModelServiceEnabled) {
+  EXPECT_TRUE(
+      TranslateModelServiceFactory::GetForProfile(browser()->profile()));
+}
+
+IN_PROC_BROWSER_TEST_F(TranslateModelServiceBrowserTest,
+                       TranslateModelServiceEnabled_OffTheRecord) {
+  EXPECT_TRUE(TranslateModelServiceFactory::GetForProfile(
+      browser()->profile()->GetPrimaryOTRProfile()));
+}
diff --git a/chrome/browser/translate/translate_model_service_factory.cc b/chrome/browser/translate/translate_model_service_factory.cc
new file mode 100644
index 0000000..306ec72
--- /dev/null
+++ b/chrome/browser/translate/translate_model_service_factory.cc
@@ -0,0 +1,46 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/translate/translate_model_service_factory.h"
+
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/translate/translate_model_service_impl.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/translate/core/common/translate_util.h"
+#include "content/public/browser/browser_context.h"
+
+// static
+TranslateModelServiceImpl* TranslateModelServiceFactory::GetForProfile(
+    Profile* profile) {
+  if (translate::IsTFLiteLanguageDetectionEnabled()) {
+    return static_cast<TranslateModelServiceImpl*>(
+        GetInstance()->GetServiceForBrowserContext(profile, true));
+  }
+  return nullptr;
+}
+
+// static
+TranslateModelServiceFactory* TranslateModelServiceFactory::GetInstance() {
+  static base::NoDestructor<TranslateModelServiceFactory> factory;
+  return factory.get();
+}
+
+TranslateModelServiceFactory::TranslateModelServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "TranslateModelService",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+TranslateModelServiceFactory::~TranslateModelServiceFactory() = default;
+
+KeyedService* TranslateModelServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  return new TranslateModelServiceImpl();
+}
+
+content::BrowserContext* TranslateModelServiceFactory::GetBrowserContextToUse(
+    content::BrowserContext* context) const {
+  // Use the original profile's TranslateModelService, even in Incognito mode.
+  return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
diff --git a/chrome/browser/translate/translate_model_service_factory.h b/chrome/browser/translate/translate_model_service_factory.h
new file mode 100644
index 0000000..54145ce
--- /dev/null
+++ b/chrome/browser/translate/translate_model_service_factory.h
@@ -0,0 +1,45 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_TRANSLATE_TRANSLATE_MODEL_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_TRANSLATE_TRANSLATE_MODEL_SERVICE_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/no_destructor.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+class TranslateModelServiceImpl;
+class Profile;
+
+// LazyInstance that owns all TranslateModelService(s) and associates
+// them with Profiles.
+class TranslateModelServiceFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  // Gets the TranslateModelService for the profile.
+  //
+  // Returns null if the features that allow for this to provide useful
+  // information are disabled.
+  static TranslateModelServiceImpl* GetForProfile(Profile* profile);
+
+  // Gets the LazyInstance that owns all TranslateModelService(s).
+  static TranslateModelServiceFactory* GetInstance();
+
+ private:
+  friend base::NoDestructor<TranslateModelServiceFactory>;
+
+  TranslateModelServiceFactory();
+  ~TranslateModelServiceFactory() override;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+  content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const override;
+};
+
+#endif  //  CHROME_BROWSER_TRANSLATE_TRANSLATE_MODEL_SERVICE_FACTORY_H_
diff --git a/chrome/browser/translate/translate_model_service_impl.cc b/chrome/browser/translate/translate_model_service_impl.cc
new file mode 100644
index 0000000..0511536
--- /dev/null
+++ b/chrome/browser/translate/translate_model_service_impl.cc
@@ -0,0 +1,22 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/translate/translate_model_service_impl.h"
+
+#include "base/files/file.h"
+#include "base/optional.h"
+
+TranslateModelServiceImpl::TranslateModelServiceImpl() {
+  // TODO(crbug.com/1151407): Register with the Optimiziation Guide for the
+  // language detection model.
+}
+
+TranslateModelServiceImpl::~TranslateModelServiceImpl() = default;
+
+base::Optional<base::File>
+TranslateModelServiceImpl::GetLanguageDetectionModelFile() {
+  // TODO(crbug.com/1151406): Implement loading the model on a background thread
+  // and return it for use by translate.
+  return base::nullopt;
+}
diff --git a/chrome/browser/translate/translate_model_service_impl.h b/chrome/browser/translate/translate_model_service_impl.h
new file mode 100644
index 0000000..4e683c2
--- /dev/null
+++ b/chrome/browser/translate/translate_model_service_impl.h
@@ -0,0 +1,22 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_TRANSLATE_TRANSLATE_MODEL_SERVICE_IMPL_H_
+#define CHROME_BROWSER_TRANSLATE_TRANSLATE_MODEL_SERVICE_IMPL_H_
+
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/translate/core/browser/translate_model_service.h"
+
+// Service that manages models required to support translation in the browser.
+class TranslateModelServiceImpl : public KeyedService,
+                                  public translate::TranslateModelService {
+ public:
+  TranslateModelServiceImpl();
+  ~TranslateModelServiceImpl() override;
+
+  // translate::TranslateModelService:
+  base::Optional<base::File> GetLanguageDetectionModelFile() override;
+};
+
+#endif  // CHROME_BROWSER_TRANSLATE_TRANSLATE_MODEL_SERVICE_IMPL_H_
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 05b190f..558c4e1 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1811,8 +1811,6 @@
       "app_list/search/search_result_ranker/frecency_store.h",
       "app_list/search/search_result_ranker/histogram_util.cc",
       "app_list/search/search_result_ranker/histogram_util.h",
-      "app_list/search/search_result_ranker/ml_app_rank_provider.cc",
-      "app_list/search/search_result_ranker/ml_app_rank_provider.h",
       "app_list/search/search_result_ranker/ranking_item_util.cc",
       "app_list/search/search_result_ranker/ranking_item_util.h",
       "app_list/search/search_result_ranker/recurrence_predictor.cc",
diff --git a/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc b/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc
index e73971b..ec5e90a7 100644
--- a/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc
+++ b/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc
@@ -11,6 +11,9 @@
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/apps/app_service/menu_util.h"
+#include "chrome/browser/chromeos/borealis/borealis_service.h"
+#include "chrome/browser/chromeos/borealis/borealis_shutdown_monitor.h"
+#include "chrome/browser/chromeos/borealis/borealis_util.h"
 #include "chrome/browser/chromeos/crosapi/browser_manager.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
 #include "chrome/browser/chromeos/crostini/crostini_terminal.h"
@@ -138,6 +141,10 @@
       } else if (app_id() == plugin_vm::kPluginVmShelfAppId) {
         plugin_vm::PluginVmManagerFactory::GetForProfile(profile())
             ->StopPluginVm(plugin_vm::kPluginVmName, /*force=*/false);
+      } else if (app_id() == borealis::kBorealisAppId) {
+        borealis::BorealisService::GetForProfile(profile())
+            ->ShutdownMonitor()
+            .ShutdownNow();
       } else {
         LOG(ERROR) << "App " << app_id()
                    << " should not have a shutdown guest OS command.";
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_event_logger.cc b/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_event_logger.cc
index 9faac3c2..1679069 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_event_logger.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_event_logger.cc
@@ -134,26 +134,6 @@
                                         weak_factory_.GetWeakPtr(), event));
 }
 
-void AppLaunchEventLogger::CreateRankings() {
-  const base::TimeDelta duration = base::Time::Now() - start_time_;
-  if (!ml_app_rank_provider_) {
-    ml_app_rank_provider_ = std::make_unique<MlAppRankProvider>();
-  }
-
-  ml_app_rank_provider_->CreateRankings(
-      app_features_map_,
-      ExponentialBucket(duration.InHours(), kTotalHoursBucketSizeMultiplier),
-      Bucketize(all_clicks_last_hour_->GetTotal(duration), kClickBuckets),
-      Bucketize(all_clicks_last_24_hours_->GetTotal(duration), kClickBuckets));
-}
-
-std::map<std::string, float> AppLaunchEventLogger::RetrieveRankings() {
-  if (!ml_app_rank_provider_) {
-    return {};
-  }
-  return ml_app_rank_provider_->RetrieveRankings();
-}
-
 std::string AppLaunchEventLogger::RemoveScheme(const std::string& id) {
   std::string app_id(id);
   if (!app_id.compare(0, strlen(kExtensionSchemeWithDelimiter),
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_event_logger.h b/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_event_logger.h
index 6559854a..5e77e7a9 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_event_logger.h
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/app_launch_event_logger.h
@@ -15,7 +15,6 @@
 #include "base/sequenced_task_runner.h"
 #include "base/values.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_event_logger.pb.h"
-#include "chrome/browser/ui/app_list/search/search_result_ranker/ml_app_rank_provider.h"
 #include "extensions/browser/extension_registry.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 
@@ -154,9 +153,6 @@
   const std::unique_ptr<chromeos::power::ml::RecentEventsCounter>
       all_clicks_last_24_hours_;
 
-  // Empty until/unless CreateRankings is called.
-  std::unique_ptr<MlAppRankProvider> ml_app_rank_provider_;
-
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
   base::WeakPtrFactory<AppLaunchEventLogger> weak_factory_;
 
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/ml_app_rank_provider.cc b/chrome/browser/ui/app_list/search/search_result_ranker/ml_app_rank_provider.cc
deleted file mode 100644
index fe4f314c..0000000
--- a/chrome/browser/ui/app_list/search/search_result_ranker/ml_app_rank_provider.cc
+++ /dev/null
@@ -1,338 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/app_list/search/search_result_ranker/ml_app_rank_provider.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/location.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/strings/stringprintf.h"
-#include "base/task/post_task.h"
-#include "base/task/task_traits.h"
-#include "base/task/thread_pool.h"
-#include "base/time/time.h"
-#include "chrome/browser/chromeos/power/ml/user_activity_ukm_logger_helpers.h"
-#include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_event_logger_helper.h"
-#include "chrome/grit/browser_resources.h"
-#include "chromeos/services/machine_learning/public/cpp/service_connection.h"
-#include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
-#include "components/assist_ranker/example_preprocessing.h"
-#include "components/crx_file/id_util.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "ui/base/resource/resource_bundle.h"
-
-using ::chromeos::machine_learning::mojom::BuiltinModelId;
-using ::chromeos::machine_learning::mojom::BuiltinModelSpec;
-using ::chromeos::machine_learning::mojom::BuiltinModelSpecPtr;
-using ::chromeos::machine_learning::mojom::CreateGraphExecutorResult;
-using ::chromeos::machine_learning::mojom::ExecuteResult;
-using ::chromeos::machine_learning::mojom::FloatList;
-using ::chromeos::machine_learning::mojom::Int64List;
-using ::chromeos::machine_learning::mojom::LoadModelResult;
-using ::chromeos::machine_learning::mojom::Tensor;
-using ::chromeos::machine_learning::mojom::TensorPtr;
-using ::chromeos::machine_learning::mojom::ValueList;
-
-namespace app_list {
-
-namespace {
-
-void LoadModelCallback(LoadModelResult result) {
-  if (result != LoadModelResult::OK) {
-    LOG(ERROR) << "Failed to load Top Cat model.";
-  }
-}
-
-void CreateGraphExecutorCallback(CreateGraphExecutorResult result) {
-  if (result != CreateGraphExecutorResult::OK) {
-    LOG(ERROR) << "Failed to create a Top Cat Graph Executor.";
-  }
-}
-
-// Returns: true if preprocessor config loaded, false if it could not be loaded.
-bool LoadExamplePreprocessorConfig(
-    assist_ranker::ExamplePreprocessorConfig* preprocessor_config) {
-  DCHECK(preprocessor_config);
-
-  const int resource_id = IDR_TOP_CAT_20190722_EXAMPLE_PREPROCESSOR_CONFIG_PB;
-  const scoped_refptr<base::RefCountedMemory> raw_config =
-      ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
-          resource_id);
-  if (!raw_config || !raw_config->front()) {
-    LOG(ERROR) << "Failed to load TopCatModel example preprocessor config.";
-    return false;
-  }
-
-  if (!preprocessor_config->ParseFromArray(raw_config->front(),
-                                           raw_config->size())) {
-    LOG(ERROR) << "Failed to parse TopCatModel example preprocessor config.";
-    return false;
-  }
-  return true;
-}
-
-// Perform the inference given the |features| and |app_id| of an app.
-// Posts |callback| to |task_runner| to perform the actual inference.
-void DoInference(const std::string& app_id,
-                 const std::vector<float>& features,
-                 scoped_refptr<base::SequencedTaskRunner> task_runner,
-                 const base::RepeatingCallback<
-                     void(base::flat_map<std::string, TensorPtr> inputs,
-                          const std::vector<std::string> outputs,
-                          const std::string app_id)> callback) {
-  // Prepare the input tensor.
-  base::flat_map<std::string, TensorPtr> inputs;
-  auto tensor = Tensor::New();
-  tensor->shape = Int64List::New();
-  tensor->shape->value = std::vector<int64_t>({1, features.size()});
-  tensor->data = ValueList::New();
-  tensor->data->set_float_list(FloatList::New());
-  tensor->data->get_float_list()->value =
-      std::vector<double>(std::begin(features), std::end(features));
-  inputs.emplace(std::string("input"), std::move(tensor));
-
-  const std::vector<std::string> outputs({std::string("output")});
-  DCHECK(task_runner);
-  task_runner->PostTask(FROM_HERE, base::BindOnce(callback, std::move(inputs),
-                                                  std::move(outputs), app_id));
-}
-
-// Process the RankerExample to vectorize the feature list for inference.
-// Returns true on success.
-bool RankerExampleToVectorizedFeatures(
-    const assist_ranker::ExamplePreprocessorConfig& preprocessor_config,
-    assist_ranker::RankerExample* example,
-    std::vector<float>* vectorized_features) {
-  int preprocessor_error = assist_ranker::ExamplePreprocessor::Process(
-      preprocessor_config, example, true);
-  // kNoFeatureIndexFound can occur normally (e.g., when the app URL
-  // isn't known to the model or a rarely seen enum value is used).
-  if (preprocessor_error != assist_ranker::ExamplePreprocessor::kSuccess &&
-      preprocessor_error !=
-          assist_ranker::ExamplePreprocessor::kNoFeatureIndexFound) {
-    // TODO: Log to UMA.
-    return false;
-  }
-
-  const auto& extracted_features =
-      example->features()
-          .at(assist_ranker::ExamplePreprocessor::kVectorizedFeatureDefaultName)
-          .float_list()
-          .float_value();
-  vectorized_features->assign(extracted_features.begin(),
-                              extracted_features.end());
-  return true;
-}
-
-// Does the CPU-intensive part of CreateRankings (preparing the Tensor inputs
-// from |app_features_map|, intended to be called on a low-priority
-// background thread. Invokes |callback| on |task_runner| once for each app in
-// |app_features_map|.
-void CreateRankingsImpl(
-    base::flat_map<std::string, AppLaunchFeatures> app_features_map,
-    int total_hours,
-    int all_clicks_last_hour,
-    int all_clicks_last_24_hours,
-    scoped_refptr<base::SequencedTaskRunner> task_runner,
-    const base::RepeatingCallback<
-        void(base::flat_map<std::string, TensorPtr> inputs,
-             const std::vector<std::string> outputs,
-             const std::string app_id)>& callback) {
-  const base::Time now(base::Time::Now());
-  const int hour = HourOfDay(now);
-  const int day = DayOfWeek(now);
-
-  assist_ranker::ExamplePreprocessorConfig preprocessor_config;
-  if (!LoadExamplePreprocessorConfig(&preprocessor_config)) {
-    return;
-  }
-  for (auto& app : app_features_map) {
-    assist_ranker::RankerExample example(
-        CreateRankerExample(app.second,
-                            now.ToDeltaSinceWindowsEpoch().InSeconds() -
-                                app.second.time_of_last_click_sec(),
-                            total_hours, day, hour, all_clicks_last_hour,
-                            all_clicks_last_24_hours));
-    std::vector<float> vectorized_features;
-    if (RankerExampleToVectorizedFeatures(preprocessor_config, &example,
-                                          &vectorized_features)) {
-      DoInference(app.first, vectorized_features, task_runner, callback);
-    }
-  }
-}
-
-}  // namespace
-
-assist_ranker::RankerExample CreateRankerExample(
-    const AppLaunchFeatures& features,
-    int time_since_last_click,
-    int total_hours,
-    int day_of_week,
-    int hour_of_day,
-    int all_clicks_last_hour,
-    int all_clicks_last_24_hours) {
-  assist_ranker::RankerExample example;
-  auto& ranker_example_features = *example.mutable_features();
-
-  ranker_example_features["DayOfWeek"].set_int32_value(day_of_week);
-  ranker_example_features["HourOfDay"].set_int32_value(hour_of_day);
-  ranker_example_features["AllClicksLastHour"].set_int32_value(
-      all_clicks_last_hour);
-  ranker_example_features["AllClicksLast24Hours"].set_int32_value(
-      all_clicks_last_24_hours);
-
-  ranker_example_features["AppType"].set_int32_value(features.app_type());
-  ranker_example_features["ClickRank"].set_int32_value(features.click_rank());
-  ranker_example_features["ClicksLastHour"].set_int32_value(
-      features.clicks_last_hour());
-  ranker_example_features["ClicksLast24Hours"].set_int32_value(
-      features.clicks_last_24_hours());
-  ranker_example_features["LastLaunchedFrom"].set_int32_value(
-      features.last_launched_from());
-  ranker_example_features["HasClick"].set_bool_value(
-      features.has_most_recently_used_index());
-  ranker_example_features["MostRecentlyUsedIndex"].set_int32_value(
-      features.most_recently_used_index());
-  ranker_example_features["TimeSinceLastClick"].set_int32_value(
-      Bucketize(time_since_last_click, kTimeSinceLastClickBuckets));
-  ranker_example_features["TotalClicks"].set_int32_value(
-      features.total_clicks());
-  ranker_example_features["TotalClicksPerHour"].set_float_value(
-      static_cast<float>(features.total_clicks()) / (total_hours + 1));
-  ranker_example_features["TotalHours"].set_int32_value(total_hours);
-
-  // Calculate FourHourClicksN and SixHourClicksN, which sum clicks for four
-  // and six hour periods respectively.
-  int four_hour_count = 0;
-  int six_hour_count = 0;
-  // Apps that have been clicked will have 24 clicks_each_hour values. Apps that
-  // have not been clicked will have no clicks_each_hour values, so can skip
-  // the FourHourClicksN and SixHourClicksN calculations.
-  if (features.clicks_each_hour_size() == 24) {
-    for (int hour = 0; hour < 24; hour++) {
-      int clicks = Bucketize(features.clicks_each_hour(hour), kClickBuckets);
-      ranker_example_features["ClicksEachHour" +
-                              base::StringPrintf("%02d", hour)]
-          .set_int32_value(clicks);
-      ranker_example_features["ClicksPerHour" +
-                              base::StringPrintf("%02d", hour)]
-          .set_float_value(static_cast<float>(clicks) / (total_hours + 1));
-      four_hour_count += clicks;
-      six_hour_count += clicks;
-      // Divide day into periods of 4 hours each.
-      if (hour % 4 == 3 && four_hour_count != 0) {
-        ranker_example_features["FourHourClicks" +
-                                base::StringPrintf("%01d", hour / 4)]
-            .set_int32_value(four_hour_count);
-        four_hour_count = 0;
-      }
-      // Divide day into periods of 6 hours each.
-      if (hour % 6 == 5 && six_hour_count != 0) {
-        ranker_example_features["SixHourClicks" +
-                                base::StringPrintf("%01d", hour / 6)]
-            .set_int32_value(six_hour_count);
-        six_hour_count = 0;
-      }
-    }
-  }
-
-  if (features.app_type() == AppLaunchEvent_AppType_CHROME) {
-    ranker_example_features["URL"].set_string_value(
-        kExtensionSchemeWithDelimiter + features.app_id());
-  } else if (features.app_type() == AppLaunchEvent_AppType_PWA) {
-    ranker_example_features["URL"].set_string_value(features.pwa_url());
-  } else if (features.app_type() == AppLaunchEvent_AppType_PLAY) {
-    ranker_example_features["URL"].set_string_value(
-        kAppScheme +
-        crx_file::id_util::GenerateId(features.arc_package_name()));
-  } else {
-    // TODO(crbug.com/1027782): Add DCHECK that this branch is not reached.
-  }
-  return example;
-}
-
-MlAppRankProvider::MlAppRankProvider()
-    : creation_task_runner_(base::SequencedTaskRunnerHandle::Get()),
-      background_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
-          {base::TaskPriority::BEST_EFFORT,
-           base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) {}
-
-MlAppRankProvider::~MlAppRankProvider() = default;
-
-void MlAppRankProvider::CreateRankings(
-    const base::flat_map<std::string, AppLaunchFeatures>& app_features_map,
-    int total_hours,
-    int all_clicks_last_hour,
-    int all_clicks_last_24_hours) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(creation_sequence_checker_);
-  // TODO(jennyz): Add start-to-end latency metrics for the work on each
-  // sequence.
-  background_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&CreateRankingsImpl, app_features_map, total_hours,
-                     all_clicks_last_hour, all_clicks_last_24_hours,
-                     creation_task_runner_,
-                     base::BindRepeating(&MlAppRankProvider::RunExecutor,
-                                         weak_factory_.GetWeakPtr())));
-}
-
-std::map<std::string, float> MlAppRankProvider::RetrieveRankings() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(creation_sequence_checker_);
-  return ranking_map_;
-}
-
-void MlAppRankProvider::RunExecutor(
-    base::flat_map<std::string, TensorPtr> inputs,
-    const std::vector<std::string> outputs,
-    const std::string app_id) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(creation_sequence_checker_);
-  BindGraphExecutorIfNeeded();
-  executor_->Execute(std::move(inputs), std::move(outputs),
-                     base::BindOnce(&MlAppRankProvider::ExecuteCallback,
-                                    base::Unretained(this), app_id));
-}
-
-void MlAppRankProvider::ExecuteCallback(
-    std::string app_id,
-    ExecuteResult result,
-    const base::Optional<std::vector<TensorPtr>> outputs) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(creation_sequence_checker_);
-  if (result != ExecuteResult::OK) {
-    LOG(ERROR) << "Top Cat inference execution failed.";
-    return;
-  }
-  ranking_map_[app_id] = outputs.value()[0]->data->get_float_list()->value[0];
-}
-
-void MlAppRankProvider::BindGraphExecutorIfNeeded() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(creation_sequence_checker_);
-  if (!model_) {
-    // Load the model.
-    BuiltinModelSpecPtr spec =
-        BuiltinModelSpec::New(BuiltinModelId::TOP_CAT_20190722);
-    chromeos::machine_learning::ServiceConnection::GetInstance()
-        ->LoadBuiltinModel(std::move(spec), model_.BindNewPipeAndPassReceiver(),
-                           base::BindOnce(&LoadModelCallback));
-  }
-
-  if (!executor_) {
-    // Get the graph executor.
-    model_->CreateGraphExecutor(executor_.BindNewPipeAndPassReceiver(),
-                                base::BindOnce(&CreateGraphExecutorCallback));
-    executor_.set_disconnect_handler(base::BindOnce(
-        &MlAppRankProvider::OnConnectionError, base::Unretained(this)));
-  }
-}
-
-void MlAppRankProvider::OnConnectionError() {
-  LOG(WARNING) << "Mojo connection for ML service closed.";
-  executor_.reset();
-  model_.reset();
-}
-
-}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/ml_app_rank_provider.h b/chrome/browser/ui/app_list/search/search_result_ranker/ml_app_rank_provider.h
deleted file mode 100644
index 319dee4..0000000
--- a/chrome/browser/ui/app_list/search/search_result_ranker/ml_app_rank_provider.h
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_ML_APP_RANK_PROVIDER_H_
-#define CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_ML_APP_RANK_PROVIDER_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/containers/flat_map.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/optional.h"
-#include "base/sequence_checker.h"
-#include "base/sequenced_task_runner.h"
-#include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_event_logger.pb.h"
-#include "chromeos/services/machine_learning/public/mojom/graph_executor.mojom.h"
-#include "chromeos/services/machine_learning/public/mojom/model.mojom.h"
-#include "chromeos/services/machine_learning/public/mojom/tensor.mojom.h"
-#include "components/assist_ranker/proto/example_preprocessor.pb.h"
-#include "components/assist_ranker/proto/ranker_example.pb.h"
-#include "mojo/public/cpp/bindings/remote.h"
-
-namespace app_list {
-
-// Creates a RankerExample with the given |features| and provided parameters.
-// Calculates other features (ClicksEachHour, ClickPerHour, FourHourClicks,
-// SixHourClicks). Converts the app id into the URL format used in the ML model.
-assist_ranker::RankerExample CreateRankerExample(
-    const AppLaunchFeatures& features,
-    int time_since_last_click,
-    int total_hours,
-    int day_of_week,
-    int hour_of_day,
-    int all_clicks_last_hour,
-    int all_clicks_last_24_hours);
-
-// Provide the app ranking using an ML model.
-// Rankings are created asynchronously using the ML Service and retrieved
-// synchronously at any time.
-// Sequencing: Must be created and used on the same sequence (typically the UI
-// thread).
-class MlAppRankProvider {
- public:
-  MlAppRankProvider();
-  ~MlAppRankProvider();
-
-  // Asynchronously generates ranking scores for the apps in |app_features_map|.
-  void CreateRankings(
-      const base::flat_map<std::string, AppLaunchFeatures>& app_features_map,
-      int total_hours,
-      int all_clicks_last_hour,
-      int all_clicks_last_24_hours);
-
-  // Returns a map of the ranking scores keyed by app id.
-  // This will return an empty map until some time after the first call to
-  // CreateRankings().
-  std::map<std::string, float> RetrieveRankings();
-
- private:
-  // Execute the |executor_| on the creation thread.
-  void RunExecutor(
-      base::flat_map<std::string,
-                     ::chromeos::machine_learning::mojom::TensorPtr> inputs,
-      std::vector<std::string> outputs,
-      std::string app_id);
-
-  // Stores the ranking score for an |app_id| in the |ranking_map_|.
-  // Executed by the ML Service when an Execute call is complete.
-  void ExecuteCallback(
-      std::string app_id,
-      ::chromeos::machine_learning::mojom::ExecuteResult result,
-      base::Optional<
-          std::vector<::chromeos::machine_learning::mojom::TensorPtr>> outputs);
-
-  // Initializes the graph executor for the ML service if it's not already
-  // available.
-  void BindGraphExecutorIfNeeded();
-
-  void OnConnectionError();
-
-  // Remotes used to execute functions in the ML service server end.
-  mojo::Remote<::chromeos::machine_learning::mojom::Model> model_;
-  mojo::Remote<::chromeos::machine_learning::mojom::GraphExecutor> executor_;
-
-  // Map from app id to ranking score.
-  std::map<std::string, float> ranking_map_;
-
-  // Runner for tasks that should run on the creation sequence.
-  scoped_refptr<base::SequencedTaskRunner> creation_task_runner_;
-
-  // Runner for low priority background tasks.
-  scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
-
-  // Sequence checker for methods that must run on the creation sequence.
-  SEQUENCE_CHECKER(creation_sequence_checker_);
-
-  base::WeakPtrFactory<MlAppRankProvider> weak_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(MlAppRankProvider);
-};
-
-}  // namespace app_list
-
-#endif  // CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_ML_APP_RANK_PROVIDER_H_
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/ml_app_rank_provider_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/ml_app_rank_provider_unittest.cc
deleted file mode 100644
index 5051a59..0000000
--- a/chrome/browser/ui/app_list/search/search_result_ranker/ml_app_rank_provider_unittest.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/app_list/search/search_result_ranker/ml_app_rank_provider.h"
-
-#include <string>
-
-#include "base/test/task_environment.h"
-#include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_event_logger.pb.h"
-#include "chromeos/services/machine_learning/public/cpp/fake_service_connection.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace app_list {
-
-const char kAppId[] = "app_id";
-
-TEST(MlAppRankProviderTest, MlInferenceTest) {
-  base::test::TaskEnvironment task_environment_;
-
-  chromeos::machine_learning::FakeServiceConnectionImpl fake_service_connection;
-
-  const double expected_value = 1.234;
-  fake_service_connection.SetOutputValue(std::vector<int64_t>{1L},
-                                         std::vector<double>{expected_value});
-
-  chromeos::machine_learning::ServiceConnection::
-      UseFakeServiceConnectionForTesting(&fake_service_connection);
-
-  MlAppRankProvider ml_app_rank_provider;
-
-  base::flat_map<std::string, AppLaunchFeatures> app_features_map;
-  AppLaunchFeatures features;
-  features.set_app_id(kAppId);
-  features.set_app_type(AppLaunchEvent_AppType_CHROME);
-  features.set_click_rank(1);
-  for (int hour = 0; hour < 24; ++hour) {
-    features.add_clicks_each_hour(1);
-  }
-
-  app_features_map[kAppId] = features;
-  ml_app_rank_provider.CreateRankings(app_features_map, 3, 1, 7);
-
-  EXPECT_EQ(0UL, ml_app_rank_provider.RetrieveRankings().size());
-
-  task_environment_.RunUntilIdle();
-
-  const std::map<std::string, float> ranking_map =
-      ml_app_rank_provider.RetrieveRankings();
-
-  task_environment_.RunUntilIdle();
-
-  ASSERT_EQ(1UL, ranking_map.size());
-  const auto it = ranking_map.find(kAppId);
-  ASSERT_NE(ranking_map.end(), it);
-  EXPECT_NEAR(expected_value, it->second, 0.001);
-}
-
-TEST(MlAppRankProviderTest, ExecutionAfterDestructorTest) {
-  base::test::TaskEnvironment task_environment_;
-
-  chromeos::machine_learning::FakeServiceConnectionImpl fake_service_connection;
-
-  const double expected_value = 1.234;
-  fake_service_connection.SetOutputValue(std::vector<int64_t>{1L},
-                                         std::vector<double>{expected_value});
-
-  chromeos::machine_learning::ServiceConnection::
-      UseFakeServiceConnectionForTesting(&fake_service_connection);
-
-  {
-    MlAppRankProvider ml_app_rank_provider;
-
-    base::flat_map<std::string, AppLaunchFeatures> app_features_map;
-    AppLaunchFeatures features;
-    features.set_app_id(kAppId);
-    features.set_app_type(AppLaunchEvent_AppType_CHROME);
-    app_features_map[kAppId] = features;
-    ml_app_rank_provider.CreateRankings(app_features_map, 3, 1, 7);
-  }
-  // Run the background tasks after ml_app_rank_provider has been destroyed.
-  // If this does not crash it is a success.
-  task_environment_.RunUntilIdle();
-}
-
-TEST(MlAppRankProviderTest, CreateRankerExampleTest) {
-  base::test::TaskEnvironment task_environment_;
-
-  MlAppRankProvider ml_app_rank_provider;
-
-  base::flat_map<std::string, AppLaunchFeatures> app_features_map;
-  AppLaunchFeatures features;
-  features.set_app_id(kAppId);
-  features.set_app_type(AppLaunchEvent_AppType_CHROME);
-  features.set_click_rank(1);
-  features.set_clicks_last_hour(3);
-  features.set_clicks_last_24_hours(4);
-  features.set_last_launched_from(AppLaunchEvent_LaunchedFrom_GRID);
-  features.set_most_recently_used_index(2);
-  features.set_total_clicks(100);
-  for (int hour = 0; hour < 24; ++hour) {
-    features.add_clicks_each_hour(hour + 10);
-  }
-
-  app_features_map[kAppId] = features;
-
-  assist_ranker::RankerExample actual =
-      CreateRankerExample(features, 120, 4, 3, 19, 7, 17);
-
-  auto* actual_feature_map(actual.mutable_features());
-
-  EXPECT_EQ(3, (*actual_feature_map)["DayOfWeek"].int32_value());
-  EXPECT_EQ(19, (*actual_feature_map)["HourOfDay"].int32_value());
-  EXPECT_EQ(7, (*actual_feature_map)["AllClicksLastHour"].int32_value());
-  EXPECT_EQ(17, (*actual_feature_map)["AllClicksLast24Hours"].int32_value());
-  EXPECT_EQ(1, (*actual_feature_map)["AppType"].int32_value());
-  EXPECT_EQ(1, (*actual_feature_map)["ClickRank"].int32_value());
-  EXPECT_EQ(3, (*actual_feature_map)["ClicksLastHour"].int32_value());
-  EXPECT_EQ(4, (*actual_feature_map)["ClicksLast24Hours"].int32_value());
-  EXPECT_EQ(1, (*actual_feature_map)["LastLaunchedFrom"].int32_value());
-  EXPECT_EQ(true, (*actual_feature_map)["HasClick"].bool_value());
-  EXPECT_EQ(2, (*actual_feature_map)["MostRecentlyUsedIndex"].int32_value());
-  EXPECT_EQ(120, (*actual_feature_map)["TimeSinceLastClick"].int32_value());
-  EXPECT_EQ(100, (*actual_feature_map)["TotalClicks"].int32_value());
-  EXPECT_NEAR(20.0, (*actual_feature_map)["TotalClicksPerHour"].float_value(),
-              0.1);
-  EXPECT_EQ(4, (*actual_feature_map)["TotalHours"].int32_value());
-  EXPECT_EQ(std::string("chrome-extension://") + kAppId,
-            (*actual_feature_map)["URL"].string_value());
-
-  EXPECT_EQ(10, (*actual_feature_map)["ClicksEachHour00"].int32_value());
-  EXPECT_EQ(11, (*actual_feature_map)["ClicksEachHour01"].int32_value());
-  EXPECT_EQ(19, (*actual_feature_map)["ClicksEachHour09"].int32_value());
-  EXPECT_EQ(20, (*actual_feature_map)["ClicksEachHour10"].int32_value());
-  // Bucketizing rounds 21-29 down to 20, 31-39 down to 30.
-  EXPECT_EQ(20, (*actual_feature_map)["ClicksEachHour11"].int32_value());
-  EXPECT_EQ(20, (*actual_feature_map)["ClicksEachHour19"].int32_value());
-  EXPECT_EQ(30, (*actual_feature_map)["ClicksEachHour20"].int32_value());
-  EXPECT_EQ(30, (*actual_feature_map)["ClicksEachHour23"].int32_value());
-
-  EXPECT_NEAR(2.0, (*actual_feature_map)["ClicksPerHour00"].float_value(), 0.1);
-  EXPECT_NEAR(2.2, (*actual_feature_map)["ClicksPerHour01"].float_value(), 0.1);
-  EXPECT_NEAR(6.0, (*actual_feature_map)["ClicksPerHour23"].float_value(), 0.1);
-
-  EXPECT_EQ(10 + 11 + 12 + 13,
-            (*actual_feature_map)["FourHourClicks0"].int32_value());
-  EXPECT_EQ(30 + 30 + 30 + 30,
-            (*actual_feature_map)["FourHourClicks5"].int32_value());
-
-  EXPECT_EQ(10 + 11 + 12 + 13 + 14 + 15,
-            (*actual_feature_map)["SixHourClicks0"].int32_value());
-  EXPECT_EQ(20 + 20 + 30 + 30 + 30 + 30,
-            (*actual_feature_map)["SixHourClicks3"].int32_value());
-}
-
-}  // namespace app_list
diff --git a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
index a72a77ff..147c9352 100644
--- a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
+++ b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
@@ -185,7 +185,7 @@
 void TestOpenSettingFromArc(Browser* browser,
                             ChromePage page,
                             const GURL& expected_url,
-                            int expected_setting_window_count) {
+                            size_t expected_setting_window_count) {
   // Install the Settings App.
   web_app::WebAppProvider::Get(browser->profile())
       ->system_web_app_manager()
@@ -206,20 +206,20 @@
   TestOpenSettingFromArc(
       browser(), ChromePage::AUTOFILL,
       GURL("chrome://settings/").Resolve(chrome::kAutofillSubPage),
-      /*expected_setting_window_count=*/0);
+      /*expected_setting_window_count=*/0u);
 
   // But opening an OS setting should open the OS setting window.
   TestOpenSettingFromArc(
       browser(), ChromePage::POWER,
       GURL("chrome://os-settings/")
           .Resolve(chromeos::settings::mojom::kPowerSubpagePath),
-      /*expected_setting_window_count=*/1);
+      /*expected_setting_window_count=*/1u);
 }
 
 IN_PROC_BROWSER_TEST_F(ChromeNewWindowClientBrowserTest, OpenAboutChromePage) {
   // Opening an about: chrome page opens a new tab, and not the Settings window.
   ChromeNewWindowClient::Get()->OpenChromePageFromArc(ChromePage::ABOUTHISTORY);
-  EXPECT_EQ(0, GetNumberOfSettingsWindows());
+  EXPECT_EQ(0u, GetNumberOfSettingsWindows());
 
   content::WebContents* contents =
       GetLastActiveBrowser()->tab_strip_model()->GetActiveWebContents();
diff --git a/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc b/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc
index 05db68b9..b770e05 100644
--- a/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc
@@ -13,6 +13,9 @@
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/apps/app_service/menu_util.h"
 #include "chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_menu_builder.h"
+#include "chrome/browser/chromeos/borealis/borealis_service.h"
+#include "chrome/browser/chromeos/borealis/borealis_shutdown_monitor.h"
+#include "chrome/browser/chromeos/borealis/borealis_util.h"
 #include "chrome/browser/chromeos/crosapi/browser_manager.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
 #include "chrome/browser/chromeos/crostini/crostini_shelf_utils.h"
@@ -150,6 +153,10 @@
         plugin_vm::PluginVmManagerFactory::GetForProfile(
             controller()->profile())
             ->StopPluginVm(plugin_vm::kPluginVmName, /*force=*/false);
+      } else if (item().id.app_id == borealis::kBorealisAppId) {
+        borealis::BorealisService::GetForProfile(controller()->profile())
+            ->ShutdownMonitor()
+            .ShutdownNow();
       } else {
         LOG(ERROR) << "App " << item().id.app_id
                    << " should not have a shutdown guest OS command.";
diff --git a/chrome/browser/ui/views/borealis/borealis_installer_view.cc b/chrome/browser/ui/views/borealis/borealis_installer_view.cc
index b93039e..1b50bfe 100644
--- a/chrome/browser/ui/views/borealis/borealis_installer_view.cc
+++ b/chrome/browser/ui/views/borealis/borealis_installer_view.cc
@@ -13,7 +13,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/borealis/borealis_context_manager.h"
-#include "chrome/browser/chromeos/borealis/borealis_installer_factory.h"
+#include "chrome/browser/chromeos/borealis/borealis_installer.h"
 #include "chrome/browser/chromeos/borealis/borealis_service.h"
 #include "chrome/browser/chromeos/borealis/borealis_util.h"
 #include "chrome/browser/ui/browser_navigator.h"
@@ -79,9 +79,7 @@
 // Currently using the UI specs that the Plugin VM installer use.
 BorealisInstallerView::BorealisInstallerView(Profile* profile)
     : app_name_(l10n_util::GetStringUTF16(IDS_BOREALIS_APP_NAME)),
-      profile_(profile),
-      borealis_installer_(
-          borealis::BorealisInstallerFactory::GetForProfile(profile_)) {
+      profile_(profile) {
   // Layout constants from the spec used for the plugin vm installer.
   gfx::Insets kDialogInsets(60, 64, 0, 64);
   const int kPrimaryMessageHeight = views::style::GetLineHeight(
@@ -165,9 +163,11 @@
 }
 
 BorealisInstallerView::~BorealisInstallerView() {
-  borealis_installer_->RemoveObserver(this);
+  borealis::BorealisInstaller& installer =
+      borealis::BorealisService::GetForProfile(profile_)->Installer();
+  installer.RemoveObserver(this);
   if (state_ == State::kConfirmInstall || state_ == State::kInstalling) {
-    borealis_installer_->Cancel();
+    installer.Cancel();
   }
   g_borealis_installer_view = nullptr;
 }
@@ -448,6 +448,8 @@
   progress_bar_->SetValue(0);
   OnStateUpdated();
 
-  borealis_installer_->AddObserver(this);
-  borealis_installer_->Start();
+  borealis::BorealisInstaller& installer =
+      borealis::BorealisService::GetForProfile(profile_)->Installer();
+  installer.AddObserver(this);
+  installer.Start();
 }
diff --git a/chrome/browser/ui/views/borealis/borealis_installer_view.h b/chrome/browser/ui/views/borealis/borealis_installer_view.h
index 0bb5082..9f4844e 100644
--- a/chrome/browser/ui/views/borealis/borealis_installer_view.h
+++ b/chrome/browser/ui/views/borealis/borealis_installer_view.h
@@ -7,7 +7,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "chrome/browser/chromeos/borealis/borealis_installer_impl.h"
+#include "chrome/browser/chromeos/borealis/borealis_installer.h"
 #include "chrome/browser/chromeos/borealis/borealis_metrics.h"
 #include "ui/views/window/dialog_delegate.h"
 
@@ -93,7 +93,6 @@
   views::BoxLayout* lower_container_layout_ = nullptr;
   views::ImageView* big_image_ = nullptr;
 
-  borealis::BorealisInstaller* borealis_installer_ = nullptr;
   State state_ = State::kConfirmInstall;
   InstallingState installing_state_ = InstallingState::kInactive;
   base::Optional<borealis::BorealisInstallResult> result_;
diff --git a/chrome/browser/ui/views/borealis/borealis_installer_view_browsertest.cc b/chrome/browser/ui/views/borealis/borealis_installer_view_browsertest.cc
index 2334b675..3191ffc 100644
--- a/chrome/browser/ui/views/borealis/borealis_installer_view_browsertest.cc
+++ b/chrome/browser/ui/views/borealis/borealis_installer_view_browsertest.cc
@@ -6,8 +6,8 @@
 
 #include "base/bind.h"
 #include "chrome/browser/chromeos/borealis/borealis_context.h"
-#include "chrome/browser/chromeos/borealis/borealis_context_manager.h"
-#include "chrome/browser/chromeos/borealis/borealis_installer_factory.h"
+#include "chrome/browser/chromeos/borealis/borealis_context_manager_mock.h"
+#include "chrome/browser/chromeos/borealis/borealis_installer.h"
 #include "chrome/browser/chromeos/borealis/borealis_metrics.h"
 #include "chrome/browser/chromeos/borealis/borealis_service_fake.h"
 #include "chrome/browser/chromeos/borealis/borealis_task.h"
@@ -40,15 +40,6 @@
   MOCK_METHOD1(RemoveObserver, void(Observer*));
 };
 
-class BorealisContextManagerMock : public borealis::BorealisContextManager {
- public:
-  MOCK_METHOD(void,
-              StartBorealis,
-              (BorealisContextManager::ResultCallback),
-              ());
-  MOCK_METHOD(void, ShutDownBorealis, (), ());
-};
-
 class BorealisInstallerViewBrowserTest : public DialogBrowserTest {
  public:
   BorealisInstallerViewBrowserTest() = default;
@@ -56,20 +47,11 @@
   // DialogBrowserTest:
   void SetUpOnMainThread() override {
     app_name_ = l10n_util::GetStringUTF16(IDS_BOREALIS_APP_NAME);
-    mock_installer_ =
-        static_cast<::testing::StrictMock<BorealisInstallerMock>*>(
-            borealis::BorealisInstallerFactory::GetInstance()
-                ->SetTestingFactoryAndUse(
-                    browser()->profile(),
-                    base::BindRepeating([](content::BrowserContext* context)
-                                            -> std::unique_ptr<KeyedService> {
-                      return std::make_unique<
-                          testing::StrictMock<BorealisInstallerMock>>();
-                    })));
 
     BorealisServiceFake* fake_service =
         BorealisServiceFake::UseFakeForTesting(browser()->profile());
     fake_service->SetContextManagerForTesting(&mock_context_manager_);
+    fake_service->SetInstallerForTesting(&mock_installer_);
   }
 
   void ShowUi(const std::string& name) override {
@@ -129,8 +111,8 @@
   }
 
   void AcceptInstallation() {
-    EXPECT_CALL(*mock_installer_, AddObserver(_));
-    EXPECT_CALL(*mock_installer_, Start());
+    EXPECT_CALL(mock_installer_, AddObserver(_));
+    EXPECT_CALL(mock_installer_, Start());
     view_->AcceptDialog();
     view_->SetInstallingStateForTesting(
         borealis::BorealisInstaller::InstallingState::kInstallingDlc);
@@ -138,13 +120,13 @@
   }
 
   void ClickCancel() {
-    EXPECT_CALL(*mock_installer_, RemoveObserver(_));
+    EXPECT_CALL(mock_installer_, RemoveObserver(_));
     view_->CancelDialog();
 
     EXPECT_TRUE(view_->GetWidget()->IsClosed());
   }
 
-  ::testing::StrictMock<BorealisInstallerMock>* mock_installer_;
+  ::testing::StrictMock<BorealisInstallerMock> mock_installer_;
   ::testing::StrictMock<BorealisContextManagerMock> mock_context_manager_;
   BorealisInstallerView* view_;
   base::string16 app_name_;
@@ -159,8 +141,8 @@
 
 // Test that the dialog can be launched.
 IN_PROC_BROWSER_TEST_F(BorealisInstallerViewBrowserTest, InvokeUi_default) {
-  EXPECT_CALL(*mock_installer_, RemoveObserver(_));
-  EXPECT_CALL(*mock_installer_, Cancel());
+  EXPECT_CALL(mock_installer_, RemoveObserver(_));
+  EXPECT_CALL(mock_installer_, Cancel());
   ShowAndVerifyUi();
 }
 
@@ -172,7 +154,7 @@
   ExpectInstallationCompletedSucessfully();
 
   EXPECT_CALL(mock_context_manager_, StartBorealis(_));
-  EXPECT_CALL(*mock_installer_, RemoveObserver(_));
+  EXPECT_CALL(mock_installer_, RemoveObserver(_));
   view_->AcceptDialog();
 
   EXPECT_TRUE(view_->GetWidget()->IsClosed());
@@ -182,7 +164,7 @@
                        ConfirmationCancelled) {
   ShowUi("default");
 
-  EXPECT_CALL(*mock_installer_, Cancel());
+  EXPECT_CALL(mock_installer_, Cancel());
   ClickCancel();
 }
 
@@ -191,7 +173,7 @@
   ShowUi("default");
   AcceptInstallation();
 
-  EXPECT_CALL(*mock_installer_, Cancel());
+  EXPECT_CALL(mock_installer_, Cancel());
   ClickCancel();
 }
 
@@ -214,7 +196,7 @@
   ExpectInstallationCompletedSucessfully();
 
   EXPECT_CALL(mock_context_manager_, StartBorealis(_));
-  EXPECT_CALL(*mock_installer_, RemoveObserver(_));
+  EXPECT_CALL(mock_installer_, RemoveObserver(_));
   view_->AcceptDialog();
 
   EXPECT_TRUE(view_->GetWidget()->IsClosed());
diff --git a/chrome/browser/ui/views/sharesheet/sharesheet_bubble_view.cc b/chrome/browser/ui/views/sharesheet/sharesheet_bubble_view.cc
index c9cc66a..238bbdc 100644
--- a/chrome/browser/ui/views/sharesheet/sharesheet_bubble_view.cc
+++ b/chrome/browser/ui/views/sharesheet/sharesheet_bubble_view.cc
@@ -447,7 +447,7 @@
   // Catch widgets that are closing due to the user clicking out of the bubble.
   // If |user_selection_made_| we should not close the bubble here as it will be
   // closed in a different code path.
-  if (!active && !user_selection_made_) {
+  if (!active && !user_selection_made_ && !is_bubble_closing_) {
     if (close_callback_) {
       std::move(close_callback_).Run(sharesheet::SharesheetResult::kCancel);
     }
diff --git a/chrome/browser/ui/views/webauthn/authenticator_client_pin_entry_sheet_view.cc b/chrome/browser/ui/views/webauthn/authenticator_client_pin_entry_sheet_view.cc
index 54f2fe0..7b86136 100644
--- a/chrome/browser/ui/views/webauthn/authenticator_client_pin_entry_sheet_view.cc
+++ b/chrome/browser/ui/views/webauthn/authenticator_client_pin_entry_sheet_view.cc
@@ -24,9 +24,8 @@
 std::unique_ptr<views::View>
 AuthenticatorClientPinEntrySheetView::BuildStepSpecificContent() {
   return std::make_unique<AuthenticatorClientPinEntryView>(
-      this, pin_entry_sheet_model()->mode() ==
-                AuthenticatorClientPinEntrySheetModel::Mode::
-                    kPinSetup /* show_confirmation_text_field */);
+      this, /*show_confirmation_text_field=*/pin_entry_sheet_model()->mode() !=
+                AuthenticatorClientPinEntrySheetModel::Mode::kPinEntry);
 }
 
 void AuthenticatorClientPinEntrySheetView::OnPincodeChanged(
diff --git a/chrome/browser/ui/views/webauthn/sheet_view_factory.cc b/chrome/browser/ui/views/webauthn/sheet_view_factory.cc
index 0ee824f..bbb2f28 100644
--- a/chrome/browser/ui/views/webauthn/sheet_view_factory.cc
+++ b/chrome/browser/ui/views/webauthn/sheet_view_factory.cc
@@ -114,6 +114,12 @@
       sheet_view = std::make_unique<AuthenticatorQRSheetView>(
           std::make_unique<AuthenticatorQRSheetModel>(dialog_model));
       break;
+    case Step::kClientPinChange:
+      sheet_view = std::make_unique<AuthenticatorClientPinEntrySheetView>(
+          std::make_unique<AuthenticatorClientPinEntrySheetModel>(
+              dialog_model,
+              AuthenticatorClientPinEntrySheetModel::Mode::kPinChange));
+      break;
     case Step::kClientPinEntry:
       sheet_view = std::make_unique<AuthenticatorClientPinEntrySheetView>(
           std::make_unique<AuthenticatorClientPinEntrySheetModel>(
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.cc b/chrome/browser/ui/web_applications/app_browser_controller.cc
index 718206a..2108710 100644
--- a/chrome/browser/ui/web_applications/app_browser_controller.cc
+++ b/chrome/browser/ui/web_applications/app_browser_controller.cc
@@ -6,7 +6,9 @@
 
 #include "base/bind.h"
 #include "base/feature_list.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/installable/installable_manager.h"
 #include "chrome/browser/profiles/profile.h"
@@ -283,7 +285,9 @@
 
 bool AppBrowserController::HasTitlebarAppOriginText() const {
   // Do not show origin text for System Apps.
-  return !is_for_system_web_app();
+  bool hide = is_for_system_web_app() ||
+              base::FeatureList::IsEnabled(features::kHideWebAppOriginText);
+  return !hide;
 }
 
 bool AppBrowserController::HasTitlebarContentSettings() const {
@@ -448,7 +452,22 @@
 
   content::NavigationEntry* entry =
       web_contents->GetController().GetVisibleEntry();
-  return entry ? entry->GetTitle() : base::string16();
+  base::string16 raw_title = entry ? entry->GetTitle() : base::string16();
+
+  if (!base::FeatureList::IsEnabled(features::kPrefixWebAppWindowsWithAppName))
+    return raw_title;
+
+  base::string16 app_name =
+      base::ASCIIToUTF16(WebAppProvider::Get(browser()->profile())
+                             ->registrar()
+                             .GetAppShortName(GetAppId()));
+  if (base::StartsWith(raw_title, app_name)) {
+    return raw_title;
+  } else if (raw_title.empty()) {
+    return app_name;
+  } else {
+    return base::StrCat({app_name, base::ASCIIToUTF16(" - "), raw_title});
+  }
 }
 
 void AppBrowserController::OnTabStripModelChanged(
diff --git a/chrome/browser/ui/web_applications/web_app_browsertest.cc b/chrome/browser/ui/web_applications/web_app_browsertest.cc
index 7e8e703..2eb70b5 100644
--- a/chrome/browser/ui/web_applications/web_app_browsertest.cc
+++ b/chrome/browser/ui/web_applications/web_app_browsertest.cc
@@ -1022,6 +1022,73 @@
   EXPECT_EQ(app_title, app_browser->GetWindowTitleForCurrentTab(false));
 }
 
+class WebAppBrowserTest_PrefixInTitle : public WebAppBrowserTest {
+ public:
+  WebAppBrowserTest_PrefixInTitle() {
+    scoped_feature_list_.InitAndEnableFeature(
+        features::kPrefixWebAppWindowsWithAppName);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// Ensure that web app windows display the app title as a prefix.
+IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_PrefixInTitle, PrefixExistsInTitle) {
+  const GURL app_url = GetSecureAppURL();
+  const base::string16 app_title = base::ASCIIToUTF16("A Web App");
+
+  auto web_app_info = std::make_unique<WebApplicationInfo>();
+  web_app_info->start_url = app_url;
+  web_app_info->scope = app_url.GetWithoutFilename();
+  web_app_info->title = app_title;
+  const AppId app_id = InstallWebApp(std::move(web_app_info));
+
+  Browser* const app_browser = LaunchWebAppBrowser(app_id);
+  content::WebContents* const web_contents =
+      app_browser->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(content::WaitForLoadStop(web_contents));
+
+  // The page title should be the combination of app name and title.
+  EXPECT_EQ(base::ASCIIToUTF16("A Web App - Google"),
+            app_browser->GetWindowTitleForCurrentTab(false));
+}
+
+// Ensure that web app windows with blank titles only display the app name.
+IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_PrefixInTitle,
+                       EmptyTitlesDisplayAppName) {
+  const GURL app_url = https_server()->GetURL("app.site.com", "/empty.html");
+  const base::string16 app_title = base::ASCIIToUTF16("A Web App");
+  auto web_app_info = std::make_unique<WebApplicationInfo>();
+  web_app_info->start_url = app_url;
+  web_app_info->scope = app_url.GetWithoutFilename();
+  web_app_info->title = app_title;
+  const AppId app_id = InstallWebApp(std::move(web_app_info));
+  Browser* const app_browser = LaunchWebAppBrowser(app_id);
+  content::WebContents* const web_contents =
+      app_browser->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(content::WaitForLoadStop(web_contents));
+  EXPECT_EQ(app_title, app_browser->GetWindowTitleForCurrentTab(false));
+}
+
+class WebAppBrowserTest_HideOrigin : public WebAppBrowserTest {
+ public:
+  WebAppBrowserTest_HideOrigin() {
+    scoped_feature_list_.InitAndEnableFeature(features::kHideWebAppOriginText);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// WebApps should not have origin text with this feature on.
+IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_HideOrigin, OriginTextRemoved) {
+  const GURL app_url = GetInstallableAppURL();
+  const AppId app_id = InstallPWA(app_url);
+  Browser* const app_browser = LaunchWebAppBrowserAndWait(app_id);
+  EXPECT_FALSE(app_browser->app_controller()->HasTitlebarAppOriginText());
+}
+
 // Check that a subframe on a regular web page can navigate to a URL that
 // redirects to a web app.  https://crbug.com/721949.
 IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, SubframeRedirectsToWebApp) {
diff --git a/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc b/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
index 28e5a51..7d7ef3a 100644
--- a/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
+++ b/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
@@ -20,10 +20,13 @@
 #include "device/fido/authenticator_data.h"
 #include "device/fido/authenticator_get_assertion_response.h"
 #include "device/fido/cable/cable_discovery_data.h"
+#include "device/fido/fido_request_handler_base.h"
 #include "device/fido/public_key_credential_user_entity.h"
 
 class AuthenticatorDialogTest : public DialogBrowserTest {
  public:
+  using CollectPINMode =
+      device::FidoRequestHandlerBase::Observer::CollectPINOptions::Mode;
   AuthenticatorDialogTest() = default;
 
   // DialogBrowserTest:
@@ -41,7 +44,7 @@
         AuthenticatorTransport::kInternal,
         AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy};
     model->set_cable_transport_info(/*cable_extension_provided=*/true,
-                                    /*have_paired_phones=*/false,
+                                    /*has_paired_phones=*/false,
                                     "fido://qrcode");
     model->StartFlow(std::move(transport_availability), base::nullopt);
 
@@ -82,19 +85,23 @@
       model->SetCurrentStep(
           AuthenticatorRequestDialogModel::Step::kCableV2QRCode);
     } else if (name == "set_pin") {
-      model->CollectPIN(6, base::nullopt,
+      model->CollectPIN(CollectPINMode::kSet, 6, 0,
                         base::BindOnce([](std::string pin) {}));
     } else if (name == "get_pin") {
-      model->CollectPIN(6, 8, base::BindOnce([](std::string pin) {}));
+      model->CollectPIN(CollectPINMode::kChallenge, 6, 8,
+                        base::BindOnce([](std::string pin) {}));
     } else if (name == "get_pin_two_tries_remaining") {
       model->set_has_attempted_pin_entry_for_testing();
-      model->CollectPIN(6, 2, base::BindOnce([](std::string pin) {}));
+      model->CollectPIN(CollectPINMode::kChallenge, 6, 2,
+                        base::BindOnce([](std::string pin) {}));
     } else if (name == "get_pin_one_try_remaining") {
       model->set_has_attempted_pin_entry_for_testing();
-      model->CollectPIN(6, 1, base::BindOnce([](std::string pin) {}));
+      model->CollectPIN(CollectPINMode::kChallenge, 6, 1,
+                        base::BindOnce([](std::string pin) {}));
     } else if (name == "get_pin_fallback") {
       model->set_internal_uv_locked();
-      model->CollectPIN(6, 8, base::BindOnce([](std::string pin) {}));
+      model->CollectPIN(CollectPINMode::kChallenge, 6, 8,
+                        base::BindOnce([](std::string pin) {}));
     } else if (name == "inline_bio_enrollment") {
       model->StartInlineBioEnrollment(base::DoNothing());
       timer_.Start(
@@ -115,6 +122,9 @@
       model->OnRetryUserVerification(2);
     } else if (name == "retry_uv_one_try_remaining") {
       model->OnRetryUserVerification(1);
+    } else if (name == "force_pin_change") {
+      model->CollectPIN(CollectPINMode::kChange, 6, 0,
+                        base::BindOnce([](std::string pin) {}));
     } else if (name == "second_tap") {
       model->SetCurrentStep(
           AuthenticatorRequestDialogModel::Step::kClientPinTapAgain);
@@ -185,6 +195,10 @@
   ShowAndVerifyUi();
 }
 
+IN_PROC_BROWSER_TEST_F(AuthenticatorDialogTest, InvokeUi_force_pin_change) {
+  ShowAndVerifyUi();
+}
+
 IN_PROC_BROWSER_TEST_F(AuthenticatorDialogTest, InvokeUi_transports) {
   ShowAndVerifyUi();
 }
diff --git a/chrome/browser/ui/webauthn/sheet_models.cc b/chrome/browser/ui/webauthn/sheet_models.cc
index d6c01027..194b42d 100644
--- a/chrome/browser/ui/webauthn/sheet_models.cc
+++ b/chrome/browser/ui/webauthn/sheet_models.cc
@@ -663,7 +663,7 @@
     return;
   }
 
-  DCHECK(mode_ == AuthenticatorClientPinEntrySheetModel::Mode::kPinSetup);
+  DCHECK(mode_ == Mode::kPinSetup || mode_ == Mode::kPinChange);
   error_ = l10n_util::GetStringUTF16(IDS_WEBAUTHN_PIN_SETUP_ERROR_FAILED);
 }
 
@@ -677,7 +677,7 @@
 
 void AuthenticatorClientPinEntrySheetModel::SetPinConfirmation(
     base::string16 pin_confirmation) {
-  DCHECK(mode_ == AuthenticatorClientPinEntrySheetModel::Mode::kPinSetup);
+  DCHECK(mode_ == Mode::kPinSetup || mode_ == Mode::kPinChange);
   pin_confirmation_ = std::move(pin_confirmation);
 }
 
@@ -694,10 +694,14 @@
 
 base::string16 AuthenticatorClientPinEntrySheetModel::GetStepDescription()
     const {
-  return l10n_util::GetStringUTF16(
-      mode_ == AuthenticatorClientPinEntrySheetModel::Mode::kPinEntry
-          ? IDS_WEBAUTHN_PIN_ENTRY_DESCRIPTION
-          : IDS_WEBAUTHN_PIN_SETUP_DESCRIPTION);
+  switch (mode_) {
+    case Mode::kPinChange:
+      return l10n_util::GetStringUTF16(IDS_WEBAUTHN_FORCE_PIN_CHANGE);
+    case Mode::kPinEntry:
+      return l10n_util::GetStringUTF16(IDS_WEBAUTHN_PIN_ENTRY_DESCRIPTION);
+    case Mode::kPinSetup:
+      return l10n_util::GetStringUTF16(IDS_WEBAUTHN_PIN_SETUP_DESCRIPTION);
+  }
 }
 
 base::string16 AuthenticatorClientPinEntrySheetModel::GetError() const {
@@ -723,7 +727,7 @@
 }
 
 void AuthenticatorClientPinEntrySheetModel::OnAccept() {
-  if (mode_ == AuthenticatorClientPinEntrySheetModel::Mode::kPinSetup) {
+  if (mode_ == Mode::kPinSetup || mode_ == Mode::kPinChange) {
     // Validate a new PIN.
     base::Optional<base::string16> error;
     if (!pin_code_.empty() && !IsValidUTF16(pin_code_)) {
diff --git a/chrome/browser/ui/webauthn/sheet_models.h b/chrome/browser/ui/webauthn/sheet_models.h
index 60827807..ace1ab8 100644
--- a/chrome/browser/ui/webauthn/sheet_models.h
+++ b/chrome/browser/ui/webauthn/sheet_models.h
@@ -292,9 +292,9 @@
 class AuthenticatorClientPinEntrySheetModel
     : public AuthenticatorSheetModelBase {
  public:
-  // Indicates whether the view should accommodate setting up a new PIN or
-  // entering an existing one.
-  enum class Mode { kPinEntry, kPinSetup };
+  // Indicates whether the view should accommodate changing an existing PIN,
+  // setting up a new PIN or entering an existing one.
+  enum class Mode { kPinChange, kPinEntry, kPinSetup };
   AuthenticatorClientPinEntrySheetModel(
       AuthenticatorRequestDialogModel* dialog_model,
       Mode mode);
@@ -425,7 +425,7 @@
 class AuthenticatorResidentCredentialConfirmationSheetView
     : public AuthenticatorSheetModelBase {
  public:
-  AuthenticatorResidentCredentialConfirmationSheetView(
+  explicit AuthenticatorResidentCredentialConfirmationSheetView(
       AuthenticatorRequestDialogModel* dialog_model);
   ~AuthenticatorResidentCredentialConfirmationSheetView() override;
 
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
index 8f98687c..81b8216d 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
@@ -129,6 +129,7 @@
       {"nameField", IDS_NTP_CUSTOM_LINKS_NAME},
       {"restoreDefaultLinks", IDS_NTP_CONFIRM_MSG_RESTORE_DEFAULTS},
       {"restoreThumbnailsShort", IDS_NEW_TAB_RESTORE_THUMBNAILS_SHORT_LINK},
+      {"shortcutAlreadyExists", IDS_NTP_CUSTOM_LINKS_ALREADY_EXISTS},
       {"urlField", IDS_NTP_CUSTOM_LINKS_URL},
 
       // Customize button and dialog.
diff --git a/chrome/browser/webapps/DIR_METADATA b/chrome/browser/webapps/DIR_METADATA
new file mode 100644
index 0000000..11597323
--- /dev/null
+++ b/chrome/browser/webapps/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>WebAppInstalls"
+}
+team_email: "pwa-dev@chromium.org"
diff --git a/chrome/browser/webapps/OWNERS b/chrome/browser/webapps/OWNERS
new file mode 100644
index 0000000..5a4b9c1
--- /dev/null
+++ b/chrome/browser/webapps/OWNERS
@@ -0,0 +1 @@
+file://components/webapps/OWNERS
diff --git a/chrome/browser/webapps/chrome_webapps_client.cc b/chrome/browser/webapps/chrome_webapps_client.cc
new file mode 100644
index 0000000..3fab64fa
--- /dev/null
+++ b/chrome/browser/webapps/chrome_webapps_client.cc
@@ -0,0 +1,24 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/webapps/chrome_webapps_client.h"
+
+#include "chrome/browser/ssl/security_state_tab_helper.h"
+
+namespace webapps {
+
+// static
+ChromeWebappsClient* ChromeWebappsClient::GetInstance() {
+  static base::NoDestructor<ChromeWebappsClient> instance;
+  return instance.get();
+}
+
+security_state::SecurityLevel
+ChromeWebappsClient::GetSecurityLevelForWebContents(
+    content::WebContents* web_contents) {
+  return SecurityStateTabHelper::FromWebContents(web_contents)
+      ->GetSecurityLevel();
+}
+
+}  // namespace webapps
diff --git a/chrome/browser/webapps/chrome_webapps_client.h b/chrome/browser/webapps/chrome_webapps_client.h
new file mode 100644
index 0000000..48b011e
--- /dev/null
+++ b/chrome/browser/webapps/chrome_webapps_client.h
@@ -0,0 +1,32 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEBAPPS_CHROME_WEBAPPS_CLIENT_H_
+#define CHROME_BROWSER_WEBAPPS_CHROME_WEBAPPS_CLIENT_H_
+
+#include "base/no_destructor.h"
+#include "components/webapps/webapps_client.h"
+
+namespace webapps {
+
+class ChromeWebappsClient : public webapps::WebappsClient {
+ public:
+  ChromeWebappsClient(const ChromeWebappsClient&) = delete;
+  ChromeWebappsClient& operator=(const ChromeWebappsClient&) = delete;
+
+  static ChromeWebappsClient* GetInstance();
+
+  // webapps::WebappsClient:
+  security_state::SecurityLevel GetSecurityLevelForWebContents(
+      content::WebContents* web_contents) override;
+
+ private:
+  friend base::NoDestructor<ChromeWebappsClient>;
+
+  ChromeWebappsClient() = default;
+};
+
+}  // namespace webapps
+
+#endif  // CHROME_BROWSER_WEBAPPS_CHROME_WEBAPPS_CLIENT_H_
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.cc b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
index bd8efc65..c951de5 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
@@ -18,6 +18,9 @@
 
 namespace {
 
+using CollectPINMode =
+    device::FidoRequestHandlerBase::Observer::CollectPINOptions::Mode;
+
 // Attempts to auto-select the most likely transport that will be used to
 // service this request, or returns base::nullopt if unsure.
 base::Optional<device::FidoTransportProtocol> SelectMostLikelyTransport(
@@ -536,17 +539,24 @@
 }
 
 void AuthenticatorRequestDialogModel::CollectPIN(
+    CollectPINMode mode,
     uint32_t min_pin_length,
-    base::Optional<int> attempts,
+    int attempts,
     base::OnceCallback<void(std::string)> provide_pin_cb) {
   pin_callback_ = std::move(provide_pin_cb);
   min_pin_length_ = min_pin_length;
   Step new_step;
-  if (attempts) {
-    pin_attempts_ = attempts;
-    new_step = Step::kClientPinEntry;
-  } else {
-    new_step = Step::kClientPinSetup;
+  switch (mode) {
+    case CollectPINMode::kChallenge:
+      pin_attempts_ = attempts;
+      new_step = Step::kClientPinEntry;
+      break;
+    case CollectPINMode::kChange:
+      new_step = Step::kClientPinChange;
+      break;
+    case CollectPINMode::kSet:
+      new_step = Step::kClientPinSetup;
+      break;
   }
   if (new_step != current_step_) {
     ephemeral_state_.has_attempted_pin_entry_ = false;
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.h b/chrome/browser/webauthn/authenticator_request_dialog_model.h
index 760bfb35..28294bf 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.h
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.h
@@ -82,6 +82,7 @@
     kCableV2QRCode,
 
     // Authenticator Client PIN.
+    kClientPinChange,
     kClientPinEntry,
     kClientPinSetup,
     kClientPinTapAgain,
@@ -365,9 +366,11 @@
 
   const std::string& cable_qr_string() const { return *cable_qr_string_; }
 
-  void CollectPIN(uint32_t min_pin_length,
-                  base::Optional<int> attempts,
-                  base::OnceCallback<void(std::string)> provide_pin_cb);
+  void CollectPIN(
+      device::FidoRequestHandlerBase::Observer::CollectPINOptions::Mode mode,
+      uint32_t min_pin_length,
+      int attempts,
+      base::OnceCallback<void(std::string)> provide_pin_cb);
   bool has_attempted_pin_entry() const {
     return ephemeral_state_.has_attempted_pin_entry_;
   }
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
index 1ceedfd..aeb99ff0 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -575,14 +575,13 @@
 }
 
 void ChromeAuthenticatorRequestDelegate::CollectPIN(
-    uint32_t min_pin_length,
-    base::Optional<int> attempts,
+    CollectPINOptions options,
     base::OnceCallback<void(std::string)> provide_pin_cb) {
   if (!weak_dialog_model_)
     return;
 
-  weak_dialog_model_->CollectPIN(min_pin_length, attempts,
-                                 std::move(provide_pin_cb));
+  weak_dialog_model_->CollectPIN(options.mode, options.min_pin_length,
+                                 options.attempts, std::move(provide_pin_cb));
 }
 
 void ChromeAuthenticatorRequestDelegate::StartBioEnrollment(
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
index b5aef20..e575d1f9 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
@@ -110,8 +110,7 @@
   void BluetoothAdapterPowerChanged(bool is_powered_on) override;
   bool SupportsPIN() const override;
   void CollectPIN(
-      uint32_t min_pin_length,
-      base::Optional<int> attempts,
+      CollectPINOptions options,
       base::OnceCallback<void(std::string)> provide_pin_cb) override;
   void StartBioEnrollment(base::OnceClosure next_callback) override;
   void OnSampleCollected(int bio_samples_remaining) override;
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index fe6c03c..5222e7d 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1607018334-f670cab7a0d67beb5d9952b6762b75fa44bc4bec.profdata
+chrome-linux-master-1607039886-9857a5090b09116b4b309953eec41db8862dfe90.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index e3311b1..e2b48f38 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1607018334-4ec258faf10b8c54ec4574a66b7b864fdc99dca8.profdata
+chrome-mac-master-1607039886-1ddd5c45cae9e9c7a03307d574bbe9f5985fa593.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 4b08e7b8..d056c96 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1607007593-3407e023275e887982890e083190cec03a46fa25.profdata
+chrome-win64-master-1607018334-2342e7b4fc523afed7119425e6663fe86ee0646f.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 08a2e2c4..bf75ccc 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -516,6 +516,10 @@
 const base::Feature kHeavyAdPrivacyMitigations{
     "HeavyAdPrivacyMitigations", base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Hides the origin text from showing up briefly in WebApp windows.
+const base::Feature kHideWebAppOriginText{"HideWebAppOriginText",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+
 #if defined(OS_MAC)
 const base::Feature kImmersiveFullscreen{"ImmersiveFullscreen",
                                          base::FEATURE_DISABLED_BY_DEFAULT};
@@ -695,6 +699,9 @@
     "PredictivePrefetchingAllowedOnAllConnectionTypes",
     base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kPrefixWebAppWindowsWithAppName{
+    "PrefixWebAppWindowsWithAppName", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Allows Chrome to do preconnect when prerender fails.
 const base::Feature kPrerenderFallbackToPreconnect{
     "PrerenderFallbackToPreconnect", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index e57e3ce0..9e44bda2 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -340,6 +340,9 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kHeavyAdPrivacyMitigations;
 
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kHideWebAppOriginText;
+
 #if defined(OS_MAC)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kImmersiveFullscreen;
@@ -463,6 +466,9 @@
 extern const base::Feature kPredictivePrefetchingAllowedOnAllConnectionTypes;
 
 COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kPrefixWebAppWindowsWithAppName;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kPrerenderFallbackToPreconnect;
 
 COMPONENT_EXPORT(CHROME_FEATURES)
diff --git a/chrome/common/extensions/api/autotest_private.idl b/chrome/common/extensions/api/autotest_private.idl
index e1c6ff7..16617ad 100644
--- a/chrome/common/extensions/api/autotest_private.idl
+++ b/chrome/common/extensions/api/autotest_private.idl
@@ -60,7 +60,8 @@
     DisabledByPolicy,
     DisabledByUser,
     Terminated,
-    UninstalledByUser
+    UninstalledByUser,
+    Removed
   };
 
   // A subset of Window State types in ash::WindowStateType. We may add more
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 0fcadb8..491d91d 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1382,6 +1382,7 @@
       "../browser/tracing/chrome_tracing_delegate_browsertest.cc",
       "../browser/translate/language_detection_service_browsertest.cc",
       "../browser/translate/translate_manager_browsertest.cc",
+      "../browser/translate/translate_model_service_browsertest.cc",
       "../browser/ui/ask_google_for_suggestions_dialog_browsertest.cc",
       "../browser/ui/autofill/payments/card_unmask_prompt_view_browsertest.cc",
       "../browser/ui/autofill/payments/card_unmask_prompt_view_tester.h",
@@ -4995,7 +4996,6 @@
       "../browser/ui/app_list/search/search_result_ranker/app_search_result_ranker_unittest.cc",
       "../browser/ui/app_list/search/search_result_ranker/chip_ranker_unittest.cc",
       "../browser/ui/app_list/search/search_result_ranker/frecency_store_unittest.cc",
-      "../browser/ui/app_list/search/search_result_ranker/ml_app_rank_provider_unittest.cc",
       "../browser/ui/app_list/search/search_result_ranker/ranking_item_util_unittest.cc",
       "../browser/ui/app_list/search/search_result_ranker/recurrence_predictor_unittest.cc",
       "../browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc",
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index 7b0bbf5f..bf7b151e 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -86,6 +86,7 @@
 #include "components/prefs/pref_notifier_impl.h"
 #include "components/prefs/testing_pref_store.h"
 #include "components/security_interstitials/content/stateful_ssl_host_state_delegate.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/signin/public/identity_manager/identity_test_utils.h"
 #include "components/sync/test/model/fake_sync_change_processor.h"
 #include "components/sync/test/model/sync_error_factory_mock.h"
@@ -940,6 +941,12 @@
   return nullptr;
 }
 
+bool TestingProfile::IsSignedIn() {
+  signin::IdentityManager* identity_manager =
+      IdentityManagerFactory::GetForProfile(this);
+  return identity_manager && identity_manager->HasPrimaryAccount();
+}
+
 storage::SpecialStoragePolicy* TestingProfile::GetSpecialStoragePolicy() {
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   return GetExtensionSpecialStoragePolicy();
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h
index c9dab3fe..fc9f550 100644
--- a/chrome/test/base/testing_profile.h
+++ b/chrome/test/base/testing_profile.h
@@ -422,6 +422,9 @@
   // ref only for right type, lifecycle is managed by prefs_
   sync_preferences::TestingPrefServiceSyncable* testing_prefs_;
 
+  // Profile implementation.
+  bool IsSignedIn() override;
+
  private:
   // Common initialization between the two constructors.
   void Init();
diff --git a/chrome/test/data/prerender/prerender_events_common.js b/chrome/test/data/prerender/prerender_events_common.js
index 8416e170..9e75f7b 100644
--- a/chrome/test/data/prerender/prerender_events_common.js
+++ b/chrome/test/data/prerender/prerender_events_common.js
@@ -7,86 +7,11 @@
 
 // TODO(gavinp): Put more common loader logic in here.
 
-// Currently only errors with the ordering of Prerender events are caught.
-var hadPrerenderEventErrors = false;
-
-var receivedPrerenderEvents = {
-  'webkitprerenderstart': [],
-  'webkitprerenderdomcontentloaded': [],
-  'webkitprerenderload': [],
-  'webkitprerenderstop': [],
-}
-// A list of callbacks to be called on every prerender event. Each callback
-// returns true if it should never be called again, or false to remain in the
-// list and be called on future events. These are used to implement
-// WaitForPrerenderEventCount.
-var prerenderEventCallbacks = [];
-
-function GetPrerenderEventCount(index, type) {
-  return receivedPrerenderEvents[type][index] || 0;
-}
-
-function PrerenderEventHandler(index, ev) {
-  // Check for errors.
-  if (ev.type == 'webkitprerenderstart') {
-    // No event may precede start.
-    if (GetPrerenderEventCount(index, 'webkitprerenderstart') ||
-        GetPrerenderEventCount(index, 'webkitprerenderdomcontentloaded') ||
-        GetPrerenderEventCount(index, 'webkitprerenderload') ||
-        GetPrerenderEventCount(index, 'webkitprerenderstop')) {
-      hadPrerenderEventErrors = true;
-    }
-  } else {
-    // There may be multiple load or domcontentloaded events, but they must not
-    // come after start and must come before stop. And there may be at most one
-    // start. Note that stop may be delivered without any load events.
-    if (!GetPrerenderEventCount(index, 'webkitprerenderstart') ||
-        GetPrerenderEventCount(index, 'webkitprerenderstop')) {
-      hadPrerenderEventErrors = true;
-    }
-  }
-
-  // Update count.
-  receivedPrerenderEvents[ev.type][index] =
-      (receivedPrerenderEvents[ev.type][index] || 0) + 1;
-
-  // Run all callbacks. Remove the ones that are done.
-  prerenderEventCallbacks = prerenderEventCallbacks.filter(function(callback) {
-    return !callback();
-  });
-}
-
-// Calls |callback| when at least |count| instances of event |type| have been
-// observed for prerender |index|.
-function WaitForPrerenderEventCount(index, type, count, callback) {
-  var checkCount = function() {
-    if (GetPrerenderEventCount(index, type) >= count) {
-      callback();
-      return true;
-    }
-    return false;
-  };
-  if (!checkCount())
-    prerenderEventCallbacks.push(checkCount);
-}
-
-function AddEventHandlersToLinkElement(link, index) {
-  link.addEventListener('webkitprerenderstart',
-                        PrerenderEventHandler.bind(null, index), false);
-  link.addEventListener('webkitprerenderdomcontentloaded',
-                        PrerenderEventHandler.bind(null, index), false);
-  link.addEventListener('webkitprerenderload',
-                        PrerenderEventHandler.bind(null, index), false);
-  link.addEventListener('webkitprerenderstop',
-                        PrerenderEventHandler.bind(null, index), false);
-}
-
 function AddPrerender(url, index) {
   var link = document.createElement('link');
   link.id = 'prerenderElement' + index;
   link.rel = 'prerender';
   link.href = url;
-  AddEventHandlersToLinkElement(link, index);
   document.body.appendChild(link);
   return link;
 }
diff --git a/chrome/test/data/webui/new_tab_page/most_visited_test.js b/chrome/test/data/webui/new_tab_page/most_visited_test.js
index b489bfb..7ead614 100644
--- a/chrome/test/data/webui/new_tab_page/most_visited_test.js
+++ b/chrome/test/data/webui/new_tab_page/most_visited_test.js
@@ -101,6 +101,10 @@
     updateScreenWidth(true, true);
   }
 
+  function leaveUrlInput() {
+    mostVisited.$.dialogInputUrl.dispatchEvent(new Event('blur'));
+  }
+
   suiteSetup(() => {
     loadTimeData.overrideValues({
       linkRemovedMsg: '',
@@ -464,7 +468,7 @@
       assertTrue(saveButton.disabled);
       inputUrl.value = 'chrome://url';
       assertFalse(inputUrl.invalid);
-      mostVisited.$.dialogInputUrl.dispatchEvent(new Event('blur'));
+      leaveUrlInput();
       assertTrue(inputUrl.invalid);
       assertTrue(saveButton.disabled);
     });
@@ -472,11 +476,30 @@
     test('invalid cleared when text entered', () => {
       inputUrl.value = '%';
       assertFalse(inputUrl.invalid);
-      mostVisited.$.dialogInputUrl.dispatchEvent(new Event('blur'));
+      leaveUrlInput();
       assertTrue(inputUrl.invalid);
+      assertEquals('Type a valid URL', inputUrl.errorMessage);
       inputUrl.value = '';
       assertFalse(inputUrl.invalid);
     });
+
+    test('shortcut already exists', async () => {
+      await addTiles(2);
+      inputUrl.value = 'b';
+      assertFalse(inputUrl.invalid);
+      leaveUrlInput();
+      assertTrue(inputUrl.invalid);
+      assertEquals('Shortcut already exists', inputUrl.errorMessage);
+      inputUrl.value = 'c';
+      assertFalse(inputUrl.invalid);
+      leaveUrlInput();
+      assertFalse(inputUrl.invalid);
+      inputUrl.value = '%';
+      assertFalse(inputUrl.invalid);
+      leaveUrlInput();
+      assertTrue(inputUrl.invalid);
+      assertEquals('Type a valid URL', inputUrl.errorMessage);
+    });
   });
 
   test('open edit dialog', async () => {
@@ -574,6 +597,20 @@
       const [url, newUrl, newTitle] = await updateCalled;
       assertEquals('https://updated-url/', newUrl.url);
     });
+
+    test('shortcut already exists', async () => {
+      inputUrl.value = 'a';
+      assertFalse(inputUrl.invalid);
+      leaveUrlInput();
+      assertTrue(inputUrl.invalid);
+      assertEquals('Shortcut already exists', inputUrl.errorMessage);
+      // The shortcut being editted has a URL of https://b/. Entering the same
+      // URL is not an error.
+      inputUrl.value = 'b';
+      assertFalse(inputUrl.invalid);
+      leaveUrlInput();
+      assertFalse(inputUrl.invalid);
+    });
   });
 
   test('remove with action menu', async () => {
diff --git a/chrome/test/data/webui/new_tab_page/realbox_test.js b/chrome/test/data/webui/new_tab_page/realbox_test.js
index e3c48e73..fb59ebd 100644
--- a/chrome/test/data/webui/new_tab_page/realbox_test.js
+++ b/chrome/test/data/webui/new_tab_page/realbox_test.js
@@ -248,9 +248,6 @@
     assertStyle(realbox, '--search-box-results-bg', '');
     assertStyle(realbox, '--search-box-text', '');
     assertStyle(realbox, '--search-box-icon', '');
-    assertStyle(matches, '--search-box-icon-bg-focused', '');
-    assertStyle(matches, '--search-box-icon-bg-hovered', '');
-    assertStyle(matches, '--search-box-icon-selected', '');
     assertStyle(matches, '--search-box-icon', '');
     assertStyle(matches, '--search-box-results-bg-hovered', '');
     assertStyle(matches, '--search-box-results-bg-selected', '');
@@ -271,9 +268,6 @@
     assertStyle(realbox, '--search-box-results-bg', 'rgba(0, 0, 4, 1)');
     assertStyle(realbox, '--search-box-text', 'rgba(0, 0, 13, 1)');
     assertStyle(realbox, '--search-box-icon', 'rgba(0, 0, 1, 1)');
-    assertStyle(matches, '--search-box-icon-bg-focused', 'rgba(0, 0, 2, 0.32)');
-    assertStyle(matches, '--search-box-icon-bg-hovered', 'rgba(0, 0, 1, 0.16)');
-    assertStyle(matches, '--search-box-icon-selected', 'rgba(0, 0, 2, 1)');
     assertStyle(matches, '--search-box-icon', 'rgba(0, 0, 1, 1)');
     assertStyle(matches, '--search-box-results-bg-hovered', 'rgba(0, 0, 5, 1)');
     assertStyle(
@@ -2061,17 +2055,22 @@
     assertTrue(window.getComputedStyle(headerEl).display !== 'none');
     assertEquals('Recommended for you', headerEl.textContent.trim());
     const toggleButtonEl =
-        realbox.$.matches.shadowRoot.querySelectorAll('ntp-realbox-button')[0];
+        realbox.$.matches.shadowRoot.querySelectorAll('cr-icon-button')[0];
     assertTrue(window.getComputedStyle(toggleButtonEl).display !== 'none');
 
     // Make the second match visible by pressing 'Space' on the toggle button.
-    const enter = new KeyboardEvent('keydown', {
+    toggleButtonEl.dispatchEvent(new KeyboardEvent('keydown', {
       bubbles: true,
       cancelable: true,
       composed: true,  // So it propagates across shadow DOM boundary.
       key: ' ',
-    });
-    toggleButtonEl.dispatchEvent(enter);
+    }));
+    toggleButtonEl.dispatchEvent(new KeyboardEvent('keyup', {
+      bubbles: true,
+      cancelable: true,
+      composed: true,  // So it propagates across shadow DOM boundary.
+      key: ' ',
+    }));
 
     await testProxy.handler.whenCalled('toggleSuggestionGroupIdVisibility')
         .then((args) => {
diff --git a/chrome/test/data/webui/settings/chromeos/internet_page_tests.js b/chrome/test/data/webui/settings/chromeos/internet_page_tests.js
index f51997c..198a7764 100644
--- a/chrome/test/data/webui/settings/chromeos/internet_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/internet_page_tests.js
@@ -278,7 +278,7 @@
           'Toggle mobile on/off should be focused for settingId=13.');
     });
 
-    test('Show rename profile dialog', async function() {
+    test('Show rename esim profile dialog', async function() {
       eSimManagerRemote.addEuiccForTest(1);
       await flushAsync();
 
@@ -293,6 +293,22 @@
       renameDialog = internetPage.$$('#esimRenameDialog');
       assertTrue(!!renameDialog);
     });
+
+    test('Show remove esim profile dialog', async function() {
+      eSimManagerRemote.addEuiccForTest(1);
+      await flushAsync();
+
+      let removeDialog = internetPage.$$('#esimRemoveProfileDialog');
+      assertFalse(!!removeDialog);
+
+      const event = new CustomEvent(
+          'show-esim-remove-profile-dialog', {detail: {iccid: '1'}});
+      internetPage.dispatchEvent(event);
+
+      await flushAsync();
+      removeDialog = internetPage.$$('#esimRemoveProfileDialog');
+      assertTrue(!!removeDialog);
+    });
   });
 
   // TODO(stevenjb): Figure out a way to reliably test navigation. Currently
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index 048dd36..afda68c 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -270,7 +270,6 @@
     tast_disabled_tests = [
       # crbug.com/1115622
       "ui.ChromeLoginGAIA",
-      "inputs.VirtualKeyboardOOBE.stable",
 
       # crbug.com/1097630
       "security.OpenFDs",
@@ -318,13 +317,6 @@
       "printer.PinPrintLexmark.no_pin",
       "printer.PinPrintLexmark.pin",
 
-      # crbug.com/1147607
-      "inputs.VirtualKeyboardAccessibility.stable",
-      "inputs.VirtualKeyboardChangeInput.stable",
-      "inputs.VirtualKeyboardDeadKeys.french_stable",
-      "inputs.VirtualKeyboardTypingApps.stable",
-      "inputs.VirtualKeyboardTypingBrowser.stable",
-
       # crbug.com/1148036
       "ui.ExistingUserLogin",
       "ui.SigninProfileExtension",
diff --git a/chromeos/components/diagnostics_ui/resources/diagnostics_app.html b/chromeos/components/diagnostics_ui/resources/diagnostics_app.html
index 82b42260..41d3325 100644
--- a/chromeos/components/diagnostics_ui/resources/diagnostics_app.html
+++ b/chromeos/components/diagnostics_ui/resources/diagnostics_app.html
@@ -1,16 +1,28 @@
 <style include="cr-shared-style diagnostics-shared diagnostics-fonts">
+  .card-width {
+    width: 100%;
+  }
+
   .diagonstics-cards-container {
     align-items: center;
     display: flex;
     flex-direction: column;
+    padding-inline: var(--container-padding);
+    width: var(--content-container-width);
   }
 
   #diagnosticsContainer {
-    --cr-centered-card-max-width: 820px;
+    align-items: center;
+    box-sizing: border-box;
+    display: flex;
+    flex-direction: column;
+    height: inherit;
+    position: relative;
   }
 
   #header {
-   @apply --diagnostics-header-font;
+    @apply --diagnostics-header-font;
+    align-self: flex-start;
     margin-bottom: 10px;
   }
 
@@ -31,23 +43,29 @@
     padding: 5px;
   }
 </style>
-<div id="diagnosticsContainer"class="cr-centered-card-container">
+<div id="diagnosticsContainer">
   <div id="header">[[i18n('diagnosticsTitle')]]</div>
   <div class="overview-container">
     <overview-card id="overviewCard"></overview-card>
   </div>
   <div class="diagonstics-cards-container">
     <template is="dom-if" if="[[showBatteryStatusCard_]]" restamp>
-      <battery-status-card id="batteryStatusCard"
-        is-test-running="{{isTestRunning}}">
-      </battery-status-card>
+      <div class="card-width">
+        <battery-status-card id="batteryStatusCard"
+          is-test-running="{{isTestRunning}}">
+        </battery-status-card>
+      </div>
     </template>
-    <cpu-card id="cpuCard"
-      is-test-running="{{isTestRunning}}">
-    </cpu-card>
-    <memory-card id="memoryCard"
-      is-test-running="{{isTestRunning}}">
-    </memory-card>
+    <div class="card-width">
+      <cpu-card id="cpuCard"
+        is-test-running="{{isTestRunning}}">
+      </cpu-card>
+    </div>
+    <div class="card-width">
+      <memory-card id="memoryCard"
+        is-test-running="{{isTestRunning}}">
+      </memory-card>
+    </div>
   </div>
   <div class="session-log-container">
     <cr-button class="session-log-button">
diff --git a/chromeos/components/diagnostics_ui/resources/diagnostics_card.html b/chromeos/components/diagnostics_ui/resources/diagnostics_card.html
index d585a3d..95e310f4 100644
--- a/chromeos/components/diagnostics_ui/resources/diagnostics_card.html
+++ b/chromeos/components/diagnostics_ui/resources/diagnostics_card.html
@@ -22,7 +22,6 @@
     display: flex;
     flex-direction: column;
     margin-top: 12px;
-    width: 650px;
   }
 
   .card-header {
diff --git a/chromeos/components/diagnostics_ui/resources/diagnostics_shared_css.html b/chromeos/components/diagnostics_ui/resources/diagnostics_shared_css.html
index ad288b0..5ec1273 100644
--- a/chromeos/components/diagnostics_ui/resources/diagnostics_shared_css.html
+++ b/chromeos/components/diagnostics_ui/resources/diagnostics_shared_css.html
@@ -19,6 +19,46 @@
       padding-inline-start: 20px;
       position: relative;
       top: 12%;
-  }
+    }
+
+    @media (min-width:600px) {
+      :host {
+        --container-padding: 24px;
+        --content-container-width: 552px;
+        --chart-width: 452px;
+        }
+    }
+
+    @media (min-width:768px) {
+      :host {
+        --container-padding: 64px;
+        --content-container-width: 640px;
+        --chart-width: 540px;
+        }
+    }
+
+    @media (min-width:960px) {
+      :host {
+        --container-padding: 160px;
+        --content-container-width: 640px;
+        --chart-width: 540px;
+      }
+    }
+
+    @media (min-width:1280px) {
+      :host {
+        --container-padding: 160px;
+        --content-container-width: 680px;
+        --chart-width: 580px;
+      }
+    }
+
+    @media (min-width:1440px) {
+      :host {
+        --container-padding: 360px;
+        --content-container-width: 720px;
+        --chart-width: 620px;
+      }
+    }
   </style>
 </template>
diff --git a/chromeos/components/diagnostics_ui/resources/realtime_cpu_chart.js b/chromeos/components/diagnostics_ui/resources/realtime_cpu_chart.js
index 249f9e70..99cdb77 100644
--- a/chromeos/components/diagnostics_ui/resources/realtime_cpu_chart.js
+++ b/chromeos/components/diagnostics_ui/resources/realtime_cpu_chart.js
@@ -138,6 +138,8 @@
     }
   },
 
+  observers: ['setScaling_(graphWidth_)'],
+
   /** @override */
   created() {
     // Initialize the data array with data outside the chart boundary.
@@ -150,6 +152,19 @@
   ready() {
     this.setScaling_();
     this.initializeChart_();
+    window.addEventListener('resize', (e) => this.updateChartWidth_());
+
+    // Set the initial chart width.
+    this.updateChartWidth_();
+  },
+
+  /** @private */
+  updateChartWidth_() {
+    // TODO(michaelcheco): Enforce 600px as the minimum window size.
+
+    // parseFloat() is used to convert the string returned by
+    // getComputedStyleValue() into a number ("642px" --> 642).
+    this.width_ = parseFloat(this.getComputedStyleValue('--chart-width'));
   },
 
   /**
diff --git a/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc b/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc
index 7f0b4fb..61700aa2 100644
--- a/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc
+++ b/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc
@@ -218,11 +218,6 @@
               HttpsLatency,
               (NetworkDiagnosticsRoutines::HttpsLatencyCallback),
               (override));
-  MOCK_METHOD(void,
-              VideoConferencing,
-              (const base::Optional<std::string>&,
-               NetworkDiagnosticsRoutines::VideoConferencingCallback),
-              (override));
 
   mojo::PendingRemote<NetworkDiagnosticsRoutines> pending_remote() {
     if (receiver_.is_bound()) {
diff --git a/chromeos/services/machine_learning/public/mojom/model.mojom b/chromeos/services/machine_learning/public/mojom/model.mojom
index 3f2b24c2..59dcc15 100644
--- a/chromeos/services/machine_learning/public/mojom/model.mojom
+++ b/chromeos/services/machine_learning/public/mojom/model.mojom
@@ -34,7 +34,7 @@
   // The Smart Dim (20190221) ML model.
   SMART_DIM_20190221 = 3,
   // The Top Cat (20190722) ML model.
-  TOP_CAT_20190722 = 4,
+  UNSUPPORTED_TOP_CAT_20190722 = 4,
   // The Smart Dim (20190521) ML model.
   SMART_DIM_20190521 = 5,
   // The Search Ranker (20190923) ML model.
diff --git a/chromeos/services/network_health/public/mojom/network_diagnostics.mojom b/chromeos/services/network_health/public/mojom/network_diagnostics.mojom
index 0601a58..8bb1675 100644
--- a/chromeos/services/network_health/public/mojom/network_diagnostics.mojom
+++ b/chromeos/services/network_health/public/mojom/network_diagnostics.mojom
@@ -128,17 +128,6 @@
   kVeryHighLatency,
 };
 
-// Problems related to the VideoConferencing routine.
-[Extensible]
-enum VideoConferencingProblem {
-  // Failed requests to a STUN server via UDP.
-  kUdpFailure,
-  // Failed requests to a STUN server via TCP.
-  kTcpFailure,
-  // Failed to establish a TLS connection to media hostnames.
-  kMediaFailure,
-};
-
 // This interface is to be used by any clients that need to run specific
 // network-related diagnostics. Expected clients of this interface are
 // NetworkHealth, cros_healthd, and a connectivity diagnostics Web UI (to name
@@ -191,12 +180,4 @@
   // the system.
   HttpsLatency() => (RoutineVerdict verdict,
       array<HttpsLatencyProblem> problems);
-
-  // Tests the device's video conferencing capabalities by testing whether the
-  // device can:
-  // (1) Contact either a default or specified STUN server via UDP.
-  // (2) Contact either a default or specified STUN server via TCP.
-  // (3) Reach common media endpoints.
-  VideoConferencing(string? stun_server_hostname) => (RoutineVerdict verdict,
-      array<VideoConferencingProblem> problems, string? support_details);
 };
diff --git a/components/content_capture/OWNERS b/components/content_capture/OWNERS
index e63fd7ee..ce296e0 100644
--- a/components/content_capture/OWNERS
+++ b/components/content_capture/OWNERS
@@ -1,3 +1 @@
-changwan@chromium.org
 michaelbai@chromium.org
-tobiasjs@chromium.org
diff --git a/components/no_state_prefetch/browser/prerender_handle.cc b/components/no_state_prefetch/browser/prerender_handle.cc
index 5d22c47..943d4fa2 100644
--- a/components/no_state_prefetch/browser/prerender_handle.cc
+++ b/components/no_state_prefetch/browser/prerender_handle.cc
@@ -73,32 +73,6 @@
   }
 }
 
-void PrerenderHandle::OnPrerenderStart(PrerenderContents* prerender_contents) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(prerender_data_);
-  DCHECK_EQ(prerender_data_->contents(), prerender_contents);
-  if (observer_)
-    observer_->OnPrerenderStart(this);
-}
-
-void PrerenderHandle::OnPrerenderStopLoading(
-    PrerenderContents* prerender_contents) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(prerender_data_);
-  DCHECK_EQ(prerender_data_->contents(), prerender_contents);
-  if (observer_)
-    observer_->OnPrerenderStopLoading(this);
-}
-
-void PrerenderHandle::OnPrerenderDomContentLoaded(
-    PrerenderContents* prerender_contents) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(prerender_data_);
-  DCHECK_EQ(prerender_data_->contents(), prerender_contents);
-  if (observer_)
-    observer_->OnPrerenderDomContentLoaded(this);
-}
-
 void PrerenderHandle::OnPrerenderStop(PrerenderContents* prerender_contents) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (observer_)
diff --git a/components/no_state_prefetch/browser/prerender_handle.h b/components/no_state_prefetch/browser/prerender_handle.h
index 38a1461f..00945240 100644
--- a/components/no_state_prefetch/browser/prerender_handle.h
+++ b/components/no_state_prefetch/browser/prerender_handle.h
@@ -26,15 +26,6 @@
  public:
   class Observer {
    public:
-    // Signals that the prerender has started running.
-    virtual void OnPrerenderStart(PrerenderHandle* handle) = 0;
-
-    // Signals that the prerender has had its load event.
-    virtual void OnPrerenderStopLoading(PrerenderHandle* handle) = 0;
-
-    // Signals that the prerender has had its 'DOMContentLoaded' event.
-    virtual void OnPrerenderDomContentLoaded(PrerenderHandle* handle) = 0;
-
     // Signals that the prerender has stopped running.
     virtual void OnPrerenderStop(PrerenderHandle* handle) = 0;
 
@@ -85,10 +76,6 @@
   explicit PrerenderHandle(PrerenderManager::PrerenderData* prerender_data);
 
   // From PrerenderContents::Observer:
-  void OnPrerenderStart(PrerenderContents* prerender_contents) override;
-  void OnPrerenderStopLoading(PrerenderContents* prerender_contents) override;
-  void OnPrerenderDomContentLoaded(
-      PrerenderContents* prerender_contents) override;
   void OnPrerenderStop(PrerenderContents* prerender_contents) override;
   void OnPrerenderNetworkBytesChanged(
       PrerenderContents* prerender_contents) override;
diff --git a/components/no_state_prefetch/browser/prerender_link_manager.cc b/components/no_state_prefetch/browser/prerender_link_manager.cc
index c78a146..f17a93e 100644
--- a/components/no_state_prefetch/browser/prerender_link_manager.cc
+++ b/components/no_state_prefetch/browser/prerender_link_manager.cc
@@ -53,8 +53,6 @@
     int launcher_render_view_id,
     blink::mojom::PrerenderAttributesPtr attributes,
     const url::Origin& initiator_origin,
-    mojo::PendingRemote<blink::mojom::PrerenderProcessorClient>
-        processor_client,
     base::TimeTicks creation_time,
     PrerenderContents* deferred_launcher)
     : launcher_render_process_id(launcher_render_process_id),
@@ -64,7 +62,6 @@
       referrer(content::Referrer(*attributes->referrer)),
       initiator_origin(initiator_origin),
       size(attributes->view_size),
-      remote_processor_client(std::move(processor_client)),
       creation_time(creation_time),
       deferred_launcher(deferred_launcher),
       has_been_abandoned(false),
@@ -93,9 +90,7 @@
     int launcher_render_process_id,
     int launcher_render_view_id,
     blink::mojom::PrerenderAttributesPtr attributes,
-    const url::Origin& initiator_origin,
-    mojo::PendingRemote<blink::mojom::PrerenderProcessorClient>
-        processor_client) {
+    const url::Origin& initiator_origin) {
 // TODO(crbug.com/722453): Use a dedicated build flag for GuestView.
 #if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_FUCHSIA)
   content::RenderViewHost* rvh = content::RenderViewHost::FromID(
@@ -122,8 +117,8 @@
 
   auto prerender = std::make_unique<LinkPrerender>(
       launcher_render_process_id, launcher_render_view_id,
-      std::move(attributes), initiator_origin, std::move(processor_client),
-      manager_->GetCurrentTimeTicks(), prerender_contents);
+      std::move(attributes), initiator_origin, manager_->GetCurrentTimeTicks(),
+      prerender_contents);
 
   // Stash pointer used only for comparison later.
   const LinkPrerender* prerender_ptr = prerender.get();
@@ -283,11 +278,9 @@
       pending_prerender->handle = std::move(handle);
       ++total_started_prerender_count;
       pending_prerender->handle->SetObserver(this);
-      OnPrerenderStart(pending_prerender->handle.get());
       running_launcher_and_render_view_routes.insert(
           launcher_and_render_view_route);
     } else {
-      pending_prerender->remote_processor_client->OnPrerenderStop();
       prerenders_.erase(it);
     }
   }
@@ -344,41 +337,10 @@
   has_shutdown_ = true;
 }
 
-// In practice, this is always called from
-// PrerenderLinkManager::OnStartPrerender().
-void PrerenderLinkManager::OnPrerenderStart(PrerenderHandle* prerender_handle) {
-  LinkPrerender* prerender = FindByPrerenderHandle(prerender_handle);
-  if (!prerender)
-    return;
-
-  prerender->remote_processor_client->OnPrerenderStart();
-}
-
-void PrerenderLinkManager::OnPrerenderStopLoading(
-    PrerenderHandle* prerender_handle) {
-  LinkPrerender* prerender = FindByPrerenderHandle(prerender_handle);
-  if (!prerender)
-    return;
-
-  prerender->remote_processor_client->OnPrerenderStopLoading();
-}
-
-void PrerenderLinkManager::OnPrerenderDomContentLoaded(
-    PrerenderHandle* prerender_handle) {
-  LinkPrerender* prerender = FindByPrerenderHandle(prerender_handle);
-  if (!prerender)
-    return;
-
-  prerender->remote_processor_client->OnPrerenderDomContentLoaded();
-}
-
 void PrerenderLinkManager::OnPrerenderStop(PrerenderHandle* prerender_handle) {
   LinkPrerender* prerender = FindByPrerenderHandle(prerender_handle);
   if (!prerender)
     return;
-
-  prerender->remote_processor_client->OnPrerenderStop();
-
   RemovePrerender(prerender);
   StartPrerenders();
 }
diff --git a/components/no_state_prefetch/browser/prerender_link_manager.h b/components/no_state_prefetch/browser/prerender_link_manager.h
index 9f93591..623465bf 100644
--- a/components/no_state_prefetch/browser/prerender_link_manager.h
+++ b/components/no_state_prefetch/browser/prerender_link_manager.h
@@ -44,9 +44,7 @@
       int launcher_render_process_id,
       int launcher_render_view_id,
       blink::mojom::PrerenderAttributesPtr attributes,
-      const url::Origin& initiator_origin,
-      mojo::PendingRemote<blink::mojom::PrerenderProcessorClient>
-          processor_client);
+      const url::Origin& initiator_origin);
 
   // Called when a <link rel=prerender ...> element has been explicitly removed
   // from a document.
@@ -72,8 +70,6 @@
                   int launcher_render_view_id,
                   blink::mojom::PrerenderAttributesPtr attributes,
                   const url::Origin& initiator_origin,
-                  mojo::PendingRemote<blink::mojom::PrerenderProcessorClient>
-                      processor_client,
                   base::TimeTicks creation_time,
                   PrerenderContents* deferred_launcher);
     ~LinkPrerender();
@@ -90,10 +86,6 @@
     const url::Origin initiator_origin;
     const gfx::Size size;
 
-    // Notification interface back to the requestor of this prerender.
-    mojo::Remote<blink::mojom::PrerenderProcessorClient>
-        remote_processor_client;
-
     // The time at which this Prerender was added to PrerenderLinkManager.
     const base::TimeTicks creation_time;
 
@@ -140,9 +132,6 @@
   void Shutdown() override;
 
   // From PrerenderHandle::Observer:
-  void OnPrerenderStart(PrerenderHandle* prerender_handle) override;
-  void OnPrerenderStopLoading(PrerenderHandle* prerender_handle) override;
-  void OnPrerenderDomContentLoaded(PrerenderHandle* prerender_handle) override;
   void OnPrerenderStop(PrerenderHandle* prerender_handle) override;
   void OnPrerenderNetworkBytesChanged(
       PrerenderHandle* prerender_handle) override;
diff --git a/components/no_state_prefetch/browser/prerender_processor_impl.cc b/components/no_state_prefetch/browser/prerender_processor_impl.cc
index ace3ac5..f79cf08 100644
--- a/components/no_state_prefetch/browser/prerender_processor_impl.cc
+++ b/components/no_state_prefetch/browser/prerender_processor_impl.cc
@@ -44,8 +44,7 @@
 }
 
 void PrerenderProcessorImpl::Start(
-    blink::mojom::PrerenderAttributesPtr attributes,
-    mojo::PendingRemote<blink::mojom::PrerenderProcessorClient> client) {
+    blink::mojom::PrerenderAttributesPtr attributes) {
   if (!initiator_origin_.opaque() &&
       !content::ChildProcessSecurityPolicy::GetInstance()
            ->CanAccessDataForOrigin(render_process_id_,
@@ -73,7 +72,7 @@
   prerender_id_ = link_manager->OnStartPrerender(
       render_process_id_,
       render_frame_host->GetRenderViewHost()->GetRoutingID(),
-      std::move(attributes), initiator_origin_, std::move(client));
+      std::move(attributes), initiator_origin_);
 }
 
 void PrerenderProcessorImpl::Cancel() {
diff --git a/components/no_state_prefetch/browser/prerender_processor_impl.h b/components/no_state_prefetch/browser/prerender_processor_impl.h
index dafe6f8a..613f2d0c 100644
--- a/components/no_state_prefetch/browser/prerender_processor_impl.h
+++ b/components/no_state_prefetch/browser/prerender_processor_impl.h
@@ -36,9 +36,7 @@
       std::unique_ptr<PrerenderProcessorImplDelegate> delegate);
 
   // blink::mojom::PrerenderProcessor implementation
-  void Start(blink::mojom::PrerenderAttributesPtr attributes,
-             mojo::PendingRemote<blink::mojom::PrerenderProcessorClient> client)
-      override;
+  void Start(blink::mojom::PrerenderAttributesPtr attributes) override;
   void Cancel() override;
 
  private:
diff --git a/components/no_state_prefetch/browser/prerender_processor_impl_unittest.cc b/components/no_state_prefetch/browser/prerender_processor_impl_unittest.cc
index 3f0c203..19e89404 100644
--- a/components/no_state_prefetch/browser/prerender_processor_impl_unittest.cc
+++ b/components/no_state_prefetch/browser/prerender_processor_impl_unittest.cc
@@ -23,9 +23,7 @@
       int launcher_render_process_id,
       int launcher_render_view_id,
       blink::mojom::PrerenderAttributesPtr attributes,
-      const url::Origin& initiator_origin,
-      mojo::PendingRemote<blink::mojom::PrerenderProcessorClient>
-          processor_client) override {
+      const url::Origin& initiator_origin) override {
     DCHECK(!is_start_called_);
     is_start_called_ = true;
     return prerender_id_;
@@ -70,24 +68,6 @@
   MockPrerenderLinkManager* link_manager_;
 };
 
-class PrerenderProcessorClientImpl final
-    : public blink::mojom::PrerenderProcessorClient {
- public:
-  // blink::mojom::PrerenderProcessorClient:
-  void OnPrerenderStart() override {}
-  void OnPrerenderStopLoading() override {}
-  void OnPrerenderDomContentLoaded() override {}
-  void OnPrerenderStop() override {}
-
-  mojo::PendingRemote<blink::mojom::PrerenderProcessorClient>
-  BindNewPipeAndPassRemote() {
-    return receiver_.BindNewPipeAndPassRemote();
-  }
-
- private:
-  mojo::Receiver<blink::mojom::PrerenderProcessorClient> receiver_{this};
-};
-
 class PrerenderProcessorImplTest : public content::RenderViewHostTestHarness {};
 
 TEST_F(PrerenderProcessorImplTest, StartCancelAbandon) {
@@ -101,11 +81,10 @@
   auto attributes = blink::mojom::PrerenderAttributes::New();
   attributes->url = GURL("https://example.com/prefetch");
   attributes->referrer = blink::mojom::Referrer::New();
-  PrerenderProcessorClientImpl client;
 
   // Start() call should be propagated to the link manager.
   EXPECT_FALSE(link_manager->is_start_called());
-  remote->Start(std::move(attributes), client.BindNewPipeAndPassRemote());
+  remote->Start(std::move(attributes));
   remote.FlushForTesting();
   EXPECT_TRUE(link_manager->is_start_called());
 
@@ -134,11 +113,10 @@
   auto attributes = blink::mojom::PrerenderAttributes::New();
   attributes->url = GURL("https://example.com/prefetch");
   attributes->referrer = blink::mojom::Referrer::New();
-  PrerenderProcessorClientImpl client;
 
   // Start() call should be propagated to the link manager.
   EXPECT_FALSE(link_manager->is_start_called());
-  remote->Start(std::move(attributes), client.BindNewPipeAndPassRemote());
+  remote->Start(std::move(attributes));
   remote.FlushForTesting();
   EXPECT_TRUE(link_manager->is_start_called());
 
@@ -169,22 +147,20 @@
   auto attributes1 = blink::mojom::PrerenderAttributes::New();
   attributes1->url = GURL("https://example.com/prefetch");
   attributes1->referrer = blink::mojom::Referrer::New();
-  PrerenderProcessorClientImpl client1;
 
   // Start() call should be propagated to the link manager.
   EXPECT_FALSE(link_manager->is_start_called());
-  remote->Start(std::move(attributes1), client1.BindNewPipeAndPassRemote());
+  remote->Start(std::move(attributes1));
   remote.FlushForTesting();
   EXPECT_TRUE(link_manager->is_start_called());
 
   auto attributes2 = blink::mojom::PrerenderAttributes::New();
   attributes2->url = GURL("https://example.com/prefetch");
   attributes2->referrer = blink::mojom::Referrer::New();
-  PrerenderProcessorClientImpl client2;
 
   // Call Start() again. This should be reported as a bad mojo message.
   ASSERT_TRUE(bad_message_error.empty());
-  remote->Start(std::move(attributes2), client2.BindNewPipeAndPassRemote());
+  remote->Start(std::move(attributes2));
   remote.FlushForTesting();
   EXPECT_EQ(bad_message_error, "PPI_START_TWICE");
 }
diff --git a/components/ntp_tiles/most_visited_sites.cc b/components/ntp_tiles/most_visited_sites.cc
index a0f3bd99..f2125d1 100644
--- a/components/ntp_tiles/most_visited_sites.cc
+++ b/components/ntp_tiles/most_visited_sites.cc
@@ -401,10 +401,9 @@
   }
 
   if (repeatable_queries_) {
+    // Restoring repeatable queries is not supported as deletion is permanent.
     if (add_url)
       repeatable_queries_->DeleteQueryWithDestinationURL(url);
-    else
-      NOTREACHED() << "Deleted repeatable queries cannot be restored.";
   }
 
   if (top_sites_) {
diff --git a/components/safe_browsing/core/features.cc b/components/safe_browsing/core/features.cc
index 1be71b1..9c6f685 100644
--- a/components/safe_browsing/core/features.cc
+++ b/components/safe_browsing/core/features.cc
@@ -101,13 +101,8 @@
     base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kRealTimeUrlLookupEnabledWithToken{
-  "SafeBrowsingRealTimeUrlLookupEnabledWithToken",
-#if BUILDFLAG(FULL_SAFE_BROWSING)
-      base::FEATURE_ENABLED_BY_DEFAULT
-#else
-      base::FEATURE_DISABLED_BY_DEFAULT
-#endif
-};
+    "SafeBrowsingRealTimeUrlLookupEnabledWithToken",
+    base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kRealTimeUrlLookupNonMainframeEnabledForEP{
     "SafeBrowsingRealTimeUrlLookupNonMainframeEnabledForEP",
diff --git a/components/services/app_service/public/cpp/app_registry_cache.cc b/components/services/app_service/public/cpp/app_registry_cache.cc
index 77b29e3..43e8c90e 100644
--- a/components/services/app_service/public/cpp/app_registry_cache.cc
+++ b/components/services/app_service/public/cpp/app_registry_cache.cc
@@ -75,7 +75,13 @@
   for (auto& delta : deltas) {
     auto d_iter = deltas_in_progress_.find(delta->app_id);
     if (d_iter != deltas_in_progress_.end()) {
-      AppUpdate::Merge(d_iter->second, delta.get());
+      if (delta->readiness == mojom::Readiness::kRemoved) {
+        // Ensure that removed deltas are *not* merged, so that the last update
+        // before the merge is sent separately.
+        deltas_pending_.push_back(std::move(delta));
+      } else {
+        AppUpdate::Merge(d_iter->second, delta.get());
+      }
     } else {
       deltas_in_progress_[delta->app_id] = delta.get();
     }
@@ -86,6 +92,10 @@
 
   // Notify the observers for every de-duplicated delta.
   for (const auto& d_iter : deltas_in_progress_) {
+    // Do not update subscribers for removed apps.
+    if (d_iter.second->readiness == mojom::Readiness::kRemoved) {
+      continue;
+    }
     auto s_iter = states_.find(d_iter.first);
     apps::mojom::App* state =
         (s_iter != states_.end()) ? s_iter->second.get() : nullptr;
@@ -103,10 +113,15 @@
         (s_iter != states_.end()) ? s_iter->second.get() : nullptr;
     apps::mojom::App* delta = d_iter.second;
 
-    if (state) {
-      AppUpdate::Merge(state, delta);
+    if (delta->readiness != mojom::Readiness::kRemoved) {
+      if (state) {
+        AppUpdate::Merge(state, delta);
+      } else {
+        states_.insert(std::make_pair(delta->app_id, delta->Clone()));
+      }
     } else {
-      states_.insert(std::make_pair(delta->app_id, delta->Clone()));
+      DCHECK(!state || state->readiness != mojom::Readiness::kReady);
+      states_.erase(d_iter.first);
     }
   }
   deltas_in_progress_.clear();
diff --git a/components/services/app_service/public/cpp/app_registry_cache_unittest.cc b/components/services/app_service/public/cpp/app_registry_cache_unittest.cc
index e732c00..2cfc393 100644
--- a/components/services/app_service/public/cpp/app_registry_cache_unittest.cc
+++ b/components/services/app_service/public/cpp/app_registry_cache_unittest.cc
@@ -5,8 +5,27 @@
 #include <map>
 
 #include "components/services/app_service/public/cpp/app_registry_cache.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace {
+
+class MockRegistryObserver : public apps::AppRegistryCache::Observer {
+ public:
+  MOCK_METHOD(void, OnAppUpdate, (const apps::AppUpdate& update), ());
+
+  MOCK_METHOD(void,
+              OnAppRegistryCacheWillBeDestroyed,
+              (apps::AppRegistryCache * cache),
+              ());
+};
+
+MATCHER_P(HasAppId, app_id, "Has the correct app id") {
+  return arg.AppId() == app_id;
+}
+
+}  // namespace
+
 class AppRegistryCacheTest : public testing::Test,
                              public apps::AppRegistryCache::Observer {
  protected:
@@ -264,6 +283,49 @@
   EXPECT_FALSE(found_e);
 }
 
+TEST_F(AppRegistryCacheTest, Removed) {
+  apps::AppRegistryCache cache;
+  testing::StrictMock<MockRegistryObserver> observer;
+  cache.SetAccountId(account_id());
+  cache.AddObserver(&observer);
+
+  // Starting with an empty cache.
+  cache.ForEachApp([&observer](const apps::AppUpdate& update) {
+    observer.OnAppUpdate(update);
+  });
+
+  // We add the app, and expect to be notified.
+  EXPECT_CALL(observer, OnAppUpdate(HasAppId("app")));
+  std::vector<apps::mojom::AppPtr> apps;
+  apps.push_back(MakeApp("app", "app", apps::mojom::Readiness::kReady));
+  cache.OnApps(std::move(apps));
+
+  // We first say the app is uninstalled, then remove it.
+  apps.clear();
+  apps.push_back(
+      MakeApp("app", "app", apps::mojom::Readiness::kUninstalledByUser));
+  apps.push_back(MakeApp("app", "app", apps::mojom::Readiness::kRemoved));
+
+  // We should see one call informing us that the app was uninstalled.
+  EXPECT_CALL(observer, OnAppUpdate(HasAppId("app")))
+      .WillOnce(
+          testing::Invoke([&observer, &cache](const apps::AppUpdate& update) {
+            EXPECT_EQ(apps::mojom::Readiness::kUninstalledByUser,
+                      update.Readiness());
+            // Even though we have queued the removal, checking the cache now
+            // shows the app is still present.
+            EXPECT_CALL(observer, OnAppUpdate(HasAppId("app")));
+            cache.ForEachApp([&observer](const apps::AppUpdate& update) {
+              observer.OnAppUpdate(update);
+            });
+          }));
+  cache.OnApps(std::move(apps));
+
+  // The cache is now empty.
+  cache.ForEachApp([](const apps::AppUpdate& update) { NOTREACHED(); });
+  cache.RemoveObserver(&observer);
+}
+
 TEST_F(AppRegistryCacheTest, Observer) {
   std::vector<apps::mojom::AppPtr> deltas;
   apps::AppRegistryCache cache;
diff --git a/components/services/app_service/public/cpp/app_update.cc b/components/services/app_service/public/cpp/app_update.cc
index f4d23671..58628b4 100644
--- a/components/services/app_service/public/cpp/app_update.cc
+++ b/components/services/app_service/public/cpp/app_update.cc
@@ -52,6 +52,10 @@
     return;
   }
 
+  // You can not merge removed states.
+  DCHECK(state->readiness != mojom::Readiness::kRemoved);
+  DCHECK(delta->readiness != mojom::Readiness::kRemoved);
+
   if (delta->readiness != apps::mojom::Readiness::kUnknown) {
     state->readiness = delta->readiness;
   }
diff --git a/components/services/app_service/public/mojom/types.mojom b/components/services/app_service/public/mojom/types.mojom
index 26923d2..bd72cdd9 100644
--- a/components/services/app_service/public/mojom/types.mojom
+++ b/components/services/app_service/public/mojom/types.mojom
@@ -108,6 +108,11 @@
   kDisabledByUser,       // Disabled by explicit user action.
   kTerminated,           // Renderer process crashed.
   kUninstalledByUser,
+  // Removed apps are purged from the registry cache and have their
+  // associated memory freed. Subscribers are not notified of removed
+  // apps, so publishers must set the app as uninstalled before
+  // removing it.
+  kRemoved,
 };
 
 // How the app was installed.
diff --git a/components/sync/PRESUBMIT.py b/components/sync/PRESUBMIT.py
index aadd362..45de349 100644
--- a/components/sync/PRESUBMIT.py
+++ b/components/sync/PRESUBMIT.py
@@ -24,11 +24,11 @@
   'NIGORI',  # Model type string is 'encryption keys'.
   'SUPERVISED_USER_SETTINGS',  # Root tag and model type string replace
                                # 'Supervised' with 'Managed'
-  'SUPERVISED_USER_ALLOWLISTS',  # See previous.
 
   # Deprecated types:
   'DEPRECATED_FAVICON_IMAGES',
-  'DEPRECATED_FAVICON_TRACKING']
+  'DEPRECATED_FAVICON_TRACKING',
+  'DEPRECATED_SUPERVISED_USER_ALLOWLISTS']
 
 # Root tags are used as prefixes when creating storage keys, so certain strings
 # are blacklisted in order to prevent prefix collision.
diff --git a/components/sync/base/model_type.cc b/components/sync/base/model_type.cc
index 17dcae0b..539d0ef6 100644
--- a/components/sync/base/model_type.cc
+++ b/components/sync/base/model_type.cc
@@ -141,10 +141,10 @@
     {APP_LIST, "APP_LIST", "app_list", "App List",
      sync_pb::EntitySpecifics::kAppListFieldNumber,
      ModelTypeForHistograms::kAppList},
-    {SUPERVISED_USER_ALLOWLISTS, "MANAGED_USER_WHITELIST",
+    {DEPRECATED_SUPERVISED_USER_ALLOWLISTS, "MANAGED_USER_WHITELIST",
      "managed_user_whitelists", "Managed User Whitelists",
      sync_pb::EntitySpecifics::kManagedUserWhitelistFieldNumber,
-     ModelTypeForHistograms::kSupervisedUserAllowlists},
+     ModelTypeForHistograms::kDeprecatedSupervisedUserAllowlists},
     {ARC_PACKAGE, "ARC_PACKAGE", "arc_package", "Arc Package",
      sync_pb::EntitySpecifics::kArcPackageFieldNumber,
      ModelTypeForHistograms::kArcPackage},
@@ -280,7 +280,7 @@
     case APP_LIST:
       specifics->mutable_app_list();
       break;
-    case SUPERVISED_USER_ALLOWLISTS:
+    case DEPRECATED_SUPERVISED_USER_ALLOWLISTS:
       specifics->mutable_managed_user_whitelist();
       break;
     case ARC_PACKAGE:
@@ -417,7 +417,7 @@
   if (specifics.has_app_list())
     return APP_LIST;
   if (specifics.has_managed_user_whitelist())
-    return SUPERVISED_USER_ALLOWLISTS;
+    return DEPRECATED_SUPERVISED_USER_ALLOWLISTS;
   if (specifics.has_arc_package())
     return ARC_PACKAGE;
   if (specifics.has_printer())
@@ -467,7 +467,7 @@
   encryptable_user_types.Remove(PRIORITY_PREFERENCES);
   encryptable_user_types.Remove(OS_PRIORITY_PREFERENCES);
   encryptable_user_types.Remove(SUPERVISED_USER_SETTINGS);
-  encryptable_user_types.Remove(SUPERVISED_USER_ALLOWLISTS);
+  encryptable_user_types.Remove(DEPRECATED_SUPERVISED_USER_ALLOWLISTS);
   // Proxy types have no sync representation and are therefore not encrypted.
   // Note however that proxy types map to one or more protocol types, which
   // may or may not be encrypted themselves.
diff --git a/components/sync/base/model_type.h b/components/sync/base/model_type.h
index 028ade4..72764d39f 100644
--- a/components/sync/base/model_type.h
+++ b/components/sync/base/model_type.h
@@ -112,7 +112,8 @@
   APP_LIST,
   // Supervised user allowlists. Each item contains a CRX ID (like an extension
   // ID) and a name.
-  SUPERVISED_USER_ALLOWLISTS,
+  // TODO(crbug.com/1155257): Remove the deprecated type.
+  DEPRECATED_SUPERVISED_USER_ALLOWLISTS,
   // ARC package items, i.e. Android apps on ChromeOS.
   ARC_PACKAGE,
   // Printer device information. ChromeOS only.
@@ -212,7 +213,7 @@
   // kDeprecatedSupervisedUserSharedSettings = 30,
   // kDeprecatedSyncedNotificationAppInfo = 31,
   // kDeprecatedWifiCredentials = 32,
-  kSupervisedUserAllowlists = 33,
+  kDeprecatedSupervisedUserAllowlists = 33,
   kAutofillWalletData = 34,
   kAutofillWalletMetadata = 35,
   kArcPackage = 36,
@@ -257,10 +258,10 @@
       APP_SETTINGS, EXTENSION_SETTINGS, HISTORY_DELETE_DIRECTIVES, DICTIONARY,
       DEPRECATED_FAVICON_IMAGES, DEPRECATED_FAVICON_TRACKING, DEVICE_INFO,
       PRIORITY_PREFERENCES, SUPERVISED_USER_SETTINGS, APP_LIST,
-      SUPERVISED_USER_ALLOWLISTS, ARC_PACKAGE, PRINTERS, READING_LIST,
-      USER_EVENTS, NIGORI, USER_CONSENTS, SEND_TAB_TO_SELF, SECURITY_EVENTS,
-      WEB_APPS, WIFI_CONFIGURATIONS, OS_PREFERENCES, OS_PRIORITY_PREFERENCES,
-      SHARING_MESSAGE);
+      DEPRECATED_SUPERVISED_USER_ALLOWLISTS, ARC_PACKAGE, PRINTERS,
+      READING_LIST, USER_EVENTS, NIGORI, USER_CONSENTS, SEND_TAB_TO_SELF,
+      SECURITY_EVENTS, WEB_APPS, WIFI_CONFIGURATIONS, OS_PREFERENCES,
+      OS_PRIORITY_PREFERENCES, SHARING_MESSAGE);
 }
 
 // These are the normal user-controlled types. This is to distinguish from
@@ -273,8 +274,8 @@
 // User types, which are not user-controlled.
 constexpr ModelTypeSet AlwaysPreferredUserTypes() {
   return ModelTypeSet(DEVICE_INFO, USER_CONSENTS, SECURITY_EVENTS,
-                      SUPERVISED_USER_SETTINGS, SUPERVISED_USER_ALLOWLISTS,
-                      SHARING_MESSAGE);
+                      SUPERVISED_USER_SETTINGS,
+                      DEPRECATED_SUPERVISED_USER_ALLOWLISTS, SHARING_MESSAGE);
 }
 
 // User types which are always encrypted.
@@ -297,7 +298,7 @@
       DEVICE_INFO, SHARING_MESSAGE,
       // For supervised users, it is important to quickly deliver changes in
       // settings and in allowed sites to the supervised user.
-      SUPERVISED_USER_SETTINGS, SUPERVISED_USER_ALLOWLISTS,
+      SUPERVISED_USER_SETTINGS, DEPRECATED_SUPERVISED_USER_ALLOWLISTS,
       // These are by definition preferences for which it is important that the
       // client picks them up quickly (also because these can get changed
       // server-side). For example, such a pref could control whether a
diff --git a/components/translate/core/browser/BUILD.gn b/components/translate/core/browser/BUILD.gn
index bd5a4476..98e2241 100644
--- a/components/translate/core/browser/BUILD.gn
+++ b/components/translate/core/browser/BUILD.gn
@@ -29,6 +29,7 @@
     "translate_metrics_logger.h",
     "translate_metrics_logger_impl.cc",
     "translate_metrics_logger_impl.h",
+    "translate_model_service.h",
     "translate_prefs.cc",
     "translate_prefs.h",
     "translate_ranker.h",
diff --git a/components/translate/core/browser/translate_model_service.h b/components/translate/core/browser/translate_model_service.h
new file mode 100644
index 0000000..b97e33d
--- /dev/null
+++ b/components/translate/core/browser/translate_model_service.h
@@ -0,0 +1,31 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_MODEL_SERVICE_H_
+#define COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_MODEL_SERVICE_H_
+
+#include "base/optional.h"
+
+namespace base {
+class File;
+}  // namespace base
+
+namespace translate {
+
+// Service that manages models required to support translation in the browser.
+class TranslateModelService {
+ public:
+  TranslateModelService() = default;
+
+  // Returns a loaded file containing the TFLite model capable of detecting the
+  // language of a web page's text.
+  virtual base::Optional<base::File> GetLanguageDetectionModelFile() = 0;
+
+ protected:
+  virtual ~TranslateModelService() = default;
+};
+
+}  //  namespace translate
+
+#endif  // COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_MODEL_SERVICE_H_
diff --git a/components/translate/core/common/translate_util.cc b/components/translate/core/common/translate_util.cc
index 963168c..88a3234 100644
--- a/components/translate/core/common/translate_util.cc
+++ b/components/translate/core/common/translate_util.cc
@@ -25,6 +25,9 @@
 const base::Feature kTranslateSubFrames{"TranslateSubFrames",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kTFLiteLanguageDetectionEnabled{
+    "TFLiteLanguageDetectionEnabled", base::FEATURE_DISABLED_BY_DEFAULT};
+
 GURL GetTranslateSecurityOrigin() {
   std::string security_origin(kSecurityOrigin);
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
@@ -45,4 +48,8 @@
              kTranslateSubFrames, kDetectLanguageInSubFrames, true);
 }
 
+bool IsTFLiteLanguageDetectionEnabled() {
+  return base::FeatureList::IsEnabled(kTFLiteLanguageDetectionEnabled);
+}
+
 }  // namespace translate
diff --git a/components/translate/core/common/translate_util.h b/components/translate/core/common/translate_util.h
index 4848ac8..e8179df 100644
--- a/components/translate/core/common/translate_util.h
+++ b/components/translate/core/common/translate_util.h
@@ -14,6 +14,9 @@
 // main frame.
 extern const base::Feature kTranslateSubFrames;
 
+// Controls whether the TFLite-based language detection is enabled.
+extern const base::Feature kTFLiteLanguageDetectionEnabled;
+
 // Isolated world sets following security-origin by default.
 extern const char kSecurityOrigin[];
 
@@ -27,6 +30,9 @@
 // Return whether sub frame language detection is enabled.
 bool IsSubFrameLanguageDetectionEnabled();
 
+// Return whether TFLIte-based language detection is enabled.
+bool IsTFLiteLanguageDetectionEnabled();
+
 }  // namespace translate
 
 #endif  // COMPONENTS_TRANSLATE_CORE_COMMON_TRANSLATE_UTIL_H_
diff --git a/components/webapps/BUILD.gn b/components/webapps/BUILD.gn
new file mode 100644
index 0000000..5bfff231
--- /dev/null
+++ b/components/webapps/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("webapps") {
+  sources = [
+    "webapps_client.cc",
+    "webapps_client.h",
+  ]
+  deps = [ "//components/security_state/core" ]
+}
diff --git a/components/webapps/DEPS b/components/webapps/DEPS
new file mode 100644
index 0000000..17177c42
--- /dev/null
+++ b/components/webapps/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+components/security_state/core",
+]
diff --git a/components/webapps/DIR_METADATA b/components/webapps/DIR_METADATA
new file mode 100644
index 0000000..11597323
--- /dev/null
+++ b/components/webapps/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>WebAppInstalls"
+}
+team_email: "pwa-dev@chromium.org"
diff --git a/components/webapps/OWNERS b/components/webapps/OWNERS
new file mode 100644
index 0000000..413ef7a
--- /dev/null
+++ b/components/webapps/OWNERS
@@ -0,0 +1,2 @@
+dominickn@chromium.org
+hartmanng@chromium.org
diff --git a/components/webapps/android/OWNERS b/components/webapps/android/OWNERS
deleted file mode 100644
index cc49ee3..0000000
--- a/components/webapps/android/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-dominickn@chromium.org
-hartmanng@chromium.org
-
-# COMPONENT: UI>Browser>WebAppInstalls
-# TEAM: web-apps-platform-team@chromium.org
diff --git a/components/webapps/webapps_client.cc b/components/webapps/webapps_client.cc
new file mode 100644
index 0000000..bec30db
--- /dev/null
+++ b/components/webapps/webapps_client.cc
@@ -0,0 +1,28 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/webapps/webapps_client.h"
+
+namespace webapps {
+
+namespace {
+WebappsClient* g_instance = nullptr;
+}
+
+WebappsClient::WebappsClient() {
+  DCHECK(!g_instance);
+  g_instance = this;
+}
+
+WebappsClient::~WebappsClient() {
+  DCHECK(g_instance);
+  g_instance = nullptr;
+}
+
+// static
+WebappsClient* WebappsClient::Get() {
+  return g_instance;
+}
+
+}  // namespace webapps
diff --git a/components/webapps/webapps_client.h b/components/webapps/webapps_client.h
new file mode 100644
index 0000000..4661b22d
--- /dev/null
+++ b/components/webapps/webapps_client.h
@@ -0,0 +1,34 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_WEBAPPS_WEBAPPS_CLIENT_H_
+#define COMPONENTS_WEBAPPS_WEBAPPS_CLIENT_H_
+
+#include "components/security_state/core/security_state.h"
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+namespace webapps {
+
+// Interface to be implemented by the embedder (such as Chrome or WebLayer) to
+// expose embedder specific logic.
+class WebappsClient {
+ public:
+  WebappsClient();
+  WebappsClient(const WebappsClient&) = delete;
+  WebappsClient& operator=(const WebappsClient&) = delete;
+  virtual ~WebappsClient();
+
+  // Return the webapps client.
+  static WebappsClient* Get();
+
+  virtual security_state::SecurityLevel GetSecurityLevelForWebContents(
+      content::WebContents* web_contents) = 0;
+};
+
+}  // namespace webapps
+
+#endif  // COMPONENTS_WEBAPPS_WEBAPPS_CLIENT_H_
diff --git a/content/browser/prerender/prerender_host_registry.cc b/content/browser/prerender/prerender_host_registry.cc
index a2d687e..93c7144 100644
--- a/content/browser/prerender/prerender_host_registry.cc
+++ b/content/browser/prerender/prerender_host_registry.cc
@@ -18,16 +18,29 @@
 
 PrerenderHostRegistry::~PrerenderHostRegistry() = default;
 
-void PrerenderHostRegistry::RegisterHost(
-    const GURL& prerendering_url,
-    std::unique_ptr<PrerenderHost> prerender_host) {
+void PrerenderHostRegistry::CreateAndStartHost(
+    blink::mojom::PrerenderAttributesPtr attributes,
+    const GlobalFrameRoutingId& initiator_render_frame_host_id,
+    const url::Origin& initiator_origin) {
+  DCHECK(attributes);
+
   // Ignore prerendering requests for the same URL.
-  if (base::Contains(prerender_host_by_url_, prerendering_url)) {
-    // TODO(https://crbug.com/1132746): In addition to this check, we may have
-    // to avoid duplicate requests in the PrerenderHost layer so that the
-    // prerender host doesn't start navigation for the duplicate requests.
+  const GURL prerendering_url = attributes->url;
+  if (base::Contains(prerender_host_by_url_, prerendering_url))
     return;
-  }
+
+  auto prerender_host = std::make_unique<PrerenderHost>(
+      std::move(attributes), initiator_render_frame_host_id, initiator_origin);
+
+  // Start prerendering before adding the host to the map to make sure
+  // navigation for prerendering doesn't select itself.
+  // TODO(https://crbug.com/1132746): SelectForNavigation() should avoid select
+  // a prerender host when the current NavigationRequest is for prerendering
+  // regardless of the calling order of StartPrerendering(). This modification
+  // would require the proper `is_prerendering` state in NavigationRequest,
+  // RenderFrameHostImpl, or somewhere else.
+  prerender_host->StartPrerendering();
+
   prerender_host_by_url_[prerendering_url] = std::move(prerender_host);
 }
 
diff --git a/content/browser/prerender/prerender_host_registry.h b/content/browser/prerender/prerender_host_registry.h
index d52a58b..c63ea6f 100644
--- a/content/browser/prerender/prerender_host_registry.h
+++ b/content/browser/prerender/prerender_host_registry.h
@@ -8,7 +8,10 @@
 #include <map>
 
 #include "content/common/content_export.h"
+#include "content/public/browser/global_routing_id.h"
+#include "third_party/blink/public/mojom/prerender/prerender.mojom.h"
 #include "url/gurl.h"
+#include "url/origin.h"
 
 namespace content {
 
@@ -19,7 +22,7 @@
 // to navigation code for activating prerendered contents. This is created and
 // owned by StoragePartitionImpl.
 //
-// TODO(https://crbug.com/1132746): Once the Prerender2 is migrated to the
+// TODO(https://crbug.com/1154501): Once the Prerender2 is migrated to the
 // MPArch, it would be more natural to make PrerenderHostRegistry scoped to
 // WebContents, that is, WebContents will own this.
 class CONTENT_EXPORT PrerenderHostRegistry {
@@ -32,9 +35,11 @@
   PrerenderHostRegistry(PrerenderHostRegistry&&) = delete;
   PrerenderHostRegistry& operator=(PrerenderHostRegistry&&) = delete;
 
-  // Registers the host for `prerendering_url`.
-  void RegisterHost(const GURL& prerendering_url,
-                    std::unique_ptr<PrerenderHost> prerender_host);
+  // Creates and starts a host for `prerendering_url`.
+  void CreateAndStartHost(
+      blink::mojom::PrerenderAttributesPtr attributes,
+      const GlobalFrameRoutingId& initiator_render_frame_host_id,
+      const url::Origin& initiator_origin);
 
   // Destroys the host registered for `prerendering_url`.
   void AbandonHost(const GURL& prerendering_url);
diff --git a/content/browser/prerender/prerender_host_registry_unittest.cc b/content/browser/prerender/prerender_host_registry_unittest.cc
index 9dc5042a..1f54520 100644
--- a/content/browser/prerender/prerender_host_registry_unittest.cc
+++ b/content/browser/prerender/prerender_host_registry_unittest.cc
@@ -54,7 +54,7 @@
   std::unique_ptr<TestBrowserContext> browser_context_;
 };
 
-TEST_F(PrerenderHostRegistryTest, RegisterHost) {
+TEST_F(PrerenderHostRegistryTest, CreateAndStartHost) {
   std::unique_ptr<TestWebContents> web_contents =
       CreateWebContents(GURL("https://example.com/"));
   RenderFrameHostImpl* render_frame_host = web_contents->GetMainFrame();
@@ -63,26 +63,23 @@
   const GURL kPrerenderingUrl("https://example.com/next");
   auto attributes = blink::mojom::PrerenderAttributes::New();
   attributes->url = kPrerenderingUrl;
-  auto prerender_host = std::make_unique<PrerenderHost>(
-      std::move(attributes), render_frame_host->GetGlobalFrameRoutingId(),
-      render_frame_host->GetLastCommittedOrigin());
-  PrerenderHost* prerender_host_rawptr = prerender_host.get();
 
   PrerenderHostRegistry* registry = GetPrerenderHostRegistry();
-
-  registry->RegisterHost(kPrerenderingUrl, std::move(prerender_host));
-  EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl),
-            prerender_host_rawptr);
+  registry->CreateAndStartHost(std::move(attributes),
+                               render_frame_host->GetGlobalFrameRoutingId(),
+                               render_frame_host->GetLastCommittedOrigin());
+  PrerenderHost* prerender_host =
+      registry->FindHostByUrlForTesting(kPrerenderingUrl);
 
   // Artificially finish navigation to make the prerender host ready to activate
   // the prerendered page.
-  prerender_host_rawptr->DidFinishNavigation(nullptr);
+  prerender_host->DidFinishNavigation(nullptr);
 
   EXPECT_TRUE(registry->SelectForNavigation(kPrerenderingUrl));
   EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
 }
 
-TEST_F(PrerenderHostRegistryTest, RegisterHostForSameURL) {
+TEST_F(PrerenderHostRegistryTest, CreateAndStartHostForSameURL) {
   std::unique_ptr<TestWebContents> web_contents =
       CreateWebContents(GURL("https://example.com/"));
   RenderFrameHostImpl* render_frame_host = web_contents->GetMainFrame();
@@ -92,41 +89,34 @@
 
   auto attributes1 = blink::mojom::PrerenderAttributes::New();
   attributes1->url = kPrerenderingUrl;
-  auto prerender_host1 = std::make_unique<PrerenderHost>(
-      std::move(attributes1), render_frame_host->GetGlobalFrameRoutingId(),
-      render_frame_host->GetLastCommittedOrigin());
-  PrerenderHost* prerender_host1_rawptr = prerender_host1.get();
 
   auto attributes2 = blink::mojom::PrerenderAttributes::New();
   attributes2->url = kPrerenderingUrl;
-  auto prerender_host2 = std::make_unique<PrerenderHost>(
-      std::move(attributes2), render_frame_host->GetGlobalFrameRoutingId(),
-      render_frame_host->GetLastCommittedOrigin());
-  PrerenderHost* prerender_host2_rawptr = prerender_host2.get();
 
   PrerenderHostRegistry* registry = GetPrerenderHostRegistry();
+  registry->CreateAndStartHost(std::move(attributes1),
+                               render_frame_host->GetGlobalFrameRoutingId(),
+                               render_frame_host->GetLastCommittedOrigin());
+  PrerenderHost* prerender_host1 =
+      registry->FindHostByUrlForTesting(kPrerenderingUrl);
 
-  registry->RegisterHost(kPrerenderingUrl, std::move(prerender_host1));
-  EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl),
-            prerender_host1_rawptr);
-
-  // Register the prerender host for the same URL. This second host should be
+  // Start the prerender host for the same URL. This second host should be
   // ignored, and the first host should still be findable.
-  registry->RegisterHost(kPrerenderingUrl, std::move(prerender_host2));
+  registry->CreateAndStartHost(std::move(attributes2),
+                               render_frame_host->GetGlobalFrameRoutingId(),
+                               render_frame_host->GetLastCommittedOrigin());
   EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl),
-            prerender_host1_rawptr);
-  EXPECT_NE(registry->FindHostByUrlForTesting(kPrerenderingUrl),
-            prerender_host2_rawptr);
+            prerender_host1);
 
   // Artificially finish navigation to make the prerender host ready to activate
   // the prerendered page.
-  prerender_host1_rawptr->DidFinishNavigation(nullptr);
+  prerender_host1->DidFinishNavigation(nullptr);
 
   EXPECT_TRUE(registry->SelectForNavigation(kPrerenderingUrl));
   EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
 }
 
-TEST_F(PrerenderHostRegistryTest, RegisterHostForDifferentURLs) {
+TEST_F(PrerenderHostRegistryTest, CreateAndStartHostForDifferentURLs) {
   std::unique_ptr<TestWebContents> web_contents =
       CreateWebContents(GURL("https://example.com/"));
   RenderFrameHostImpl* render_frame_host = web_contents->GetMainFrame();
@@ -135,40 +125,34 @@
   const GURL kPrerenderingUrl1("https://example.com/next1");
   auto attributes1 = blink::mojom::PrerenderAttributes::New();
   attributes1->url = kPrerenderingUrl1;
-  auto prerender_host1 = std::make_unique<PrerenderHost>(
-      std::move(attributes1), render_frame_host->GetGlobalFrameRoutingId(),
-      render_frame_host->GetLastCommittedOrigin());
-  PrerenderHost* prerender_host1_rawptr = prerender_host1.get();
 
   const GURL kPrerenderingUrl2("https://example.com/next2");
   auto attributes2 = blink::mojom::PrerenderAttributes::New();
   attributes2->url = kPrerenderingUrl2;
-  auto prerender_host2 = std::make_unique<PrerenderHost>(
-      std::move(attributes2), render_frame_host->GetGlobalFrameRoutingId(),
-      render_frame_host->GetLastCommittedOrigin());
-  PrerenderHost* prerender_host2_rawptr = prerender_host2.get();
 
   PrerenderHostRegistry* registry = GetPrerenderHostRegistry();
-
-  registry->RegisterHost(kPrerenderingUrl1, std::move(prerender_host1));
-  EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl1),
-            prerender_host1_rawptr);
-  registry->RegisterHost(kPrerenderingUrl2, std::move(prerender_host2));
-  EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl2),
-            prerender_host2_rawptr);
+  registry->CreateAndStartHost(std::move(attributes1),
+                               render_frame_host->GetGlobalFrameRoutingId(),
+                               render_frame_host->GetLastCommittedOrigin());
+  registry->CreateAndStartHost(std::move(attributes2),
+                               render_frame_host->GetGlobalFrameRoutingId(),
+                               render_frame_host->GetLastCommittedOrigin());
+  PrerenderHost* prerender_host1 =
+      registry->FindHostByUrlForTesting(kPrerenderingUrl1);
+  PrerenderHost* prerender_host2 =
+      registry->FindHostByUrlForTesting(kPrerenderingUrl2);
 
   // Artificially finish navigation to make the prerender hosts ready to
   // activate the prerendered pages.
-  prerender_host1_rawptr->DidFinishNavigation(nullptr);
-  prerender_host2_rawptr->DidFinishNavigation(nullptr);
+  prerender_host1->DidFinishNavigation(nullptr);
+  prerender_host2->DidFinishNavigation(nullptr);
 
   // Select the first host.
   EXPECT_TRUE(registry->SelectForNavigation(kPrerenderingUrl1));
   EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl1), nullptr);
   // The second host should still be findable.
-  registry->RegisterHost(kPrerenderingUrl2, std::move(prerender_host2));
   EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl2),
-            prerender_host2_rawptr);
+            prerender_host2);
 
   // Select the second host.
   EXPECT_TRUE(registry->SelectForNavigation(kPrerenderingUrl2));
@@ -184,20 +168,17 @@
   const GURL kPrerenderingUrl("https://example.com/next");
   auto attributes = blink::mojom::PrerenderAttributes::New();
   attributes->url = kPrerenderingUrl;
-  auto prerender_host = std::make_unique<PrerenderHost>(
-      std::move(attributes), render_frame_host->GetGlobalFrameRoutingId(),
-      render_frame_host->GetLastCommittedOrigin());
-  PrerenderHost* prerender_host_rawptr = prerender_host.get();
 
   PrerenderHostRegistry* registry = GetPrerenderHostRegistry();
-
-  registry->RegisterHost(kPrerenderingUrl, std::move(prerender_host));
-  EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl),
-            prerender_host_rawptr);
+  registry->CreateAndStartHost(std::move(attributes),
+                               render_frame_host->GetGlobalFrameRoutingId(),
+                               render_frame_host->GetLastCommittedOrigin());
+  PrerenderHost* prerender_host =
+      registry->FindHostByUrlForTesting(kPrerenderingUrl);
 
   // The prerender host is not ready for activation yet, so the registry
   // shouldn't select the host and instead should abandon it.
-  ASSERT_FALSE(prerender_host_rawptr->is_ready_for_activation());
+  ASSERT_FALSE(prerender_host->is_ready_for_activation());
   EXPECT_FALSE(registry->SelectForNavigation(kPrerenderingUrl));
   EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
 }
@@ -211,16 +192,12 @@
   const GURL kPrerenderingUrl("https://example.com/next");
   auto attributes = blink::mojom::PrerenderAttributes::New();
   attributes->url = kPrerenderingUrl;
-  auto prerender_host = std::make_unique<PrerenderHost>(
-      std::move(attributes), render_frame_host->GetGlobalFrameRoutingId(),
-      render_frame_host->GetLastCommittedOrigin());
-  PrerenderHost* prerender_host_rawptr = prerender_host.get();
 
   PrerenderHostRegistry* registry = GetPrerenderHostRegistry();
-
-  registry->RegisterHost(kPrerenderingUrl, std::move(prerender_host));
-  EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl),
-            prerender_host_rawptr);
+  registry->CreateAndStartHost(std::move(attributes),
+                               render_frame_host->GetGlobalFrameRoutingId(),
+                               render_frame_host->GetLastCommittedOrigin());
+  EXPECT_NE(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
 
   registry->AbandonHost(kPrerenderingUrl);
   EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
diff --git a/content/browser/prerender/prerender_processor.cc b/content/browser/prerender/prerender_processor.cc
index 898774cb..c390dab1 100644
--- a/content/browser/prerender/prerender_processor.cc
+++ b/content/browser/prerender/prerender_processor.cc
@@ -30,9 +30,7 @@
 // no-state-prefetch implementation. See PrerenderContents::StartPrerendering()
 // for example.
 void PrerenderProcessor::Start(
-    blink::mojom::PrerenderAttributesPtr attributes,
-    mojo::PendingRemote<blink::mojom::PrerenderProcessorClient>
-        pending_remote) {
+    blink::mojom::PrerenderAttributesPtr attributes) {
   // Start() must be called only one time.
   if (state_ != State::kInitial) {
     mojo::ReportBadMessage("PP_START_TWICE");
@@ -49,17 +47,10 @@
 
   prerendering_url_ = attributes->url;
 
-  // Start prerendering.
-  auto prerender_host = std::make_unique<PrerenderHost>(
+  GetPrerenderHostRegistry().CreateAndStartHost(
       std::move(attributes),
       initiator_render_frame_host_.GetGlobalFrameRoutingId(),
       initiator_origin_);
-  prerender_host->StartPrerendering();
-
-  // Register the prerender host to PrerenderHostRegistry so that navigation can
-  // find this prerendered contents.
-  GetPrerenderHostRegistry().RegisterHost(prerendering_url_,
-                                          std::move(prerender_host));
 }
 
 void PrerenderProcessor::Cancel() {
diff --git a/content/browser/prerender/prerender_processor.h b/content/browser/prerender/prerender_processor.h
index 1897643..c35154c 100644
--- a/content/browser/prerender/prerender_processor.h
+++ b/content/browser/prerender/prerender_processor.h
@@ -24,8 +24,8 @@
 // request (see comments on the mojom interface for details) and owned by the
 // initiator RenderFrameHostImpl's mojo::UniqueReceiverSet.
 //
-// When Start() is called from a renderer process, this instantiates a new
-// PrerenderHost, and forwards the request to the prerender host.
+// When Start() is called from a renderer process, this asks
+// PrerenderHostRegistry to create a PrerenderHost and start prerendering.
 class CONTENT_EXPORT PrerenderProcessor final
     : public blink::mojom::PrerenderProcessor {
  public:
@@ -38,9 +38,7 @@
   PrerenderProcessor& operator=(PrerenderProcessor&&) = delete;
 
   // blink::mojom::PrerenderProcessor implementation:
-  void Start(blink::mojom::PrerenderAttributesPtr attributes,
-             mojo::PendingRemote<blink::mojom::PrerenderProcessorClient>
-                 pending_remote) override;
+  void Start(blink::mojom::PrerenderAttributesPtr attributes) override;
   void Cancel() override;
 
  private:
diff --git a/content/browser/prerender/prerender_processor_unittest.cc b/content/browser/prerender/prerender_processor_unittest.cc
index 4a12422..55fca906 100644
--- a/content/browser/prerender/prerender_processor_unittest.cc
+++ b/content/browser/prerender/prerender_processor_unittest.cc
@@ -19,26 +19,6 @@
 namespace content {
 namespace {
 
-// TODO(https://crbug.com/839030): Remove this implementation along with
-// deprecating the prefixed prerender events.
-class PrerenderProcessorClient final
-    : public blink::mojom::PrerenderProcessorClient {
- public:
-  // blink::mojom::PrerenderProcessorClient:
-  void OnPrerenderStart() override {}
-  void OnPrerenderStopLoading() override {}
-  void OnPrerenderDomContentLoaded() override {}
-  void OnPrerenderStop() override {}
-
-  mojo::PendingRemote<blink::mojom::PrerenderProcessorClient>
-  BindNewPipeAndPassRemote() {
-    return receiver_.BindNewPipeAndPassRemote();
-  }
-
- private:
-  mojo::Receiver<blink::mojom::PrerenderProcessorClient> receiver_{this};
-};
-
 class PrerenderProcessorTest : public RenderViewHostImplTestHarness {
  public:
   void SetUp() override {
@@ -96,11 +76,10 @@
   auto attributes = blink::mojom::PrerenderAttributes::New();
   attributes->url = kPrerenderingUrl;
   attributes->referrer = blink::mojom::Referrer::New();
-  PrerenderProcessorClient client;
 
   // Start() call should register a new prerender host.
   EXPECT_FALSE(registry->FindHostByUrlForTesting(kPrerenderingUrl));
-  remote->Start(std::move(attributes), client.BindNewPipeAndPassRemote());
+  remote->Start(std::move(attributes));
   remote.FlushForTesting();
   EXPECT_TRUE(registry->FindHostByUrlForTesting(kPrerenderingUrl));
 
@@ -122,11 +101,10 @@
   auto attributes = blink::mojom::PrerenderAttributes::New();
   attributes->url = kPrerenderingUrl;
   attributes->referrer = blink::mojom::Referrer::New();
-  PrerenderProcessorClient client;
 
   // Start() call should register a new prerender host.
   EXPECT_FALSE(registry->FindHostByUrlForTesting(kPrerenderingUrl));
-  remote->Start(std::move(attributes), client.BindNewPipeAndPassRemote());
+  remote->Start(std::move(attributes));
   remote.FlushForTesting();
   EXPECT_TRUE(registry->FindHostByUrlForTesting(kPrerenderingUrl));
 
@@ -149,11 +127,10 @@
   auto attributes = blink::mojom::PrerenderAttributes::New();
   attributes->url = kPrerenderingUrl;
   attributes->referrer = blink::mojom::Referrer::New();
-  PrerenderProcessorClient client;
 
   // Start() call should register a new prerender host.
   EXPECT_FALSE(registry->FindHostByUrlForTesting(kPrerenderingUrl));
-  remote->Start(std::move(attributes), client.BindNewPipeAndPassRemote());
+  remote->Start(std::move(attributes));
   remote.FlushForTesting();
   EXPECT_TRUE(registry->FindHostByUrlForTesting(kPrerenderingUrl));
 
@@ -182,22 +159,20 @@
   auto attributes1 = blink::mojom::PrerenderAttributes::New();
   attributes1->url = kPrerenderingUrl;
   attributes1->referrer = blink::mojom::Referrer::New();
-  PrerenderProcessorClient client1;
 
   // Start() call should register a new prerender host.
   EXPECT_FALSE(registry->FindHostByUrlForTesting(kPrerenderingUrl));
-  remote->Start(std::move(attributes1), client1.BindNewPipeAndPassRemote());
+  remote->Start(std::move(attributes1));
   remote.FlushForTesting();
   EXPECT_TRUE(registry->FindHostByUrlForTesting(kPrerenderingUrl));
 
   auto attributes2 = blink::mojom::PrerenderAttributes::New();
   attributes2->url = kPrerenderingUrl;
   attributes2->referrer = blink::mojom::Referrer::New();
-  PrerenderProcessorClient client2;
 
   // Call Start() again. This should be reported as a bad mojo message.
   ASSERT_TRUE(bad_message_error.empty());
-  remote->Start(std::move(attributes2), client2.BindNewPipeAndPassRemote());
+  remote->Start(std::move(attributes2));
   remote.FlushForTesting();
   EXPECT_EQ(bad_message_error, "PP_START_TWICE");
 }
@@ -221,7 +196,6 @@
   auto attributes1 = blink::mojom::PrerenderAttributes::New();
   attributes1->url = kPrerenderingUrl;
   attributes1->referrer = blink::mojom::Referrer::New();
-  PrerenderProcessorClient client1;
 
   // Call Cancel() before Start(). This should be reported as a bad mojo
   // message.
diff --git a/content/browser/webauth/authenticator_common.cc b/content/browser/webauth/authenticator_common.cc
index 38ea28b..fd7a06fe 100644
--- a/content/browser/webauth/authenticator_common.cc
+++ b/content/browser/webauth/authenticator_common.cc
@@ -641,13 +641,7 @@
 #endif  // defined(OS_WIN)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  // Ignore the ChromeOS u2fd virtual U2F HID device for WebAuthn requests so
-  // that it doesn't collide with the ChromeOS platform authenticator, also
-  // implemented in u2fd.
-  if (base::FeatureList::IsEnabled(device::kWebAuthCrosPlatformAuthenticator) &&
-      !is_u2f_api_request) {
-    constexpr device::VidPid kChromeOsU2fdVidPid{0x18d1, 0x502c};
-    discovery_factory->set_hid_ignore_list({kChromeOsU2fdVidPid});
+  if (base::FeatureList::IsEnabled(device::kWebAuthCrosPlatformAuthenticator)) {
     discovery_factory->set_generate_request_id_callback(
         request_delegate->GetGenerateRequestIdCallback(render_frame_host));
   }
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index cd13549..cfe5829 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -3464,7 +3464,7 @@
 
     bssl::ScopedEVP_MD_CTX md_ctx;
     ASSERT_EQ(EVP_DigestVerifyInit(md_ctx.get(), /*pctx=*/nullptr, test.digest,
-                                   /*engine=*/nullptr, pkey.get()),
+                                   /*e=*/nullptr, pkey.get()),
               1);
     EXPECT_EQ(EVP_DigestVerify(md_ctx.get(), signature.data(), signature.size(),
                                signed_data.data(), signed_data.size()),
@@ -3514,11 +3514,10 @@
   bool SupportsPIN() const override { return true; }
 
   void CollectPIN(
-      uint32_t min_pin_length,
-      base::Optional<int> attempts,
+      CollectPINOptions options,
       base::OnceCallback<void(std::string)> provide_pin_cb) override {
     *collected_pin_ = true;
-    *min_pin_length_ = min_pin_length;
+    *min_pin_length_ = options.min_pin_length;
     base::SequencedTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(provide_pin_cb), kTestPIN));
   }
@@ -3642,11 +3641,15 @@
   DISALLOW_COPY_AND_ASSIGN(UVAuthenticatorImplTest);
 };
 
-// PINExpectation represent expected |attempts| and |min_pin_length| value and
+using PINMode =
+    device::FidoRequestHandlerBase::Observer::CollectPINOptions::Mode;
+
+// PINExpectation represent expected |mode|, |attempts|, |min_pin_length| and
 // the PIN to answer with.
 struct PINExpectation {
-  base::Optional<int> attempts;
+  PINMode mode;
   std::string pin;
+  int attempts;
   uint32_t min_pin_length = device::kMinPinLength;
 };
 
@@ -3665,15 +3668,17 @@
   bool SupportsPIN() const override { return supports_pin_; }
 
   void CollectPIN(
-      uint32_t min_pin_length,
-      base::Optional<int> attempts,
+      CollectPINOptions options,
       base::OnceCallback<void(std::string)> provide_pin_cb) override {
     DCHECK(supports_pin_);
     DCHECK(!expected_.empty());
-    DCHECK(attempts == expected_.front().attempts)
-        << "got: " << attempts.value_or(-1)
-        << " expected: " << expected_.front().attempts.value_or(-1);
-    DCHECK_EQ(expected_.front().min_pin_length, min_pin_length);
+    if (expected_.front().mode == CollectPINOptions::Mode::kChallenge) {
+      DCHECK(options.attempts == expected_.front().attempts)
+          << "got: " << options.attempts
+          << " expected: " << expected_.front().attempts;
+    }
+    DCHECK_EQ(expected_.front().min_pin_length, options.min_pin_length);
+    DCHECK_EQ(expected_.front().mode, options.mode);
     std::string pin = std::move(expected_.front().pin);
     expected_.pop_front();
 
@@ -3857,12 +3862,12 @@
 
               case kSetPIN:
                 // A single PIN prompt to set a PIN is expected.
-                test_client_.expected = {{base::nullopt, kTestPIN}};
+                test_client_.expected = {{PINMode::kSet, kTestPIN}};
                 break;
 
               case kUsePIN:
                 // A single PIN prompt to get the PIN is expected.
-                test_client_.expected = {{8, kTestPIN}};
+                test_client_.expected = {{PINMode::kChallenge, kTestPIN, 8}};
                 break;
 
               default:
@@ -3907,7 +3912,9 @@
   virtual_device_factory_->mutable_state()->pin_retries =
       device::kMaxPinRetries;
 
-  test_client_.expected = {{8, "wrong"}, {7, "wrong"}, {6, "wrong"}};
+  test_client_.expected = {{PINMode::kChallenge, "wrong", 8},
+                           {PINMode::kChallenge, "wrong", 7},
+                           {PINMode::kChallenge, "wrong", 6}};
   EXPECT_EQ(AuthenticatorMakeCredential(make_credential_options()).status,
             AuthenticatorStatus::NOT_ALLOWED_ERROR);
   EXPECT_EQ(5, virtual_device_factory_->mutable_state()->pin_retries);
@@ -3921,7 +3928,7 @@
   virtual_device_factory_->mutable_state()->pin = kTestPIN;
   virtual_device_factory_->mutable_state()->pin_retries = 1;
 
-  test_client_.expected = {{1, "wrong"}};
+  test_client_.expected = {{PINMode::kChallenge, "wrong", 1}};
   EXPECT_EQ(AuthenticatorMakeCredential().status,
             AuthenticatorStatus::NOT_ALLOWED_ERROR);
   EXPECT_EQ(0, virtual_device_factory_->mutable_state()->pin_retries);
@@ -3936,7 +3943,8 @@
       device::kMaxPinRetries;
 
   // Test that we can successfully get a PIN token after a failure.
-  test_client_.expected = {{8, "wrong"}, {7, kTestPIN}};
+  test_client_.expected = {{PINMode::kChallenge, "wrong", 8},
+                           {PINMode::kChallenge, kTestPIN, 7}};
   EXPECT_EQ(AuthenticatorMakeCredential().status, AuthenticatorStatus::SUCCESS);
   EXPECT_EQ(static_cast<int>(device::kMaxPinRetries),
             virtual_device_factory_->mutable_state()->pin_retries);
@@ -3952,7 +3960,8 @@
       });
   virtual_device_factory_->mutable_state()->pin_retries =
       device::kMaxPinRetries;
-  test_client_.expected = {{device::kMaxPinRetries, kTestPIN}};
+  test_client_.expected = {
+      {PINMode::kChallenge, kTestPIN, device::kMaxPinRetries}};
   EXPECT_EQ(AuthenticatorMakeCredential().status, AuthenticatorStatus::SUCCESS);
   EXPECT_EQ(taps, 1);
 }
@@ -3982,7 +3991,8 @@
   AuthenticatorEnvironmentImpl::GetInstance()
       ->ReplaceDefaultDiscoveryFactoryForTesting(std::move(discovery));
 
-  test_client_.expected = {{device::kMaxPinRetries, kTestPIN}};
+  test_client_.expected = {
+      {PINMode::kChallenge, kTestPIN, device::kMaxPinRetries}};
   EXPECT_EQ(AuthenticatorMakeCredential().status, AuthenticatorStatus::SUCCESS);
   EXPECT_EQ(taps, 2);
 }
@@ -4000,7 +4010,8 @@
   config.u2f_support = true;
   virtual_device_factory_->SetCtap2Config(config);
   virtual_device_factory_->mutable_state()->pin = kTestPIN;
-  test_client_.expected = {{device::kMaxPinRetries, kTestPIN}};
+  test_client_.expected = {
+      {PINMode::kChallenge, kTestPIN, device::kMaxPinRetries}};
 
   MakeCredentialResult result =
       AuthenticatorMakeCredential(make_credential_options(
@@ -4053,7 +4064,7 @@
   config.ctap2_versions = {device::Ctap2Version::kCtap2_1};
   virtual_device_factory_->SetCtap2Config(config);
   virtual_device_factory_->mutable_state()->min_pin_length = 6;
-  test_client_.expected = {{base::nullopt, "123456", 6}};
+  test_client_.expected = {{PINMode::kSet, "123456", 0, 6}};
 
   MakeCredentialResult result =
       AuthenticatorMakeCredential(make_credential_options());
@@ -4072,7 +4083,8 @@
   virtual_device_factory_->SetCtap2Config(config);
   virtual_device_factory_->mutable_state()->min_pin_length = 6;
   virtual_device_factory_->mutable_state()->pin = "123456";
-  test_client_.expected = {{device::kMaxPinRetries, "123456", 6}};
+  test_client_.expected = {
+      {PINMode::kChallenge, "123456", device::kMaxPinRetries, 6}};
 
   MakeCredentialResult result =
       AuthenticatorMakeCredential(make_credential_options());
@@ -4095,9 +4107,9 @@
   virtual_device_factory_->mutable_state()->pin_retries =
       device::kMaxPinRetries;
   virtual_device_factory_->mutable_state()->min_pin_length = 6;
-  test_client_.expected = {
-      {device::kMaxPinRetries, kTestPIN, device::kMinPinLength},
-      {base::nullopt, "567890", 6}};
+  test_client_.expected = {{PINMode::kChallenge, kTestPIN,
+                            device::kMaxPinRetries, device::kMinPinLength},
+                           {PINMode::kChange, "567890", 0, 6}};
 
   MakeCredentialResult result =
       AuthenticatorMakeCredential(make_credential_options());
@@ -4163,7 +4175,7 @@
 
               case kUsePIN:
                 // A single prompt to get the PIN is expected.
-                test_client_.expected = {{8, kTestPIN}};
+                test_client_.expected = {{PINMode::kChallenge, kTestPIN, 8}};
                 break;
 
               default:
@@ -4210,7 +4222,9 @@
   ASSERT_TRUE(virtual_device_factory_->mutable_state()->InjectRegistration(
       options->allow_credentials[0].id(), kTestRelyingPartyId));
 
-  test_client_.expected = {{8, "wrong"}, {7, "wrong"}, {6, "wrong"}};
+  test_client_.expected = {{PINMode::kChallenge, "wrong", 8},
+                           {PINMode::kChallenge, "wrong", 7},
+                           {PINMode::kChallenge, "wrong", 6}};
   EXPECT_EQ(AuthenticatorGetAssertion(std::move(options)).status,
             AuthenticatorStatus::NOT_ALLOWED_ERROR);
   EXPECT_EQ(5, virtual_device_factory_->mutable_state()->pin_retries);
@@ -4228,7 +4242,7 @@
   ASSERT_TRUE(virtual_device_factory_->mutable_state()->InjectRegistration(
       options->allow_credentials[0].id(), kTestRelyingPartyId));
 
-  test_client_.expected = {{1, "wrong"}};
+  test_client_.expected = {{PINMode::kChallenge, "wrong", 1}};
   EXPECT_EQ(AuthenticatorGetAssertion(std::move(options)).status,
             AuthenticatorStatus::NOT_ALLOWED_ERROR);
   EXPECT_EQ(0, virtual_device_factory_->mutable_state()->pin_retries);
@@ -4248,7 +4262,8 @@
   PublicKeyCredentialRequestOptionsPtr options = get_credential_options();
   ASSERT_TRUE(virtual_device_factory_->mutable_state()->InjectRegistration(
       options->allow_credentials[0].id(), kTestRelyingPartyId));
-  test_client_.expected = {{device::kMaxPinRetries, kTestPIN}};
+  test_client_.expected = {
+      {PINMode::kChallenge, kTestPIN, device::kMaxPinRetries}};
   EXPECT_EQ(AuthenticatorGetAssertion(std::move(options)).status,
             AuthenticatorStatus::SUCCESS);
   EXPECT_EQ(taps, 1);
@@ -4282,7 +4297,8 @@
   AuthenticatorEnvironmentImpl::GetInstance()
       ->ReplaceDefaultDiscoveryFactoryForTesting(std::move(discovery));
 
-  test_client_.expected = {{device::kMaxPinRetries, kTestPIN}};
+  test_client_.expected = {
+      {PINMode::kChallenge, kTestPIN, device::kMaxPinRetries}};
   EXPECT_EQ(AuthenticatorGetAssertion(std::move(options)).status,
             AuthenticatorStatus::SUCCESS);
   EXPECT_EQ(taps, 2);
@@ -4301,7 +4317,8 @@
       get_credential_options(device::UserVerificationRequirement::kDiscouraged);
   ASSERT_TRUE(virtual_device_factory_->mutable_state()->InjectRegistration(
       options->allow_credentials[0].id(), kTestRelyingPartyId));
-  test_client_.expected = {{device::kMaxPinRetries, kTestPIN}};
+  test_client_.expected = {
+      {PINMode::kChallenge, kTestPIN, device::kMaxPinRetries}};
 
   GetAssertionResult result = AuthenticatorGetAssertion(std::move(options));
   EXPECT_EQ(result.status, AuthenticatorStatus::SUCCESS);
@@ -4371,7 +4388,8 @@
       virtual_device_factory_->mutable_state()->pin_retries =
           device::kMaxPinRetries;
       virtual_device_factory_->SetCtap2Config(config);
-      test_client_.expected = {{device::kMaxPinRetries, kTestPIN}};
+      test_client_.expected = {
+          {PINMode::kChallenge, kTestPIN, device::kMaxPinRetries}};
       // Since converting to U2F isn't possible, this will trigger a PIN prompt
       // and succeed because the device does actually support the algorithm.
       expected_to_succeed = true;
@@ -4430,7 +4448,8 @@
       // PRF request is higher priority than avoiding a PIN prompt. (The PIN
       // test infrastructure will CHECK if |expected| is set and not used.)
       options->prf_enable = true;
-      test_client_.expected = {{device::kMaxPinRetries, kTestPIN}};
+      test_client_.expected = {
+          {PINMode::kChallenge, kTestPIN, device::kMaxPinRetries}};
     } else {
       // If PRF is requested, but the authenticator doesn't support it, then we
       // should still use U2F.
@@ -4982,8 +5001,7 @@
   bool SupportsPIN() const override { return true; }
 
   void CollectPIN(
-      uint32_t min_pin_length,
-      base::Optional<int> attempts,
+      CollectPINOptions options,
       base::OnceCallback<void(std::string)> provide_pin_cb) override {
     base::SequencedTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(provide_pin_cb), kTestPIN));
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/OWNERS b/content/public/android/java/src/org/chromium/content/browser/input/OWNERS
index 2878f5c..395fd997 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/OWNERS
+++ b/content/public/android/java/src/org/chromium/content/browser/input/OWNERS
@@ -1 +1 @@
-changwan@chromium.org
+ctzsm@chromium.org
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/OWNERS b/content/public/android/javatests/src/org/chromium/content/browser/input/OWNERS
index 2878f5c..395fd997 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/OWNERS
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/OWNERS
@@ -1 +1 @@
-changwan@chromium.org
+ctzsm@chromium.org
diff --git a/content/public/android/junit/src/org/chromium/content/browser/input/OWNERS b/content/public/android/junit/src/org/chromium/content/browser/input/OWNERS
index 2878f5c..395fd997 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/input/OWNERS
+++ b/content/public/android/junit/src/org/chromium/content/browser/input/OWNERS
@@ -1 +1 @@
-changwan@chromium.org
+ctzsm@chromium.org
diff --git a/content/public/browser/authenticator_request_client_delegate.cc b/content/public/browser/authenticator_request_client_delegate.cc
index bba28ef..3193b5e 100644
--- a/content/public/browser/authenticator_request_client_delegate.cc
+++ b/content/public/browser/authenticator_request_client_delegate.cc
@@ -133,8 +133,7 @@
 }
 
 void AuthenticatorRequestClientDelegate::CollectPIN(
-    uint32_t min_pin_length,
-    base::Optional<int> attempts,
+    CollectPINOptions options,
     base::OnceCallback<void(std::string)> provide_pin_cb) {
   NOTREACHED();
 }
diff --git a/content/public/browser/authenticator_request_client_delegate.h b/content/public/browser/authenticator_request_client_delegate.h
index 8e91def..30f9b29 100644
--- a/content/public/browser/authenticator_request_client_delegate.h
+++ b/content/public/browser/authenticator_request_client_delegate.h
@@ -239,8 +239,7 @@
   void FidoAuthenticatorRemoved(base::StringPiece device_id) override;
   bool SupportsPIN() const override;
   void CollectPIN(
-      uint32_t min_pin_length,
-      base::Optional<int> attempts,
+      CollectPINOptions options,
       base::OnceCallback<void(std::string)> provide_pin_cb) override;
   void StartBioEnrollment(base::OnceClosure next_callback) override;
   void OnSampleCollected(int bio_samples_remaining) override;
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index d24da83..829ad39 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -1689,14 +1689,12 @@
 
 TEST_F(RenderViewImplTextInputStateChanged, ActiveElementGetLayoutBounds) {
   // Load an HTML page consisting of one input fields.
-  LoadHTML(
-      "<html>"
-      "<head>"
-      "</head>"
-      "<body>"
-      "<input id=\"test\" type=\"text\"></input>"
-      "</body>"
-      "</html>");
+  LoadHTML(R"HTML(
+    <style>
+      input { position: fixed; }
+    </style>
+      <input id='test' type='text'></input>
+    )HTML");
   ClearState();
   // Create an EditContext with control and selection bounds and set input
   // panel policy to auto.
@@ -1722,6 +1720,82 @@
       updated_states()[0]->edit_context_control_bounds.value());
   EXPECT_EQ(actual_active_element_control_bounds,
             expected_control_bounds_in_dips);
+
+  // Update the position of the element and that should trigger control bounds
+  // update to IME.
+  ExecuteJavaScriptForTests(
+      "document.getElementById('test').style.top = 50 + "
+      "\"px\";document.getElementById('test').style.left = 350 + \"px\";");
+  // This RunLoop is waiting for styles to be processed for the active element.
+  base::RunLoop run_loop2;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                run_loop2.QuitClosure());
+  run_loop2.Run();
+  // Update the IME status and verify if our IME backend sends an IPC message
+  // to notify layout bounds of the EditContext.
+  main_frame_widget()->UpdateTextInputState();
+  // This RunLoop is to flush the TextInputState update message.
+  base::RunLoop run_loop3;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                run_loop3.QuitClosure());
+  run_loop3.Run();
+  EXPECT_EQ(2u, updated_states().size());
+  controller->GetLayoutBounds(&expected_control_bounds, &temp_selection_bounds);
+  gfx::Rect expected_control_bounds_in_dips_updated =
+      main_frame_widget()->BlinkSpaceToEnclosedDIPs(expected_control_bounds);
+  actual_active_element_control_bounds =
+      updated_states()[1]->edit_context_control_bounds.value();
+  EXPECT_EQ(actual_active_element_control_bounds,
+            expected_control_bounds_in_dips_updated);
+  // Also check that the updated bounds are different from last reported bounds.
+  EXPECT_NE(expected_control_bounds_in_dips_updated,
+            expected_control_bounds_in_dips);
+}
+
+TEST_F(RenderViewImplTextInputStateChanged,
+       ActiveElementMultipleLayoutBoundsUpdates) {
+  // Load an HTML page consisting of one input fields.
+  LoadHTML(R"HTML(
+      <input id='test' type='text'></input>
+    )HTML");
+  ClearState();
+  // Create an EditContext with control and selection bounds and set input
+  // panel policy to auto.
+  ExecuteJavaScriptForTests("document.getElementById('test').focus();");
+  // This RunLoop is waiting for focus to be processed for the active element.
+  base::RunLoop run_loop;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                run_loop.QuitClosure());
+  run_loop.Run();
+  // Update the IME status and verify if our IME backend sends an IPC message
+  // to notify layout bounds of the EditContext.
+  main_frame_widget()->UpdateTextInputState();
+  // This RunLoop is to flush the TextInputState update message.
+  base::RunLoop run_loop2;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                run_loop2.QuitClosure());
+  run_loop2.Run();
+  EXPECT_EQ(1u, updated_states().size());
+  blink::WebInputMethodController* controller =
+      frame()->GetWebFrame()->GetInputMethodController();
+  blink::WebRect expected_control_bounds;
+  blink::WebRect temp_selection_bounds;
+  controller->GetLayoutBounds(&expected_control_bounds, &temp_selection_bounds);
+  gfx::Rect expected_control_bounds_in_dips =
+      main_frame_widget()->BlinkSpaceToEnclosedDIPs(expected_control_bounds);
+  gfx::Rect actual_active_element_control_bounds(
+      updated_states()[0]->edit_context_control_bounds.value());
+  EXPECT_EQ(actual_active_element_control_bounds,
+            expected_control_bounds_in_dips);
+
+  // No updates in control bounds so this shouldn't trigger an update to IME.
+  main_frame_widget()->UpdateTextInputState();
+  // This RunLoop is to flush the TextInputState update message.
+  base::RunLoop run_loop3;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                run_loop3.QuitClosure());
+  run_loop3.Run();
+  EXPECT_EQ(1u, updated_states().size());
 }
 
 TEST_F(RenderViewImplTextInputStateChanged, VirtualKeyboardPolicyAuto) {
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 3fdc206..3f001ba8 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -387,7 +387,6 @@
     "//third_party/blink/public:blink",
     "//third_party/blink/public:test_support",
     "//third_party/blink/public/strings:strings_grit",
-    "//ui/gl:test_support",
   ]
 
   deps = [
@@ -460,6 +459,7 @@
     "//ui/events/blink",
     "//ui/gfx:test_support",
     "//ui/gl",
+    "//ui/gl:test_support",
     "//ui/native_theme",
     "//ui/resources",
     "//ui/shell_dialogs:shell_dialogs",
diff --git a/content/test/trust_token_browsertest.cc b/content/test/trust_token_browsertest.cc
index 25b24d7..023e185 100644
--- a/content/test/trust_token_browsertest.cc
+++ b/content/test/trust_token_browsertest.cc
@@ -65,7 +65,6 @@
 MATCHER_P(HasHeader, name, base::StringPrintf("Has header %s", name)) {
   if (!arg.headers.HasHeader(name)) {
     *result_listener << base::StringPrintf("%s wasn't present", name);
-    LOG(INFO) << __LINE__;
     return false;
   }
   *result_listener << base::StringPrintf("%s was present", name);
@@ -80,10 +79,8 @@
   std::string header;
   if (!arg.headers.GetHeader(name, &header)) {
     *result_listener << base::StringPrintf("%s wasn't present", name);
-    LOG(INFO) << __LINE__;
     return false;
   }
-  LOG(INFO) << header;
   return ExplainMatchResult(other_matcher, header, result_listener);
 }
 
diff --git a/device/fido/auth_token_requester.cc b/device/fido/auth_token_requester.cc
index ebd721b..33348ad5 100644
--- a/device/fido/auth_token_requester.cc
+++ b/device/fido/auth_token_requester.cc
@@ -261,6 +261,7 @@
       case CtapDeviceResponseCode::kCtap2ErrPinPolicyViolation:
         // The user needs to set a new PIN before they can use the device.
         delegate_->CollectNewPIN(authenticator_->NewMinPINLength(),
+                                 /*force_pin_change=*/true,
                                  base::BindOnce(&AuthTokenRequester::HaveNewPIN,
                                                 weak_factory_.GetWeakPtr()));
         return;
@@ -286,6 +287,7 @@
 void AuthTokenRequester::ObtainTokenFromNewPIN() {
   NotifyAuthenticatorSelected();
   delegate_->CollectNewPIN(authenticator_->NewMinPINLength(),
+                           /*force_pin_change=*/false,
                            base::BindOnce(&AuthTokenRequester::HaveNewPIN,
                                           weak_factory_.GetWeakPtr()));
 }
diff --git a/device/fido/auth_token_requester.h b/device/fido/auth_token_requester.h
index 9a7d6e5d..e9c4a8b 100644
--- a/device/fido/auth_token_requester.h
+++ b/device/fido/auth_token_requester.h
@@ -79,11 +79,14 @@
 
     // CollectNewPIN is invoked to prompt the user to enter a new PIN for an
     // authenticator. |min_pin_length| is the minimum length for a valid PIN.
+    // |force_pin_change| is true iff the user must change the PIN on their
+    // security key before using it.
     //
     // The callee must provide the PIN by invoking |provide_pin_cb|. The
     // callback is weakly bound and safe to invoke even after the
     // AuthTokenRequester was freed.
     virtual void CollectNewPIN(uint32_t min_pin_length,
+                               bool force_pin_change,
                                ProvidePINCallback provide_pin_cb) = 0;
 
     // CollectExistingPIN is invoked to prompt the user to provide the existing
diff --git a/device/fido/auth_token_requester_unittest.cc b/device/fido/auth_token_requester_unittest.cc
index 8d54953..abab19e6 100644
--- a/device/fido/auth_token_requester_unittest.cc
+++ b/device/fido/auth_token_requester_unittest.cc
@@ -45,6 +45,7 @@
   bool pin_was_collected() { return pin_was_collected_; }
   bool internal_uv_was_retried() { return internal_uv_num_retries_ > 0u; }
   size_t internal_uv_num_retries() { return internal_uv_num_retries_; }
+  bool forced_pin_change() { return forced_pin_change_; }
   bool internal_uv_was_locked() { return internal_uv_was_locked_; }
 
  private:
@@ -52,10 +53,12 @@
   void AuthenticatorSelectedForPINUVAuthToken(
       FidoAuthenticator* authenticator) override {}
   void CollectNewPIN(uint32_t min_pin_length,
+                     bool force_pin_change,
                      ProvidePINCallback provide_pin_cb) override {
     DCHECK(!pin_.empty());
     pin_was_set_ = true;
     min_pin_length_ = min_pin_length;
+    forced_pin_change_ = force_pin_change;
     std::move(provide_pin_cb).Run(pin_);
   }
   void CollectExistingPIN(int attempts,
@@ -89,6 +92,7 @@
 
   bool pin_was_collected_ = false;
   bool pin_was_set_ = false;
+  bool forced_pin_change_ = false;
   size_t internal_uv_num_retries_ = 0u;
   uint32_t min_pin_length_ = 0;
   bool internal_uv_was_locked_ = false;
@@ -235,6 +239,7 @@
     }
     EXPECT_FALSE(delegate_->internal_uv_was_retried());
     EXPECT_FALSE(delegate_->internal_uv_was_locked());
+    EXPECT_FALSE(delegate_->forced_pin_change());
   }
 }
 
@@ -320,6 +325,7 @@
                         UserVerificationAvailability::kSupportedAndConfigured);
       EXPECT_FALSE(delegate_->internal_uv_was_retried());
       EXPECT_FALSE(delegate_->internal_uv_was_locked());
+      EXPECT_FALSE(delegate_->forced_pin_change());
     } else {
       EXPECT_EQ(*delegate_->result(),
                 AuthTokenRequester::Result::kPreTouchUnsatisfiableRequest);
@@ -328,6 +334,7 @@
       EXPECT_FALSE(delegate_->pin_was_collected());
       EXPECT_FALSE(delegate_->internal_uv_was_retried());
       EXPECT_FALSE(delegate_->internal_uv_was_locked());
+      EXPECT_FALSE(delegate_->forced_pin_change());
     }
   }
 }
@@ -354,6 +361,7 @@
   EXPECT_TRUE(delegate_->pin_was_collected());
   EXPECT_FALSE(delegate_->internal_uv_was_retried());
   EXPECT_FALSE(delegate_->internal_uv_was_locked());
+  EXPECT_FALSE(delegate_->forced_pin_change());
 }
 
 TEST_F(AuthTokenRequesterTest, PINHardLock) {
@@ -378,6 +386,7 @@
   EXPECT_FALSE(delegate_->pin_was_collected());
   EXPECT_FALSE(delegate_->internal_uv_was_retried());
   EXPECT_FALSE(delegate_->internal_uv_was_locked());
+  EXPECT_FALSE(delegate_->forced_pin_change());
 }
 
 TEST_F(AuthTokenRequesterTest, UVLockedPINFallback) {
@@ -402,6 +411,31 @@
   EXPECT_TRUE(delegate_->pin_was_collected());
   EXPECT_EQ(delegate_->internal_uv_num_retries(), 2u);
   EXPECT_TRUE(delegate_->internal_uv_was_locked());
+  EXPECT_FALSE(delegate_->forced_pin_change());
+}
+
+TEST_F(AuthTokenRequesterTest, ForcePINChange) {
+  VirtualCtap2Device::Config config;
+  config.pin_uv_auth_token_support = true;
+  config.ctap2_versions = {std::begin(kCtap2Versions2_1),
+                           std::end(kCtap2Versions2_1)};
+  config.min_pin_length_support = true;
+  auto state = base::MakeRefCounted<VirtualFidoDevice::State>();
+  state->force_pin_change = true;
+
+  RunTestCase(std::move(config), state,
+              TestCase{
+                  ClientPinAvailability::kSupportedAndPinSet,
+                  UserVerificationAvailability::kNotSupported,
+                  true,
+              });
+
+  EXPECT_EQ(*delegate_->result(), AuthTokenRequester::Result::kSuccess);
+  EXPECT_TRUE(delegate_->response());
+  EXPECT_TRUE(delegate_->pin_was_set());
+  EXPECT_TRUE(delegate_->pin_was_collected());
+  EXPECT_FALSE(delegate_->internal_uv_was_locked());
+  EXPECT_TRUE(delegate_->forced_pin_change());
 }
 
 }  // namespace
diff --git a/device/fido/ble_adapter_manager_unittest.cc b/device/fido/ble_adapter_manager_unittest.cc
index 0989131..87b3b2f 100644
--- a/device/fido/ble_adapter_manager_unittest.cc
+++ b/device/fido/ble_adapter_manager_unittest.cc
@@ -47,10 +47,9 @@
                void(const FidoAuthenticator& authenticator));
   MOCK_METHOD1(FidoAuthenticatorRemoved, void(base::StringPiece device_id));
   MOCK_CONST_METHOD0(SupportsPIN, bool());
-  MOCK_METHOD3(CollectPIN,
-               void(uint32_t,
-                    base::Optional<int>,
-                    base::OnceCallback<void(std::string)>));
+  MOCK_METHOD2(CollectPIN,
+               void(CollectPINOptions, base::OnceCallback<void(std::string)>));
+  MOCK_METHOD0(OnForcePINChange, void());
   MOCK_METHOD1(StartBioEnrollment, void(base::OnceClosure));
   MOCK_METHOD1(OnSampleCollected, void(int));
   MOCK_METHOD0(FinishCollectToken, void());
diff --git a/device/fido/fido_request_handler_base.cc b/device/fido/fido_request_handler_base.cc
index 7eb2d155..d5c9c63f 100644
--- a/device/fido/fido_request_handler_base.cc
+++ b/device/fido/fido_request_handler_base.cc
@@ -41,7 +41,7 @@
 FidoRequestHandlerBase::TransportAvailabilityInfo::
     ~TransportAvailabilityInfo() = default;
 
-// FidoRequestHandlerBase::Observer ----------------------
+// FidoRequestHandlerBase::Observer -------------------------------------------
 
 FidoRequestHandlerBase::Observer::~Observer() = default;
 
diff --git a/device/fido/fido_request_handler_base.h b/device/fido/fido_request_handler_base.h
index 66eaf2d..d20950be 100644
--- a/device/fido/fido_request_handler_base.h
+++ b/device/fido/fido_request_handler_base.h
@@ -22,6 +22,7 @@
 #include "base/optional.h"
 #include "base/strings/string_piece_forward.h"
 #include "build/build_config.h"
+#include "device/fido/fido_constants.h"
 #include "device/fido/fido_discovery_base.h"
 #include "device/fido/fido_transport_protocol.h"
 
@@ -100,6 +101,29 @@
 
   class COMPONENT_EXPORT(DEVICE_FIDO) Observer {
    public:
+    struct COMPONENT_EXPORT(DEVICE_FIDO) CollectPINOptions {
+      enum class Mode {
+        // Indicates a new PIN is being set. |attempts| should be ignored.
+        kSet,
+
+        // The existing PIN must be changed before using this authenticator.
+        kChange,
+
+        // The existing PIN is being collected to prove user verification.
+        kChallenge
+      };
+
+      // Why this PIN is being collected.
+      Mode mode;
+
+      // The minimum PIN length the authenticator will accept for the PIN.
+      uint32_t min_pin_length = device::kMinPinLength;
+
+      // The number of attempts remaining before a hard lock. Should be ignored
+      // unless |mode| is kChallenge.
+      int attempts = 0;
+    };
+
     virtual ~Observer();
 
     // This method will not be invoked until the observer is set.
@@ -133,8 +157,7 @@
     // to set a PIN, or contains the number of PIN attempts remaining before a
     // hard lock.
     virtual void CollectPIN(
-        uint32_t min_pin_length,
-        base::Optional<int> attempts,
+        CollectPINOptions options,
         base::OnceCallback<void(std::string)> provide_pin_cb) = 0;
 
     virtual void FinishCollectToken() = 0;
diff --git a/device/fido/fido_request_handler_unittest.cc b/device/fido/fido_request_handler_unittest.cc
index 1ea9ae2..775e919 100644
--- a/device/fido/fido_request_handler_unittest.cc
+++ b/device/fido/fido_request_handler_unittest.cc
@@ -113,8 +113,7 @@
   bool SupportsPIN() const override { return false; }
 
   void CollectPIN(
-      uint32_t min_pin_length,
-      base::Optional<int> attempts,
+      CollectPINOptions options,
       base::OnceCallback<void(std::string)> provide_pin_cb) override {
     NOTREACHED();
   }
diff --git a/device/fido/get_assertion_handler_unittest.cc b/device/fido/get_assertion_handler_unittest.cc
index 0805fe7..6dc718ac 100644
--- a/device/fido/get_assertion_handler_unittest.cc
+++ b/device/fido/get_assertion_handler_unittest.cc
@@ -761,8 +761,7 @@
   void FidoAuthenticatorRemoved(base::StringPiece device_id) override {}
   bool SupportsPIN() const override { return false; }
   void CollectPIN(
-      uint32_t min_pin_length,
-      base::Optional<int> attempts,
+      CollectPINOptions options,
       base::OnceCallback<void(std::string)> provide_pin_cb) override {
     NOTREACHED();
   }
diff --git a/device/fido/get_assertion_request_handler.cc b/device/fido/get_assertion_request_handler.cc
index 4e0c51c..a17694c 100644
--- a/device/fido/get_assertion_request_handler.cc
+++ b/device/fido/get_assertion_request_handler.cc
@@ -439,10 +439,14 @@
 
 void GetAssertionRequestHandler::CollectNewPIN(
     uint32_t min_pin_length,
+    bool force_pin_change,
     ProvidePINCallback provide_pin_cb) {
   DCHECK_EQ(state_, State::kWaitingForToken);
-  observer()->CollectPIN(min_pin_length, /*attempts=*/base::nullopt,
-                         std::move(provide_pin_cb));
+  observer()->CollectPIN(
+      {.mode = force_pin_change ? Observer::CollectPINOptions::Mode::kChange
+                                : Observer::CollectPINOptions::Mode::kSet,
+       .min_pin_length = min_pin_length},
+      std::move(provide_pin_cb));
 }
 
 void GetAssertionRequestHandler::CollectExistingPIN(
@@ -450,7 +454,10 @@
     uint32_t min_pin_length,
     ProvidePINCallback provide_pin_cb) {
   DCHECK_EQ(state_, State::kWaitingForToken);
-  observer()->CollectPIN(min_pin_length, attempts, std::move(provide_pin_cb));
+  observer()->CollectPIN({.mode = Observer::CollectPINOptions::Mode::kChallenge,
+                          .min_pin_length = min_pin_length,
+                          .attempts = attempts},
+                         std::move(provide_pin_cb));
 }
 
 void GetAssertionRequestHandler::PromptForInternalUVRetry(int attempts) {
diff --git a/device/fido/get_assertion_request_handler.h b/device/fido/get_assertion_request_handler.h
index 38800d48..cab048e 100644
--- a/device/fido/get_assertion_request_handler.h
+++ b/device/fido/get_assertion_request_handler.h
@@ -93,6 +93,7 @@
   void AuthenticatorSelectedForPINUVAuthToken(
       FidoAuthenticator* authenticator) override;
   void CollectNewPIN(uint32_t min_pin_length,
+                     bool force_pin_change,
                      ProvidePINCallback provide_pin_cb) override;
   void CollectExistingPIN(int attempts,
                           uint32_t min_pin_length,
diff --git a/device/fido/make_credential_request_handler.cc b/device/fido/make_credential_request_handler.cc
index c1a6e65..0994210 100644
--- a/device/fido/make_credential_request_handler.cc
+++ b/device/fido/make_credential_request_handler.cc
@@ -486,10 +486,14 @@
 
 void MakeCredentialRequestHandler::CollectNewPIN(
     uint32_t min_pin_length,
+    bool force_pin_change,
     ProvidePINCallback provide_pin_cb) {
   DCHECK_EQ(state_, State::kWaitingForToken);
-  observer()->CollectPIN(min_pin_length, /*attempts=*/base::nullopt,
-                         std::move(provide_pin_cb));
+  observer()->CollectPIN(
+      {.mode = force_pin_change ? Observer::CollectPINOptions::Mode::kChange
+                                : Observer::CollectPINOptions::Mode::kSet,
+       .min_pin_length = min_pin_length},
+      std::move(provide_pin_cb));
 }
 
 void MakeCredentialRequestHandler::CollectExistingPIN(
@@ -497,7 +501,10 @@
     uint32_t min_pin_length,
     ProvidePINCallback provide_pin_cb) {
   DCHECK_EQ(state_, State::kWaitingForToken);
-  observer()->CollectPIN(min_pin_length, attempts, std::move(provide_pin_cb));
+  observer()->CollectPIN({.mode = Observer::CollectPINOptions::Mode::kChallenge,
+                          .min_pin_length = min_pin_length,
+                          .attempts = attempts},
+                         std::move(provide_pin_cb));
 }
 
 void MakeCredentialRequestHandler::PromptForInternalUVRetry(int attempts) {
diff --git a/device/fido/make_credential_request_handler.h b/device/fido/make_credential_request_handler.h
index 610ec6f91..e8b5a4b4 100644
--- a/device/fido/make_credential_request_handler.h
+++ b/device/fido/make_credential_request_handler.h
@@ -151,6 +151,7 @@
   void AuthenticatorSelectedForPINUVAuthToken(
       FidoAuthenticator* authenticator) override;
   void CollectNewPIN(uint32_t min_pin_length,
+                     bool force_pin_change,
                      ProvidePINCallback provide_pin_cb) override;
   void CollectExistingPIN(int attempts,
                           uint32_t min_pin_length,
diff --git a/device/vr/android/arcore/arcore_impl.cc b/device/vr/android/arcore/arcore_impl.cc
index 2ce9f55a..94cb36a6 100644
--- a/device/vr/android/arcore/arcore_impl.cc
+++ b/device/vr/android/arcore/arcore_impl.cc
@@ -7,6 +7,7 @@
 #include "base/android/jni_android.h"
 #include "base/bind.h"
 #include "base/containers/span.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/numerics/checked_math.h"
 #include "base/numerics/math_constants.h"
 #include "base/optional.h"
@@ -1760,6 +1761,8 @@
                           << num_planes;
 
   if (time_delta > previous_depth_data_time_) {
+    // The depth data is more recent than what was previously returned, we need
+    // to send the latest information back:
     mojom::XRDepthDataUpdatedPtr result = mojom::XRDepthDataUpdated::New();
 
     result->time_delta = time_delta;
@@ -1782,6 +1785,26 @@
       return nullptr;
     }
 
+    // Log a histogram w/ the number of entries in the depth buffer to make sure
+    // we have a way of measuring the impact of the decision to suppress
+    // too-high-resolution depth buffers. Assuming various common aspect ratios
+    // & fixing the width to 160 pixels, the total number of pixels varies from
+    // ~6000 to ~20000, and w/ the threshold below set to 43200 pixels, the
+    // custom count from 5000 to 55000 with bucket size of 1000 should give us
+    // sufficient granularity of data.
+    UMA_HISTOGRAM_CUSTOM_COUNTS("XR.ARCore.DepthBufferSizeInPixels",
+                                buffer_size / 2, 5000, 55000, 50);
+
+    if (buffer_size / 2 > 240 * 180) {
+      // ARCore should report depth data buffers w/ resolution in the ballpark
+      // of 160x120. If the number of data entries is higher than 240 * 180
+      // (=43200), we should not return it. The threshold was picked by
+      // multiplying each expected dimension (160x120) by 1.5. Note that this
+      // translates to 2.25 increase in allowed number of pixels compared to
+      // the currently expected resolution.
+      return nullptr;
+    }
+
     mojo_base::BigBuffer pixels(buffer_size);
 
     // Interpret BigBuffer's data as a width by height array of uint16_t's and
@@ -1805,6 +1828,8 @@
     return mojom::XRDepthData::NewUpdatedDepthData(std::move(result));
   }
 
+  // We don't have more recent data than what was already returned, inform the
+  // caller that previously returned data is still valid:
   return mojom::XRDepthData::NewDataStillValid(
       mojom::XRDepthDataStillValid::New());
 }
diff --git a/gpu/config/skia_limits.cc b/gpu/config/skia_limits.cc
index 82fb1dc..5293e43 100644
--- a/gpu/config/skia_limits.cc
+++ b/gpu/config/skia_limits.cc
@@ -25,12 +25,7 @@
 #if !defined(OS_NACL)
   // The limit of the bytes allocated toward GPU resources in the GrContext's
   // GPU cache.
-#if defined(OS_FUCHSIA)
-  // Reduce protected budget on fuchsia due to https://fxb/36620.
-  constexpr size_t kMaxLowEndGaneshResourceCacheBytes = 24 * 1024 * 1024;
-#else
   constexpr size_t kMaxLowEndGaneshResourceCacheBytes = 48 * 1024 * 1024;
-#endif  // defined(OS_FUCHSIA)
   constexpr size_t kMaxHighEndGaneshResourceCacheBytes = 256 * 1024 * 1024;
   // Limits for glyph cache textures.
   constexpr size_t kMaxLowEndGlyphCacheTextureBytes = 1024 * 512 * 4;
diff --git a/infra/config/generated/commit-queue.cfg b/infra/config/generated/commit-queue.cfg
index 5caf045..47c487d 100644
--- a/infra/config/generated/commit-queue.cfg
+++ b/infra/config/generated/commit-queue.cfg
@@ -1035,6 +1035,10 @@
         includable_only: true
       }
       builders {
+        name: "chromium/try/linux-example-builder"
+        includable_only: true
+      }
+      builders {
         name: "chromium/try/linux-gcc-rel"
         includable_only: true
       }
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index 08ec6cc..a059662 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -33656,6 +33656,61 @@
       }
     }
     builders {
+      name: "linux-example-builder"
+      swarming_host: "chromium-swarm.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      dimensions: "builderless:1"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-16.04"
+      dimensions: "pool:luci.chromium.try"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/master"
+        cmd: "recipes"
+      }
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
+      execution_timeout_secs: 14400
+      expiration_secs: 7200
+      caches {
+        name: "win_toolchain"
+        path: "win_toolchain"
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      task_template_canary_percentage {
+        value: 5
+      }
+      experiments {
+        key: "chromium.resultdb.result_sink"
+        value: 100
+      }
+      experiments {
+        key: "luci.use_realms"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "luci-resultdb"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "luci-resultdb"
+          dataset: "chromium"
+          table: "gpu_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+"
+            }
+          }
+        }
+      }
+    }
+    builders {
       name: "linux-gcc-rel"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg
index bb47780..4c0782fc 100644
--- a/infra/config/generated/luci-milo.cfg
+++ b/infra/config/generated/luci-milo.cfg
@@ -9394,6 +9394,31 @@
     short_name: "bld"
   }
   builders {
+    name: "buildbucket/luci.chrome.official/mac64"
+    category: "official|mac"
+    short_name: "64"
+  }
+  builders {
+    name: "buildbucket/luci.chrome.official/mac-arm64"
+    category: "official|mac"
+    short_name: "arm64"
+  }
+  builders {
+    name: "buildbucket/luci.chrome.official/win-asan"
+    category: "official|win"
+    short_name: "asan"
+  }
+  builders {
+    name: "buildbucket/luci.chrome.official/win-clang"
+    category: "official|win"
+    short_name: "clang"
+  }
+  builders {
+    name: "buildbucket/luci.chrome.official/win64-clang"
+    category: "official|win"
+    short_name: "clang (64)"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/mac10.11-updater-tester-rel"
     category: "release|mac"
     short_name: "10.11"
@@ -12041,6 +12066,9 @@
     name: "buildbucket/luci.chromium.try/linux-dcheck-off-rel"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/linux-example-builder"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/linux-gcc-rel"
   }
   builders {
@@ -12892,6 +12920,9 @@
     name: "buildbucket/luci.chromium.try/linux-dcheck-off-rel"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/linux-example-builder"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/linux-gcc-rel"
   }
   builders {
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star
index 3539a7a4..a607a0a 100644
--- a/infra/config/subprojects/chromium/ci.star
+++ b/infra/config/subprojects/chromium/ci.star
@@ -382,6 +382,20 @@
     ("win64-chrome", "win"),
 )]
 
+# The chromium.updater console includes some entries from official chrome builders.
+[branches.console_view_entry(
+    builder = "chrome:official/{}".format(name),
+    console_view = "chromium.updater",
+    category = category,
+    short_name = short_name,
+) for name, category, short_name in (
+    ("mac64", "official|mac", "64"),
+    ("mac-arm64", "official|mac", "arm64"),
+    ("win-asan", "official|win", "asan"),
+    ("win-clang", "official|win", "clang"),
+    ("win64-clang", "official|win", "clang (64)"),
+)]
+
 # Builders are sorted first lexicographically by the function used to define
 # them, then lexicographically by their name
 
diff --git a/infra/config/subprojects/chromium/try.star b/infra/config/subprojects/chromium/try.star
index 4c0bc53..db0df76d 100644
--- a/infra/config/subprojects/chromium/try.star
+++ b/infra/config/subprojects/chromium/try.star
@@ -964,6 +964,10 @@
 )
 
 try_.chromium_linux_builder(
+    name = "linux-example-builder",
+)
+
+try_.chromium_linux_builder(
     name = "linux-gcc-rel",
     goma_backend = None,
 )
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
index 77f863a..0b9a5cc8 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-324a16db812e7879d250a3514b1b4f744ff091a6
\ No newline at end of file
+e8cc68e7f0a9462e7fe5176f72c0472b0d43f798
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
index 656ea71..3a6af793 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-da316f13de971feba199e67c04ec286b5f540efd
\ No newline at end of file
+8b4ba9ac6d9db8818ca21e0da16edf6c9b7596b6
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
index 43269a1..ecc56cc 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-3fc65b170cd78ecb71476702ea616029ae29a579
\ No newline at end of file
+562263f237c7382847b69ea22c1b0dba5853073f
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
index c29c7bdd..0df4b4d 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-583af3b9184883631bc86b8a08f7d68dd593a496
\ No newline at end of file
+fe68565446e72a0a7cd4e2ffac6f5e86e01fc5c4
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
index 90cd644..3cad4a7 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-5bf91f7a6db7a5b3a621efaecaf32857a608e44d
\ No newline at end of file
+07706cc502d4e96f8cd467cc21928fac20f2ad5e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
index 51c52020..7e6a680 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-905e9bc24b4da815ea1a39784920c36e058cfd4a
\ No newline at end of file
+196af581649bc19a3ec986a79f3dea7785abbf3d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
index fada12c..521ef566 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-6f87cfac459edaadd4991cc00cf72696c38e6089
\ No newline at end of file
+2794e08bd996f366ef29661aec67b2ac55f1d36d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
index fe2d71e6..173fe76 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-36af3cc1f2655871d5f44a076ed41b72afbac9bd
\ No newline at end of file
+9f82383e0b823c90af30e49bee1b0f175d24f72d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
index 9a33718d..5b2b871 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-a37fc59391bc432a2d56c23484996cb1ac156eee
\ No newline at end of file
+5cc00d13e041eddf6ecb6d24097c1d3680c6fba1
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
index c12aaa1..b30de96a 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-5d3f0a379bf5c4c956e22131b8e16ffe54520e1f
\ No newline at end of file
+f2a5782397ad41a258e4d1a4fe6c5ac3449c9ed7
\ No newline at end of file
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
index c49ba54..4ed3df67 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
@@ -187,25 +187,20 @@
 
 void CameraHalDispatcherImpl::AddActiveClientObserver(
     CameraActiveClientObserver* observer) {
-  base::WaitableEvent observer_added_event;
-  proxy_thread_.task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          &CameraHalDispatcherImpl::AddActiveClientObserverOnProxyThread,
-          base::Unretained(this), std::move(observer), &observer_added_event));
-  observer_added_event.Wait();
+  base::AutoLock lock(opened_camera_id_map_lock_);
+  for (auto& opened_camera_id_pair : opened_camera_id_map_) {
+    const auto& camera_client_type = opened_camera_id_pair.first;
+    const auto& camera_id_set = opened_camera_id_pair.second;
+    if (!camera_id_set.empty()) {
+      observer->OnActiveClientChange(camera_client_type, /*is_active=*/true);
+    }
+  }
+  active_client_observers_->AddObserver(observer);
 }
 
 void CameraHalDispatcherImpl::RemoveActiveClientObserver(
     CameraActiveClientObserver* observer) {
-  base::WaitableEvent observer_removed_event;
-  proxy_thread_.task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          &CameraHalDispatcherImpl::RemoveActiveClientObserverOnProxyThread,
-          base::Unretained(this), std::move(observer),
-          &observer_removed_event));
-  observer_removed_event.Wait();
+  active_client_observers_->RemoveObserver(observer);
 }
 
 void CameraHalDispatcherImpl::RegisterPluginVmToken(
@@ -326,6 +321,7 @@
     cros::mojom::CameraClientType type) {
   VLOG(1) << type << (opened ? " opened " : " closed ") << "camera "
           << camera_id;
+  base::AutoLock lock(opened_camera_id_map_lock_);
   auto& camera_id_set = opened_camera_id_map_[type];
   if (opened) {
     auto result = camera_id_set.insert(camera_id);
@@ -336,9 +332,9 @@
     }
     if (camera_id_set.size() == 1) {
       VLOG(1) << type << " is active";
-      for (auto& observer : active_client_observers_) {
-        observer.OnActiveClientChange(type, /*is_active=*/true);
-      }
+      active_client_observers_->Notify(
+          FROM_HERE, &CameraActiveClientObserver::OnActiveClientChange, type,
+          /*is_active=*/true);
     }
   } else {
     auto it = camera_id_set.find(camera_id);
@@ -353,9 +349,9 @@
     camera_id_set.erase(it);
     if (camera_id_set.empty()) {
       VLOG(1) << type << " is inactive";
-      for (auto& observer : active_client_observers_) {
-        observer.OnActiveClientChange(type, /*is_active=*/false);
-      }
+      active_client_observers_->Notify(
+          FROM_HERE, &CameraActiveClientObserver::OnActiveClientChange, type,
+          /*is_active=*/false);
     }
   }
 }
@@ -532,29 +528,6 @@
   VLOG(1) << "Camera HAL client registered";
 }
 
-void CameraHalDispatcherImpl::AddActiveClientObserverOnProxyThread(
-    CameraActiveClientObserver* observer,
-    base::WaitableEvent* observer_added_event) {
-  DCHECK(proxy_task_runner_->BelongsToCurrentThread());
-  for (auto& opened_camera_id_pair : opened_camera_id_map_) {
-    const auto& camera_client_type = opened_camera_id_pair.first;
-    const auto& camera_id_set = opened_camera_id_pair.second;
-    if (!camera_id_set.empty()) {
-      observer->OnActiveClientChange(camera_client_type, /*is_active=*/true);
-    }
-  }
-  active_client_observers_.AddObserver(observer);
-  observer_added_event->Signal();
-}
-
-void CameraHalDispatcherImpl::RemoveActiveClientObserverOnProxyThread(
-    CameraActiveClientObserver* observer,
-    base::WaitableEvent* observer_removed_event) {
-  DCHECK(proxy_task_runner_->BelongsToCurrentThread());
-  active_client_observers_.RemoveObserver(observer);
-  observer_removed_event->Signal();
-}
-
 void CameraHalDispatcherImpl::EstablishMojoChannel(
     CameraClientObserver* client_observer) {
   DCHECK(proxy_task_runner_->BelongsToCurrentThread());
@@ -577,6 +550,7 @@
 
 void CameraHalDispatcherImpl::OnCameraHalServerConnectionError() {
   DCHECK(proxy_task_runner_->BelongsToCurrentThread());
+  base::AutoLock lock(opened_camera_id_map_lock_);
   VLOG(1) << "Camera HAL server connection lost";
   camera_hal_server_.reset();
   camera_hal_server_callbacks_.reset();
@@ -584,9 +558,9 @@
     auto camera_client_type = opened_camera_id_pair.first;
     const auto& camera_id_set = opened_camera_id_pair.second;
     if (!camera_id_set.empty()) {
-      for (auto& observer : active_client_observers_) {
-        observer.OnActiveClientChange(camera_client_type, /*is_active=*/false);
-      }
+      active_client_observers_->Notify(
+          FROM_HERE, &CameraActiveClientObserver::OnActiveClientChange,
+          camera_client_type, /*is_active=*/false);
     }
   }
   opened_camera_id_map_.clear();
@@ -595,18 +569,18 @@
 void CameraHalDispatcherImpl::OnCameraHalClientConnectionError(
     CameraClientObserver* client_observer) {
   DCHECK(proxy_task_runner_->BelongsToCurrentThread());
-  auto type = client_observer->GetType();
-  auto opened_it = opened_camera_id_map_.find(type);
+  base::AutoLock lock(opened_camera_id_map_lock_);
+  auto camera_client_type = client_observer->GetType();
+  auto opened_it = opened_camera_id_map_.find(camera_client_type);
   if (opened_it == opened_camera_id_map_.end()) {
     // This can happen if this camera client never opened a camera.
     return;
   }
   const auto& camera_id_set = opened_it->second;
   if (!camera_id_set.empty()) {
-    for (auto& observer : active_client_observers_) {
-      observer.OnActiveClientChange(type,
-                                    /*is_active=*/false);
-    }
+    active_client_observers_->Notify(
+        FROM_HERE, &CameraActiveClientObserver::OnActiveClientChange,
+        camera_client_type, /*is_active=*/false);
   }
   opened_camera_id_map_.erase(opened_it);
 
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.h b/media/capture/video/chromeos/camera_hal_dispatcher_impl.h
index 11b9cd88..d5c516e 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.h
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.h
@@ -12,10 +12,12 @@
 #include "base/containers/flat_set.h"
 #include "base/containers/unique_ptr_adapters.h"
 #include "base/files/scoped_file.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/memory/singleton.h"
-#include "base/observer_list.h"
+#include "base/observer_list_threadsafe.h"
 #include "base/observer_list_types.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/thread_annotations.h"
 #include "base/threading/thread.h"
 #include "base/unguessable_token.h"
 #include "components/chromeos_camera/common/jpeg_encode_accelerator.mojom.h"
@@ -190,14 +192,6 @@
       std::unique_ptr<CameraClientObserver> observer,
       base::OnceCallback<void(int32_t)> result_callback);
 
-  void AddActiveClientObserverOnProxyThread(
-      CameraActiveClientObserver* observer,
-      base::WaitableEvent* observer_added_event);
-
-  void RemoveActiveClientObserverOnProxyThread(
-      CameraActiveClientObserver* observer,
-      base::WaitableEvent* observer_removed_event);
-
   void EstablishMojoChannel(CameraClientObserver* client_observer);
 
   // Handler for incoming Mojo connection on the unix domain socket.
@@ -239,9 +233,12 @@
 
   TokenManager token_manager_;
 
+  base::Lock opened_camera_id_map_lock_;
   base::flat_map<cros::mojom::CameraClientType, base::flat_set<int32_t>>
-      opened_camera_id_map_;
-  base::ObserverList<CameraActiveClientObserver> active_client_observers_;
+      opened_camera_id_map_ GUARDED_BY(opened_camera_id_map_lock_);
+
+  scoped_refptr<base::ObserverListThreadSafe<CameraActiveClientObserver>>
+      active_client_observers_;
 
   DISALLOW_COPY_AND_ASSIGN(CameraHalDispatcherImpl);
 };
diff --git a/media/gpu/av1_decoder.cc b/media/gpu/av1_decoder.cc
index 74dbe99..85ad000607 100644
--- a/media/gpu/av1_decoder.cc
+++ b/media/gpu/av1_decoder.cc
@@ -56,7 +56,7 @@
 }
 
 bool IsYUV420Sequence(const libgav1::ColorConfig& color_config) {
-  return color_config.subsampling_x == 1 && color_config.subsampling_y == 1 &&
+  return color_config.subsampling_x == 1u && color_config.subsampling_y == 1u &&
          !color_config.is_monochrome;
 }
 
diff --git a/media/gpu/av1_decoder_unittest.cc b/media/gpu/av1_decoder_unittest.cc
index d9e8646a..e5e4a762 100644
--- a/media/gpu/av1_decoder_unittest.cc
+++ b/media/gpu/av1_decoder_unittest.cc
@@ -410,7 +410,17 @@
   EXPECT_EQ(Decode(buffers[1]), expected);
 }
 
-// TODO(hiroh): Add more tests, non-YUV420 stream, Reset() flow, mid-stream
-// configuration change, and reference frame tracking.
+TEST_F(AV1DecoderTest, DenyDecodeNonYUV420) {
+  const std::string kYUV444Stream("blackwhite_yuv444p-frame.av1.ivf");
+  std::vector<scoped_refptr<DecoderBuffer>> buffers = ReadIVF(kYUV444Stream);
+  ASSERT_EQ(buffers.size(), 1u);
+  std::vector<DecodeResult> expected = {DecodeResult::kDecodeError};
+  EXPECT_EQ(Decode(buffers[0]), expected);
+  // Once AV1Decoder gets into an error state, Decode() returns kDecodeError
+  // until Reset().
+  EXPECT_EQ(Decode(buffers[0]), expected);
+}
+// TODO(hiroh): Add more tests, Reset() flow, mid-stream configuration change,
+// and reference frame tracking.
 }  // namespace
 }  // namespace media
diff --git a/media/gpu/h264_decoder.cc b/media/gpu/h264_decoder.cc
index 527abe7..fbba8f22 100644
--- a/media/gpu/h264_decoder.cc
+++ b/media/gpu/h264_decoder.cc
@@ -18,6 +18,7 @@
 
 namespace media {
 namespace {
+
 bool ParseBitDepth(const H264SPS& sps, uint8_t& bit_depth) {
   // Spec 7.4.2.1.1
   if (sps.bit_depth_luma_minus8 != sps.bit_depth_chroma_minus8) {
@@ -77,6 +78,11 @@
       return false;
   }
 }
+
+bool IsYUV420Sequence(const H264SPS& sps) {
+  // Spec 6.2
+  return sps.chroma_format_idc == 1;
+}
 }  // namespace
 
 H264Decoder::H264Accelerator::H264Accelerator() = default;
@@ -1156,6 +1162,11 @@
     DVLOG(1) << "Invalid DPB size: " << max_dpb_size;
     return false;
   }
+  if (!IsYUV420Sequence(*sps)) {
+    DVLOG(1) << "Only YUV 4:2:0 is supported";
+    return false;
+  }
+
   VideoCodecProfile new_profile =
       H264Parser::ProfileIDCToVideoCodecProfile(sps->profile_idc);
   uint8_t new_bit_depth = 0;
diff --git a/media/gpu/h264_decoder_unittest.cc b/media/gpu/h264_decoder_unittest.cc
index 90864f7..b0d2044 100644
--- a/media/gpu/h264_decoder_unittest.cc
+++ b/media/gpu/h264_decoder_unittest.cc
@@ -46,6 +46,7 @@
 const std::string k10BitFrame1 = "bear-320x180-10bit-frame-1.h264";
 const std::string k10BitFrame2 = "bear-320x180-10bit-frame-2.h264";
 const std::string k10BitFrame3 = "bear-320x180-10bit-frame-3.h264";
+const std::string kYUV444Frame = "blackwhite_yuv444p-frame.h264";
 
 // Checks whether the decrypt config in the picture matches the decrypt config
 // passed to this matcher.
@@ -456,6 +457,12 @@
   ASSERT_TRUE(decoder_->Flush());
 }
 
+TEST_F(H264DecoderTest, DenyDecodeNonYUV420) {
+  // YUV444 frame causes kDecodeError.
+  SetInputFrameFiles({kYUV444Frame});
+  ASSERT_EQ(AcceleratedVideoDecoder::kDecodeError, Decode());
+}
+
 TEST_F(H264DecoderTest, SwitchBaselineToHigh) {
   SetInputFrameFiles({
       kBaselineFrame0, kHighFrame0, kHighFrame1, kHighFrame2, kHighFrame3,
@@ -555,6 +562,25 @@
   ASSERT_TRUE(decoder_->Flush());
 }
 
+TEST_F(H264DecoderTest, SwitchYUV420ToNonYUV420) {
+  SetInputFrameFiles({kBaselineFrame0, kYUV444Frame});
+  // The first frame, YUV420, is decoded with no error.
+  ASSERT_EQ(AcceleratedVideoDecoder::kConfigChange, Decode());
+  EXPECT_EQ(gfx::Size(320, 192), decoder_->GetPicSize());
+  EXPECT_EQ(H264PROFILE_BASELINE, decoder_->GetProfile());
+  EXPECT_LE(9u, decoder_->GetRequiredNumOfPictures());
+  {
+    InSequence sequence;
+    EXPECT_CALL(*accelerator_, CreateH264Picture());
+    EXPECT_CALL(*accelerator_, SubmitFrameMetadata(_, _, _, _, _, _, _));
+    EXPECT_CALL(*accelerator_, SubmitSlice(_, _, _, _, _, _, _, _));
+    EXPECT_CALL(*accelerator_, SubmitDecode(_));
+    EXPECT_CALL(*accelerator_, OutputPicture(WithPoc(0)));
+  }
+  // The second frame, YUV444, causes kDecodeError.
+  ASSERT_EQ(AcceleratedVideoDecoder::kDecodeError, Decode());
+}
+
 // Verify that the decryption config is passed to the accelerator.
 TEST_F(H264DecoderTest, SetEncryptedStream) {
   std::string bitstream;
diff --git a/media/gpu/h265_decoder.cc b/media/gpu/h265_decoder.cc
index 490ad80..64d5106 100644
--- a/media/gpu/h265_decoder.cc
+++ b/media/gpu/h265_decoder.cc
@@ -44,6 +44,11 @@
       return false;
   }
 }
+
+bool IsYUV420Sequence(const H265SPS& sps) {
+  // Spec 6.2
+  return sps.chroma_format_idc == 1;
+}
 }  // namespace
 
 H265Decoder::H265Accelerator::H265Accelerator() = default;
@@ -369,6 +374,10 @@
     DVLOG(2) << "New visible rect: " << new_visible_rect.ToString();
     visible_rect_ = new_visible_rect;
   }
+  if (!IsYUV420Sequence(*sps)) {
+    DVLOG(1) << "Only YUV 4:2:0 is supported";
+    return false;
+  }
 
   // Equation 7-8
   max_pic_order_cnt_lsb_ =
diff --git a/media/gpu/h265_decoder_unittest.cc b/media/gpu/h265_decoder_unittest.cc
index 4c96a988..ad34fc4 100644
--- a/media/gpu/h265_decoder_unittest.cc
+++ b/media/gpu/h265_decoder_unittest.cc
@@ -41,6 +41,7 @@
 constexpr char k10BitFrame1[] = "bear-320x180-10bit-frame-1.hevc";
 constexpr char k10BitFrame2[] = "bear-320x180-10bit-frame-2.hevc";
 constexpr char k10BitFrame3[] = "bear-320x180-10bit-frame-3.hevc";
+constexpr char kYUV444Frame[] = "blackwhite_yuv444p-frame.hevc";
 
 // Checks whether the decrypt config in the picture matches the decrypt config
 // passed to this matcher.
@@ -310,6 +311,12 @@
   EXPECT_TRUE(decoder_->Flush());
 }
 
+TEST_F(H265DecoderTest, DenyDecodeNonYUV420) {
+  // YUV444 frame causes kDecodeError.
+  SetInputFrameFiles({kYUV444Frame});
+  ASSERT_EQ(AcceleratedVideoDecoder::kDecodeError, Decode());
+}
+
 TEST_F(H265DecoderTest, OutputPictureFailureCausesDecodeToFail) {
   // Provide enough data that Decode() will try to output a frame.
   SetInputFrameFiles({kSpsPps, kFrame0, kFrame1, kFrame2, kFrame3});
diff --git a/media/gpu/test/video_encoder/bitstream_file_writer.cc b/media/gpu/test/video_encoder/bitstream_file_writer.cc
index 8917a6e..3d98b09 100644
--- a/media/gpu/test/video_encoder/bitstream_file_writer.cc
+++ b/media/gpu/test/video_encoder/bitstream_file_writer.cc
@@ -39,8 +39,10 @@
 };
 
 BitstreamFileWriter::BitstreamFileWriter(
-    std::unique_ptr<FrameFileWriter> frame_file_writer)
+    std::unique_ptr<FrameFileWriter> frame_file_writer,
+    base::Optional<size_t> num_vp9_temporal_layers_to_write)
     : frame_file_writer_(std::move(frame_file_writer)),
+      num_vp9_temporal_layers_to_write_(num_vp9_temporal_layers_to_write),
       num_buffers_writing_(0),
       num_errors_(0),
       writer_thread_("BitstreamFileWriterThread"),
@@ -59,7 +61,8 @@
     VideoCodec codec,
     const gfx::Size& resolution,
     uint32_t frame_rate,
-    uint32_t num_frames) {
+    uint32_t num_frames,
+    base::Optional<size_t> num_vp9_temporal_layers_to_write) {
   std::unique_ptr<FrameFileWriter> frame_file_writer;
   if (!base::DirectoryExists(output_filepath.DirName()))
     base::CreateDirectory(output_filepath.DirName());
@@ -82,8 +85,8 @@
         std::make_unique<FrameFileWriter>(std::move(ivf_writer));
   }
 
-  auto bitstream_file_writer =
-      base::WrapUnique(new BitstreamFileWriter(std::move(frame_file_writer)));
+  auto bitstream_file_writer = base::WrapUnique(new BitstreamFileWriter(
+      std::move(frame_file_writer), num_vp9_temporal_layers_to_write));
   if (!bitstream_file_writer->writer_thread_.Start()) {
     LOG(ERROR) << "Failed to start file writer thread";
     return nullptr;
@@ -95,6 +98,14 @@
 void BitstreamFileWriter::ProcessBitstream(
     scoped_refptr<BitstreamRef> bitstream,
     size_t frame_index) {
+  if (num_vp9_temporal_layers_to_write_ &&
+      bitstream->metadata.vp9->temporal_idx >=
+          *num_vp9_temporal_layers_to_write_) {
+    // Skip |bitstream| because it contains a frame in upper layers than layers
+    // to be saved.
+    return;
+  }
+
   base::AutoLock auto_lock(writer_lock_);
   num_buffers_writing_++;
   writer_thread_.task_runner()->PostTask(
diff --git a/media/gpu/test/video_encoder/bitstream_file_writer.h b/media/gpu/test/video_encoder/bitstream_file_writer.h
index d0c333f..da37184fe3 100644
--- a/media/gpu/test/video_encoder/bitstream_file_writer.h
+++ b/media/gpu/test/video_encoder/bitstream_file_writer.h
@@ -26,7 +26,8 @@
       VideoCodec codec,
       const gfx::Size& resolution,
       uint32_t frame_rate,
-      uint32_t num_frames);
+      uint32_t num_frames,
+      base::Optional<size_t> num_vp9_temporal_layers_to_write = base::nullopt);
   BitstreamFileWriter(const BitstreamFileWriter&) = delete;
   BitstreamFileWriter operator=(const BitstreamFileWriter&) = delete;
   ~BitstreamFileWriter() override;
@@ -37,11 +38,13 @@
 
  private:
   class FrameFileWriter;
-  BitstreamFileWriter(std::unique_ptr<FrameFileWriter> frame_file_writer);
+  BitstreamFileWriter(std::unique_ptr<FrameFileWriter> frame_file_writer,
+                      base::Optional<size_t> num_vp9_temporal_layers_to_write_);
   void WriteBitstreamTask(scoped_refptr<BitstreamRef> bitstream,
                           size_t frame_index);
 
   const std::unique_ptr<FrameFileWriter> frame_file_writer_;
+  const base::Optional<size_t> num_vp9_temporal_layers_to_write_;
 
   // The number of buffers currently queued for writing.
   size_t num_buffers_writing_ GUARDED_BY(writer_lock_);
diff --git a/media/gpu/test/video_encoder/bitstream_validator.cc b/media/gpu/test/video_encoder/bitstream_validator.cc
index 810c03b..ff5fc58 100644
--- a/media/gpu/test/video_encoder/bitstream_validator.cc
+++ b/media/gpu/test/video_encoder/bitstream_validator.cc
@@ -49,14 +49,16 @@
 std::unique_ptr<BitstreamValidator> BitstreamValidator::Create(
     const VideoDecoderConfig& decoder_config,
     size_t last_frame_index,
-    std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors) {
+    std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors,
+    base::Optional<size_t> num_vp9_temporal_layers_to_decode) {
   std::unique_ptr<VideoDecoder> decoder;
   decoder = CreateDecoder(decoder_config.codec());
   if (!decoder)
     return nullptr;
 
   auto validator = base::WrapUnique(new BitstreamValidator(
-      std::move(decoder), last_frame_index, std::move(video_frame_processors)));
+      std::move(decoder), last_frame_index, num_vp9_temporal_layers_to_decode,
+      std::move(video_frame_processors)));
   if (!validator->Initialize(decoder_config))
     return nullptr;
   return validator;
@@ -104,9 +106,11 @@
 BitstreamValidator::BitstreamValidator(
     std::unique_ptr<VideoDecoder> decoder,
     size_t last_frame_index,
+    base::Optional<size_t> num_vp9_temporal_layers_to_decode,
     std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors)
     : decoder_(std::move(decoder)),
       last_frame_index_(last_frame_index),
+      num_vp9_temporal_layers_to_decode_(num_vp9_temporal_layers_to_decode),
       video_frame_processors_(std::move(video_frame_processors)),
       validator_thread_("BitstreamValidatorThread"),
       validator_cv_(&validator_lock_),
@@ -133,16 +137,26 @@
     scoped_refptr<BitstreamRef> bitstream,
     size_t frame_index) {
   SEQUENCE_CHECKER(validator_thread_sequence_checker_);
-  scoped_refptr<DecoderBuffer> buffer = bitstream->buffer;
-  int64_t timestamp = buffer->timestamp().InMicroseconds();
-  decoding_buffers_.Put(timestamp,
-                        std::make_pair(frame_index, std::move(bitstream)));
-  // Validate the encoded bitstream buffer by decoding its contents using a
-  // software decoder.
-  decoder_->Decode(std::move(buffer),
-                   base::BindOnce(&BitstreamValidator::DecodeDone,
-                                  base::Unretained(this), timestamp));
-
+  const bool should_decode = !num_vp9_temporal_layers_to_decode_ ||
+                             (bitstream->metadata.vp9->temporal_idx <
+                              *num_vp9_temporal_layers_to_decode_);
+  if (should_decode) {
+    scoped_refptr<DecoderBuffer> buffer = bitstream->buffer;
+    int64_t timestamp = buffer->timestamp().InMicroseconds();
+    decoding_buffers_.Put(timestamp,
+                          std::make_pair(frame_index, std::move(bitstream)));
+    // Validate the encoded bitstream buffer by decoding its contents using a
+    // software decoder.
+    decoder_->Decode(std::move(buffer),
+                     base::BindOnce(&BitstreamValidator::DecodeDone,
+                                    base::Unretained(this), timestamp));
+  } else {
+    // Skip |bitstream| because it contains a frame in upper layers than layers
+    // to be validated.
+    base::AutoLock lock(validator_lock_);
+    num_buffers_validating_--;
+    validator_cv_.Signal();
+  }
   if (frame_index == last_frame_index_) {
     // Flush pending buffers.
     decoder_->Decode(DecoderBuffer::CreateEOSBuffer(),
diff --git a/media/gpu/test/video_encoder/bitstream_validator.h b/media/gpu/test/video_encoder/bitstream_validator.h
index 10b3d45..5996bd4 100644
--- a/media/gpu/test/video_encoder/bitstream_validator.h
+++ b/media/gpu/test/video_encoder/bitstream_validator.h
@@ -44,7 +44,9 @@
       const VideoDecoderConfig& decoder_config,
       size_t last_frame_index,
       std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors =
-          {});
+          {},
+      base::Optional<size_t> num_vp9_temporal_layers_to_decode = base::nullopt);
+
   ~BitstreamValidator() override;
 
   // BitstreamProcessor implementation.
@@ -56,6 +58,7 @@
   BitstreamValidator(
       std::unique_ptr<VideoDecoder> decoder,
       size_t last_frame_index,
+      base::Optional<size_t> num_vp9_temporal_layers_to_decode,
       std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors);
   BitstreamValidator(const BitstreamValidator&) = delete;
   BitstreamValidator& operator=(const BitstreamValidator&) = delete;
@@ -73,6 +76,7 @@
   // Validator components touched by validator_thread_ only.
   std::unique_ptr<VideoDecoder> decoder_;
   const size_t last_frame_index_;
+  const base::Optional<size_t> num_vp9_temporal_layers_to_decode_;
   const std::vector<std::unique_ptr<VideoFrameProcessor>>
       video_frame_processors_;
   // The key is timestamp, and the value is BitstreamRef that is being processed
diff --git a/media/gpu/test/video_frame_file_writer.cc b/media/gpu/test/video_frame_file_writer.cc
index 7cfeb50..193e8ab 100644
--- a/media/gpu/test/video_frame_file_writer.cc
+++ b/media/gpu/test/video_frame_file_writer.cc
@@ -24,12 +24,15 @@
 namespace media {
 namespace test {
 
-VideoFrameFileWriter::VideoFrameFileWriter(const base::FilePath& output_folder,
-                                           OutputFormat output_format,
-                                           size_t output_limit)
+VideoFrameFileWriter::VideoFrameFileWriter(
+    const base::FilePath& output_folder,
+    OutputFormat output_format,
+    size_t output_limit,
+    const base::FilePath::StringType& output_file_prefix)
     : output_folder_(output_folder),
       output_format_(output_format),
       output_limit_(output_limit),
+      output_file_prefix_(output_file_prefix),
       num_frames_writing_(0),
       frame_writer_thread_("FrameWriterThread"),
       frame_writer_cv_(&frame_writer_lock_) {
@@ -48,7 +51,8 @@
 std::unique_ptr<VideoFrameFileWriter> VideoFrameFileWriter::Create(
     const base::FilePath& output_folder,
     OutputFormat output_format,
-    size_t output_limit) {
+    size_t output_limit,
+    const base::FilePath::StringType& output_file_prefix) {
   // If the directory is not absolute, consider it relative to our working dir.
   base::FilePath resolved_output_folder(output_folder);
   if (!resolved_output_folder.IsAbsolute()) {
@@ -67,7 +71,7 @@
   }
 
   auto frame_file_writer = base::WrapUnique(new VideoFrameFileWriter(
-      resolved_output_folder, output_format, output_limit));
+      resolved_output_folder, output_format, output_limit, output_file_prefix));
   if (!frame_file_writer->Initialize()) {
     LOG(ERROR) << "Failed to initialize VideoFrameFileWriter";
     return nullptr;
@@ -129,6 +133,9 @@
   const gfx::Size& visible_size = video_frame->visible_rect().size();
   base::SStringPrintf(&filename, FILE_PATH_LITERAL("frame_%04zu_%dx%d"),
                       frame_index, visible_size.width(), visible_size.height());
+  if (!output_file_prefix_.empty())
+    filename = output_file_prefix_ + FILE_PATH_LITERAL("_") + filename;
+
   // Copies to |frame| in this function so that |video_frame| stays alive until
   // in the end of function.
   auto frame = video_frame;
diff --git a/media/gpu/test/video_frame_file_writer.h b/media/gpu/test/video_frame_file_writer.h
index b3149a2e..9161fb9 100644
--- a/media/gpu/test/video_frame_file_writer.h
+++ b/media/gpu/test/video_frame_file_writer.h
@@ -41,7 +41,9 @@
   static std::unique_ptr<VideoFrameFileWriter> Create(
       const base::FilePath& output_folder,
       OutputFormat output_format = OutputFormat::kPNG,
-      size_t output_limit = std::numeric_limits<size_t>::max());
+      size_t output_limit = std::numeric_limits<size_t>::max(),
+      const base::FilePath::StringType& output_file_prefix =
+          base::FilePath::StringType());
 
   // Interface VideoFrameProcessor
   void ProcessVideoFrame(scoped_refptr<const VideoFrame> video_frame,
@@ -52,7 +54,8 @@
  private:
   VideoFrameFileWriter(const base::FilePath& output_folder,
                        OutputFormat output_format,
-                       size_t output_limit);
+                       size_t output_limit,
+                       const base::FilePath::StringType& output_prefix);
 
   // Initialize the video frame file writer.
   bool Initialize();
@@ -74,6 +77,8 @@
   const OutputFormat output_format_;
   // The maximum number of frames that can be written.
   const size_t output_limit_;
+  // The prefix of the output file.
+  const base::FilePath::StringType output_file_prefix_;
 
   // The video frame mapper used to gain access to the raw video frame memory.
   std::unique_ptr<VideoFrameMapper> video_frame_mapper_;
diff --git a/media/gpu/video_encode_accelerator_tests.cc b/media/gpu/video_encode_accelerator_tests.cc
index edb94318..947ce29e 100644
--- a/media/gpu/video_encode_accelerator_tests.cc
+++ b/media/gpu/video_encode_accelerator_tests.cc
@@ -122,6 +122,40 @@
   }
 
  private:
+  std::unique_ptr<BitstreamProcessor> CreateBitstreamValidator(
+      const VideoDecoderConfig& decoder_config,
+      const size_t last_frame_index,
+      VideoFrameValidator::GetModelFrameCB get_model_frame_cb,
+      base::Optional<size_t> num_vp9_temporal_layers_to_decode) {
+    std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors;
+
+    // Attach a video frame writer to store individual frames to disk if
+    // requested.
+    std::unique_ptr<VideoFrameProcessor> image_writer;
+    auto frame_output_config = g_env->ImageOutputConfig();
+    base::FilePath output_folder = base::FilePath(g_env->OutputFolder())
+                                       .Append(g_env->GetTestOutputFilePath());
+    if (frame_output_config.output_mode != FrameOutputMode::kNone) {
+      image_writer = VideoFrameFileWriter::Create(
+          output_folder, frame_output_config.output_format,
+          frame_output_config.output_limit,
+          num_vp9_temporal_layers_to_decode
+              ? base::NumberToString(*num_vp9_temporal_layers_to_decode)
+              : "");
+      LOG_ASSERT(image_writer);
+      if (frame_output_config.output_mode == FrameOutputMode::kAll)
+        video_frame_processors.push_back(std::move(image_writer));
+    }
+    auto ssim_validator = SSIMVideoFrameValidator::Create(
+        get_model_frame_cb, std::move(image_writer),
+        VideoFrameValidator::ValidationMode::kAverage);
+    LOG_ASSERT(ssim_validator);
+    video_frame_processors.push_back(std::move(ssim_validator));
+    return BitstreamValidator::Create(decoder_config, last_frame_index,
+                                      std::move(video_frame_processors),
+                                      num_vp9_temporal_layers_to_decode);
+  }
+
   std::vector<std::unique_ptr<BitstreamProcessor>> CreateBitstreamProcessors(
       Video* video,
       const VideoEncoderClientConfig& config) {
@@ -137,11 +171,24 @@
           g_env->OutputFolder()
               .Append(g_env->GetTestOutputFilePath())
               .Append(video->FilePath().BaseName().ReplaceExtension(extension));
-      auto bitstream_writer = BitstreamFileWriter::Create(
-          output_bitstream_filepath, codec, visible_rect.size(),
-          config.framerate, config.num_frames_to_encode);
-      LOG_ASSERT(bitstream_writer);
-      bitstream_processors.emplace_back(std::move(bitstream_writer));
+      if (config.num_temporal_layers > 1) {
+        for (size_t num_vp9_temporal_layers_to_write = 1;
+             num_vp9_temporal_layers_to_write <= config.num_temporal_layers;
+             ++num_vp9_temporal_layers_to_write) {
+          bitstream_processors.emplace_back(BitstreamFileWriter::Create(
+              output_bitstream_filepath.InsertBeforeExtensionASCII(
+                  FILE_PATH_LITERAL(".TL") +
+                  base::NumberToString(num_vp9_temporal_layers_to_write)),
+              codec, visible_rect.size(), config.framerate,
+              config.num_frames_to_encode, num_vp9_temporal_layers_to_write));
+          LOG_ASSERT(bitstream_processors.back());
+        }
+      } else {
+        bitstream_processors.emplace_back(BitstreamFileWriter::Create(
+            output_bitstream_filepath, codec, visible_rect.size(),
+            config.framerate, config.num_frames_to_encode));
+        LOG_ASSERT(bitstream_processors.back());
+      }
     }
 
     if (!g_env->IsBitstreamValidatorEnabled()) {
@@ -174,7 +221,6 @@
         codec, config.output_profile, VideoDecoderConfig::AlphaMode::kIsOpaque,
         VideoColorSpace(), kNoTransformation, visible_rect.size(), visible_rect,
         visible_rect.size(), EmptyExtraData(), EncryptionScheme::kUnencrypted);
-    std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors;
     raw_data_helper_ = RawDataHelper::Create(video);
     if (!raw_data_helper_) {
       LOG(ERROR) << "Failed to create raw data helper";
@@ -184,31 +230,21 @@
     VideoFrameValidator::GetModelFrameCB get_model_frame_cb =
         base::BindRepeating(&VideoEncoderTest::GetModelFrame,
                             base::Unretained(this), visible_rect);
-
-    // Attach a video frame writer to store individual frames to disk if
-    // requested.
-    std::unique_ptr<VideoFrameProcessor> image_writer;
-    auto frame_output_config = g_env->ImageOutputConfig();
-    base::FilePath output_folder = base::FilePath(g_env->OutputFolder())
-                                       .Append(g_env->GetTestOutputFilePath());
-    if (frame_output_config.output_mode != FrameOutputMode::kNone) {
-      image_writer = VideoFrameFileWriter::Create(
-          output_folder, frame_output_config.output_format,
-          frame_output_config.output_limit);
-      LOG_ASSERT(image_writer);
-      if (frame_output_config.output_mode == FrameOutputMode::kAll)
-        video_frame_processors.push_back(std::move(image_writer));
+    if (config.num_temporal_layers > 1) {
+      for (size_t num_temporal_layers_to_decode = 1;
+           num_temporal_layers_to_decode <= config.num_temporal_layers;
+           ++num_temporal_layers_to_decode) {
+        bitstream_processors.emplace_back(CreateBitstreamValidator(
+            decoder_config, config.num_frames_to_encode - 1, get_model_frame_cb,
+            num_temporal_layers_to_decode));
+        LOG_ASSERT(bitstream_processors.back());
+      }
+    } else {
+      bitstream_processors.emplace_back(CreateBitstreamValidator(
+          decoder_config, config.num_frames_to_encode - 1, get_model_frame_cb,
+          base::nullopt));
+      LOG_ASSERT(bitstream_processors.back());
     }
-    auto ssim_validator = SSIMVideoFrameValidator::Create(
-        get_model_frame_cb, std::move(image_writer),
-        VideoFrameValidator::ValidationMode::kAverage);
-    LOG_ASSERT(ssim_validator);
-    video_frame_processors.push_back(std::move(ssim_validator));
-    auto bitstream_validator = BitstreamValidator::Create(
-        decoder_config, config.num_frames_to_encode - 1,
-        std::move(video_frame_processors));
-    LOG_ASSERT(bitstream_validator);
-    bitstream_processors.emplace_back(std::move(bitstream_validator));
     return bitstream_processors;
   }
 
diff --git a/media/gpu/vp9_decoder.cc b/media/gpu/vp9_decoder.cc
index bdaba57..fda81b91 100644
--- a/media/gpu/vp9_decoder.cc
+++ b/media/gpu/vp9_decoder.cc
@@ -70,6 +70,11 @@
       return false;
   }
 }
+
+bool IsYUV420Sequence(const Vp9FrameHeader& frame_header) {
+  // Spec 7.2.2
+  return frame_header.subsampling_x == 1u && frame_header.subsampling_y == 1u;
+}
 }  // namespace
 
 VP9Decoder::VP9Accelerator::VP9Accelerator() {}
@@ -237,6 +242,10 @@
                << ", profile=" << GetProfileName(new_profile);
       return kDecodeError;
     }
+    if (!IsYUV420Sequence(*curr_frame_hdr_)) {
+      DVLOG(1) << "Only YUV 4:2:0 is supported";
+      return kDecodeError;
+    }
 
     DCHECK(!new_pic_size.IsEmpty());
     if (new_pic_size != pic_size_ || new_profile != profile_ ||
diff --git a/media/renderers/paint_canvas_video_renderer.cc b/media/renderers/paint_canvas_video_renderer.cc
index ba266e6..0943bb8 100644
--- a/media/renderers/paint_canvas_video_renderer.cc
+++ b/media/renderers/paint_canvas_video_renderer.cc
@@ -1369,8 +1369,13 @@
 // TODO(crbug.com/1108154): Expand this uploading path to macOS, linux
 // chromeOS after collecting perf data and resolve failure cases.
 #if defined(OS_WIN)
-    // Try direct uploading path
-    if (premultiply_alpha && level == 0) {
+    // Since skia always produces premultiply alpha outputs,
+    // trying direct uploading path when video format is opaque or premultiply
+    // alpha been requested. And dst texture mipLevel must be 0.
+    // TODO(crbug.com/1155003): Figure out whether premultiply options here are
+    // accurate.
+    if ((media::IsOpaque(video_frame->format()) || premultiply_alpha) &&
+        level == 0) {
       if (UploadVideoFrameToGLTexture(raster_context_provider, destination_gl,
                                       video_frame, target, texture,
                                       internal_format, format, type, flip_y)) {
@@ -1483,7 +1488,7 @@
   destination_gl->GenUnverifiedSyncTokenCHROMIUM(
       mailbox_holder.sync_token.GetData());
 
-  if (!VideoFrameYUVConverter::ConvertYUVVideoFrameWithSkSurfaceNoCaching(
+  if (!VideoFrameYUVConverter::ConvertYUVVideoFrameToDstTextureNoCaching(
           video_frame.get(), raster_context_provider, mailbox_holder,
           internal_format, type, flip_y, true /* use visible_rect */)) {
     return false;
diff --git a/media/renderers/video_frame_yuv_converter.cc b/media/renderers/video_frame_yuv_converter.cc
index 64775dbe..c553a1dc 100644
--- a/media/renderers/video_frame_yuv_converter.cc
+++ b/media/renderers/video_frame_yuv_converter.cc
@@ -8,7 +8,6 @@
 
 #include "components/viz/common/gpu/raster_context_provider.h"
 #include "components/viz/common/resources/resource_format_utils.h"
-#include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/raster_interface.h"
 #include "gpu/command_buffer/client/shared_image_interface.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
@@ -29,8 +28,7 @@
 
 SkYUVColorSpace ColorSpaceToSkYUVColorSpace(
     const gfx::ColorSpace& color_space) {
-  // TODO(hubbe): This should really default to rec709.
-  // https://crbug.com/828599
+  // TODO(crbug.com/828599): This should really default to rec709.
   SkYUVColorSpace sk_color_space = kRec601_SkYUVColorSpace;
   color_space.ToSkYUVColorSpace(&sk_color_space);
   return sk_color_space;
@@ -141,20 +139,6 @@
   return true;
 }
 
-void FinishRasterTextureAccess(
-    const gpu::MailboxHolder& dest_mailbox_holder,
-    viz::RasterContextProvider* raster_context_provider,
-    GLuint tex_id) {
-  DCHECK(raster_context_provider);
-
-  auto* ri = raster_context_provider->RasterInterface();
-  DCHECK(ri);
-
-  if (dest_mailbox_holder.mailbox.IsSharedImage())
-    ri->EndSharedImageAccessDirectCHROMIUM(tex_id);
-  ri->DeleteGpuRasterTexture(tex_id);
-}
-
 }  // namespace
 
 class VideoFrameYUVConverter::VideoFrameYUVMailboxesHolder {
@@ -398,19 +382,23 @@
          SkYUVAInfo::PlaneConfig::kUnknown;
 }
 
-void VideoFrameYUVConverter::ConvertYUVVideoFrameNoCaching(
+bool VideoFrameYUVConverter::ConvertYUVVideoFrameNoCaching(
     const VideoFrame* video_frame,
     viz::RasterContextProvider* raster_context_provider,
     const gpu::MailboxHolder& dest_mailbox_holder) {
   VideoFrameYUVConverter converter;
-  converter.ConvertYUVVideoFrame(video_frame, raster_context_provider,
-                                 dest_mailbox_holder);
+  return converter.ConvertYUVVideoFrame(video_frame, raster_context_provider,
+                                        dest_mailbox_holder);
 }
 
-void VideoFrameYUVConverter::ConvertYUVVideoFrame(
+bool VideoFrameYUVConverter::ConvertYUVVideoFrame(
     const VideoFrame* video_frame,
     viz::RasterContextProvider* raster_context_provider,
-    const gpu::MailboxHolder& dest_mailbox_holder) {
+    const gpu::MailboxHolder& dest_mailbox_holder,
+    unsigned int internal_format,
+    unsigned int type,
+    bool flip_y,
+    bool use_visible_rect) {
   DCHECK(video_frame);
   DCHECK(IsVideoFrameFormatSupported(*video_frame))
       << "VideoFrame has an unsupported YUV format " << video_frame->format();
@@ -422,9 +410,9 @@
     holder_ = std::make_unique<VideoFrameYUVMailboxesHolder>();
 
   if (raster_context_provider->GrContext()) {
-    ConvertFromVideoFrameYUVWithGrContext(video_frame, raster_context_provider,
-                                          dest_mailbox_holder);
-    return;
+    return ConvertFromVideoFrameYUVWithGrContext(
+        video_frame, raster_context_provider, dest_mailbox_holder,
+        internal_format, type, flip_y, use_visible_rect);
   }
 
   auto* ri = raster_context_provider->RasterInterface();
@@ -439,9 +427,10 @@
   ri->ConvertYUVAMailboxesToRGB(dest_mailbox_holder.mailbox, color_space,
                                 holder_->plane_config(), holder_->subsampling(),
                                 mailboxes);
+  return true;
 }
 
-bool VideoFrameYUVConverter::ConvertYUVVideoFrameWithSkSurface(
+bool VideoFrameYUVConverter::ConvertYUVVideoFrameToDstTextureNoCaching(
     const VideoFrame* video_frame,
     viz::RasterContextProvider* raster_context_provider,
     const gpu::MailboxHolder& dest_mailbox_holder,
@@ -449,40 +438,68 @@
     unsigned int type,
     bool flip_y,
     bool use_visible_rect) {
-  DCHECK(video_frame);
-  DCHECK(IsVideoFrameFormatSupported(*video_frame))
-      << "VideoFrame has an unsupported YUV format " << video_frame->format();
-  DCHECK(!video_frame->coded_size().IsEmpty())
-      << "|video_frame| must have an area > 0";
-  DCHECK(raster_context_provider);
-  DCHECK(raster_context_provider->GrContext());
+  VideoFrameYUVConverter converter;
+  return converter.ConvertYUVVideoFrame(video_frame, raster_context_provider,
+                                        dest_mailbox_holder, internal_format,
+                                        type, flip_y, use_visible_rect);
+}
 
-  if (!holder_)
-    holder_ = std::make_unique<VideoFrameYUVMailboxesHolder>();
+void VideoFrameYUVConverter::ReleaseCachedData() {
+  holder_.reset();
+}
 
+bool VideoFrameYUVConverter::ConvertFromVideoFrameYUVWithGrContext(
+    const VideoFrame* video_frame,
+    viz::RasterContextProvider* raster_context_provider,
+    const gpu::MailboxHolder& dest_mailbox_holder,
+    unsigned int internal_format,
+    unsigned int type,
+    bool flip_y,
+    bool use_visible_rect) {
   gpu::raster::RasterInterface* ri = raster_context_provider->RasterInterface();
   DCHECK(ri);
   ri->WaitSyncTokenCHROMIUM(dest_mailbox_holder.sync_token.GetConstData());
-
-  // Consume mailbox to get dst texture.
   GLuint dest_tex_id =
       ri->CreateAndConsumeForGpuRaster(dest_mailbox_holder.mailbox);
-
   if (dest_mailbox_holder.mailbox.IsSharedImage()) {
     ri->BeginSharedImageAccessDirectCHROMIUM(
         dest_tex_id, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
   }
 
+  bool result = ConvertFromVideoFrameYUVSkia(
+      video_frame, raster_context_provider, dest_mailbox_holder.texture_target,
+      dest_tex_id, internal_format, type, flip_y, use_visible_rect);
+
+  if (dest_mailbox_holder.mailbox.IsSharedImage())
+    ri->EndSharedImageAccessDirectCHROMIUM(dest_tex_id);
+  ri->DeleteGpuRasterTexture(dest_tex_id);
+
+  return result;
+}
+
+bool VideoFrameYUVConverter::ConvertFromVideoFrameYUVSkia(
+    const VideoFrame* video_frame,
+    viz::RasterContextProvider* raster_context_provider,
+    unsigned int texture_target,
+    unsigned int texture_id,
+    unsigned int internal_format,
+    unsigned int type,
+    bool flip_y,
+    bool use_visible_rect) {
   // Rendering YUV textures to SkSurface by dst texture
   GrDirectContext* gr_context = raster_context_provider->GrContext();
+  DCHECK(gr_context);
+  // TODO(crbug.com/674185): We should compare the DCHECK vs when
+  // UpdateLastImage calls this function.
+  DCHECK(IsVideoFrameFormatSupported(*video_frame));
 
   GrYUVABackendTextures yuva_backend_textures =
       holder_->VideoFrameToSkiaTextures(video_frame, raster_context_provider);
   DCHECK(yuva_backend_textures.isValid());
 
   GrGLTextureInfo result_gl_texture_info{};
-  result_gl_texture_info.fID = dest_tex_id;
-  result_gl_texture_info.fTarget = dest_mailbox_holder.texture_target;
+  result_gl_texture_info.fID = texture_id;
+  result_gl_texture_info.fTarget = texture_target;
   result_gl_texture_info.fFormat = GetSurfaceColorFormat(internal_format, type);
 
   int result_width = use_visible_rect ? video_frame->visible_rect().width()
@@ -502,8 +519,6 @@
 
   // Terminate if surface cannot be created.
   if (!surface) {
-    FinishRasterTextureAccess(dest_mailbox_holder, raster_context_provider,
-                              dest_tex_id);
     return false;
   }
 
@@ -511,87 +526,11 @@
                                                 yuva_backend_textures, surface,
                                                 use_visible_rect);
 
-  // Finish access of dest_tex_id
-  FinishRasterTextureAccess(dest_mailbox_holder, raster_context_provider,
-                            dest_tex_id);
-
-  return result;
-}
-
-bool VideoFrameYUVConverter::ConvertYUVVideoFrameWithSkSurfaceNoCaching(
-    const VideoFrame* video_frame,
-    viz::RasterContextProvider* raster_context_provider,
-    const gpu::MailboxHolder& dest_mailbox_holder,
-    unsigned int internal_format,
-    unsigned int type,
-    bool flip_y,
-    bool use_visible_rect) {
-  VideoFrameYUVConverter converter;
-  return converter.ConvertYUVVideoFrameWithSkSurface(
-      video_frame, raster_context_provider, dest_mailbox_holder,
-      internal_format, type, flip_y, use_visible_rect);
-}
-
-void VideoFrameYUVConverter::ReleaseCachedData() {
-  holder_.reset();
-}
-
-void VideoFrameYUVConverter::ConvertFromVideoFrameYUVWithGrContext(
-    const VideoFrame* video_frame,
-    viz::RasterContextProvider* raster_context_provider,
-    const gpu::MailboxHolder& dest_mailbox_holder) {
-  gpu::raster::RasterInterface* ri = raster_context_provider->RasterInterface();
-  DCHECK(ri);
-  ri->WaitSyncTokenCHROMIUM(dest_mailbox_holder.sync_token.GetConstData());
-  GLuint dest_tex_id =
-      ri->CreateAndConsumeForGpuRaster(dest_mailbox_holder.mailbox);
-  if (dest_mailbox_holder.mailbox.IsSharedImage()) {
-    ri->BeginSharedImageAccessDirectCHROMIUM(
-        dest_tex_id, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
-  }
-
-  ConvertFromVideoFrameYUVSkia(video_frame, raster_context_provider,
-                               dest_mailbox_holder.texture_target, dest_tex_id);
-
-  if (dest_mailbox_holder.mailbox.IsSharedImage())
-    ri->EndSharedImageAccessDirectCHROMIUM(dest_tex_id);
-  ri->DeleteGpuRasterTexture(dest_tex_id);
-}
-
-void VideoFrameYUVConverter::ConvertFromVideoFrameYUVSkia(
-    const VideoFrame* video_frame,
-    viz::RasterContextProvider* raster_context_provider,
-    unsigned int texture_target,
-    unsigned int texture_id) {
-  GrDirectContext* gr_context = raster_context_provider->GrContext();
-  DCHECK(gr_context);
-  // TODO: We should compare the DCHECK vs when UpdateLastImage calls this
-  // function. (https://crbug.com/674185)
-  DCHECK(IsVideoFrameFormatSupported(*video_frame));
-
-  GrYUVABackendTextures yuva_backend_textures =
-      holder_->VideoFrameToSkiaTextures(video_frame, raster_context_provider);
-  DCHECK(yuva_backend_textures.isValid());
-
-  GrGLTextureInfo result_gl_texture_info{};
-  result_gl_texture_info.fID = texture_id;
-  result_gl_texture_info.fTarget = texture_target;
-  result_gl_texture_info.fFormat = GL_RGBA8;
-  GrBackendTexture result_texture(video_frame->coded_size().width(),
-                                  video_frame->coded_size().height(),
-                                  GrMipMapped::kNo, result_gl_texture_info);
-
-  // Creating the SkImage triggers conversion into the dest texture. We ignore
-  // the returned image and track the result using |dest_mailbox_holder|
-  SkImage::MakeFromYUVATexturesCopyToExternal(gr_context, yuva_backend_textures,
-                                              result_texture,
-                                              kRGBA_8888_SkColorType);
-
-  gr_context->flushAndSubmit();
-
   // Release textures to guarantee |holder_| doesn't hold read access on
   // textures it doesn't own.
   holder_->ReleaseTextures();
+
+  return result;
 }
 
 }  // namespace media
diff --git a/media/renderers/video_frame_yuv_converter.h b/media/renderers/video_frame_yuv_converter.h
index e454ddb..1256667 100644
--- a/media/renderers/video_frame_yuv_converter.h
+++ b/media/renderers/video_frame_yuv_converter.h
@@ -7,6 +7,7 @@
 
 #include <array>
 
+#include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/common/mailbox_holder.h"
 #include "media/base/media_export.h"
 #include "ui/gfx/color_space.h"
@@ -34,7 +35,7 @@
  public:
   static bool IsVideoFrameFormatSupported(const VideoFrame& video_frame);
 
-  static void ConvertYUVVideoFrameNoCaching(
+  static bool ConvertYUVVideoFrameNoCaching(
       const VideoFrame* video_frame,
       viz::RasterContextProvider* raster_context_provider,
       const gpu::MailboxHolder& dest_mailbox_holder);
@@ -42,7 +43,7 @@
   // TODO(crbug.com/1108154): Will merge this uploading path
   // with ConvertYUVVideoFrameYUVWithGrContext after solving
   // issue 1120911, 1120912
-  static bool ConvertYUVVideoFrameWithSkSurfaceNoCaching(
+  static bool ConvertYUVVideoFrameToDstTextureNoCaching(
       const VideoFrame* video_frame,
       viz::RasterContextProvider* raster_context_provider,
       const gpu::MailboxHolder& dest_mailbox_holder,
@@ -54,22 +55,17 @@
   VideoFrameYUVConverter();
   ~VideoFrameYUVConverter();
 
-  void ConvertYUVVideoFrame(const VideoFrame* video_frame,
+  bool ConvertYUVVideoFrame(const VideoFrame* video_frame,
                             viz::RasterContextProvider* raster_context_provider,
-                            const gpu::MailboxHolder& dest_mailbox_holder);
+                            const gpu::MailboxHolder& dest_mailbox_holder,
+                            unsigned int internal_format = GL_RGBA,
+                            unsigned int type = GL_UNSIGNED_BYTE,
+                            bool flip_y = false,
+                            bool use_visible_rect = false);
   void ReleaseCachedData();
 
  private:
-  void ConvertFromVideoFrameYUVWithGrContext(
-      const VideoFrame* video_frame,
-      viz::RasterContextProvider* raster_context_provider,
-      const gpu::MailboxHolder& dest_mailbox_holder);
-  void ConvertFromVideoFrameYUVSkia(
-      const VideoFrame* video_frame,
-      viz::RasterContextProvider* raster_context_provider,
-      unsigned int texture_target,
-      unsigned int texture_id);
-  bool ConvertYUVVideoFrameWithSkSurface(
+  bool ConvertFromVideoFrameYUVWithGrContext(
       const VideoFrame* video_frame,
       viz::RasterContextProvider* raster_context_provider,
       const gpu::MailboxHolder& dest_mailbox_holder,
@@ -77,6 +73,15 @@
       unsigned int type,
       bool flip_y,
       bool use_visible_rect);
+  bool ConvertFromVideoFrameYUVSkia(
+      const VideoFrame* video_frame,
+      viz::RasterContextProvider* raster_context_provider,
+      unsigned int texture_target,
+      unsigned int texture_id,
+      unsigned int internal_format,
+      unsigned int type,
+      bool flip_y,
+      bool use_visible_rect);
 
   class VideoFrameYUVMailboxesHolder;
   std::unique_ptr<VideoFrameYUVMailboxesHolder> holder_;
diff --git a/media/test/data/README.md b/media/test/data/README.md
index 2ba9f00e..45f5639 100644
--- a/media/test/data/README.md
+++ b/media/test/data/README.md
@@ -186,6 +186,9 @@
 This is the same as 00000592.ivf in
 https://people.xiph.org/~tterribe/av1/samples-all/
 
+#### blackwhite\_yuv444p-frame.av1.ivf
+The first frame of blackwhite\_yuv444p.mp4 coded in AV1 by the following command.
+`ffmpeg -i blackwhite_yuv444p.mp4 -strict -2 -vcodec av1 -vframes 1 blackwhite_yuv444p-frame.av1.ivf`
 
 ### Alpha Channel
 
@@ -898,6 +901,13 @@
 Manually dumped from libvpx with bear-vp9.ivf and test-25fps.vp9. See
 vp9_parser_unittest.cc for description of their format.
 
+
+### H264 decoder test files:
+
+#### blackwhite\_yuv444p-frame.h264
+The first frame of blackwhite_yuv444p.mp4 by the following command.
+`ffmpeg -i blackwhite_yuv444p.mp4 -vcodec copy -vframes 1 blackwhite_yuv444p-frame.h264`
+
 ### HEVC parser/decoder test files:
 
 #### bear.hevc
@@ -925,6 +935,10 @@
 bear-320x180-10bit-frame-2.hevc: B
 bear-320x180-10bit-frame-3.hevc: P
 
+#### blackwhite\_yuv444p-frame.hevc
+The first frame of blackwhite_yuv444p.mp4 coded in HEVC by the following command.
+`ffmpeg -i blackwhite_yuv444p.mp4 -vcodec hevc -vframes 1 blackwhite_yuv444p-frame.hevc`
+
 ###  WebM files for testing multiple tracks.
 
 #### green-a300hz.webm
diff --git a/media/test/data/blackwhite_yuv444p-frame.av1.ivf b/media/test/data/blackwhite_yuv444p-frame.av1.ivf
new file mode 100644
index 0000000..b363bfb
--- /dev/null
+++ b/media/test/data/blackwhite_yuv444p-frame.av1.ivf
Binary files differ
diff --git a/media/test/data/blackwhite_yuv444p-frame.h264 b/media/test/data/blackwhite_yuv444p-frame.h264
new file mode 100644
index 0000000..3e14c098
--- /dev/null
+++ b/media/test/data/blackwhite_yuv444p-frame.h264
Binary files differ
diff --git a/media/test/data/blackwhite_yuv444p-frame.hevc b/media/test/data/blackwhite_yuv444p-frame.hevc
new file mode 100644
index 0000000..d08f3f9d
--- /dev/null
+++ b/media/test/data/blackwhite_yuv444p-frame.hevc
Binary files differ
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 6563da5..af1020cc 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -1038,6 +1038,7 @@
   send_start_time_ = base::TimeTicks::Now();
   next_state_ = STATE_SEND_REQUEST_COMPLETE;
 
+  stream_->SetRequestIdempotency(request_->idempotency);
   return stream_->SendRequest(request_headers_, &response_, io_callback_);
 }
 
diff --git a/net/http/http_stream.h b/net/http/http_stream.h
index 96937af..8310330e 100644
--- a/net/http/http_stream.h
+++ b/net/http/http_stream.h
@@ -18,6 +18,7 @@
 
 #include "base/macros.h"
 #include "net/base/completion_once_callback.h"
+#include "net/base/idempotency.h"
 #include "net/base/net_error_details.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_export.h"
@@ -187,6 +188,9 @@
 
   virtual void SetRequestHeadersCallback(RequestHeadersCallback callback) = 0;
 
+  // Set the idempotency of the request. No-op by default.
+  virtual void SetRequestIdempotency(Idempotency idempotency) {}
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HttpStream);
 };
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc
index c440ae8..297aeb0 100644
--- a/net/quic/quic_chromium_client_session.cc
+++ b/net/quic/quic_chromium_client_session.cc
@@ -2180,6 +2180,8 @@
                       quic::ConnectionCloseBehavior::SILENT_CLOSE);
 }
 
+// TODO(renjietang): Deprecate this method once IETF QUIC supports connection
+// migration.
 void QuicChromiumClientSession::OnProbeSucceeded(
     NetworkChangeNotifier::NetworkHandle network,
     const quic::QuicSocketAddress& peer_address,
@@ -2187,6 +2189,25 @@
     std::unique_ptr<DatagramClientSocket> socket,
     std::unique_ptr<QuicChromiumPacketWriter> writer,
     std::unique_ptr<QuicChromiumPacketReader> reader) {
+  if (current_migration_cause_ == CHANGE_PORT_ON_PATH_DEGRADING) {
+    DCHECK(allow_port_migration_);
+    OnPortMigrationProbeSucceeded(network, peer_address, self_address,
+                                  std::move(socket), std::move(writer),
+                                  std::move(reader));
+    return;
+  }
+  OnConnectionMigrationProbeSucceeded(network, peer_address, self_address,
+                                      std::move(socket), std::move(writer),
+                                      std::move(reader));
+}
+
+void QuicChromiumClientSession::OnPortMigrationProbeSucceeded(
+    NetworkChangeNotifier::NetworkHandle network,
+    const quic::QuicSocketAddress& peer_address,
+    const quic::QuicSocketAddress& self_address,
+    std::unique_ptr<DatagramClientSocket> socket,
+    std::unique_ptr<QuicChromiumPacketWriter> writer,
+    std::unique_ptr<QuicChromiumPacketReader> reader) {
   DCHECK(socket);
   DCHECK(writer);
   DCHECK(reader);
@@ -2196,11 +2217,7 @@
                       return NetLogProbingResultParams(network, &peer_address,
                                                        /*is_success=*/true);
                     });
-
-  if (!allow_port_migration_ &&
-      network == NetworkChangeNotifier::kInvalidNetworkHandle)
-    return;
-
+  // TODO(crbug.com/1151419): Use the name Port migration in histogram.
   LogProbeResultToHistogram(current_migration_cause_, true);
 
   // Remove |this| as the old packet writer's delegate. Write error on old
@@ -2212,10 +2229,6 @@
   writer->set_delegate(this);
   connection()->SetSelfAddress(self_address);
 
-  // Close streams that are not migratable to the probed |network|.
-  if (!allow_port_migration_)
-    ResetNonMigratableStreams();
-
   if (!migrate_idle_session_ && !HasActiveRequestStreams()) {
     // If idle sessions won't be migrated, close the connection.
     CloseSessionOnErrorLater(
@@ -2241,8 +2254,70 @@
   LogMigrateToSocketStatus(true);
 
   // Notify the connection that migration succeeds after probing.
-  if (connection()->IsPathDegrading())
-    connection()->OnSuccessfulMigration();
+  connection()->OnSuccessfulMigration();
+  num_migrations_++;
+  HistogramAndLogMigrationSuccess(connection_id());
+}
+
+void QuicChromiumClientSession::OnConnectionMigrationProbeSucceeded(
+    NetworkChangeNotifier::NetworkHandle network,
+    const quic::QuicSocketAddress& peer_address,
+    const quic::QuicSocketAddress& self_address,
+    std::unique_ptr<DatagramClientSocket> socket,
+    std::unique_ptr<QuicChromiumPacketWriter> writer,
+    std::unique_ptr<QuicChromiumPacketReader> reader) {
+  DCHECK(socket);
+  DCHECK(writer);
+  DCHECK(reader);
+
+  net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CONNECTIVITY_PROBING_FINISHED,
+                    [&] {
+                      return NetLogProbingResultParams(network, &peer_address,
+                                                       /*is_success=*/true);
+                    });
+  if (network == NetworkChangeNotifier::kInvalidNetworkHandle)
+    return;
+
+  LogProbeResultToHistogram(current_migration_cause_, true);
+
+  // Remove |this| as the old packet writer's delegate. Write error on old
+  // writers will be ignored.
+  // Set |this| to listen on socket write events on the packet writer
+  // that was used for probing.
+  static_cast<QuicChromiumPacketWriter*>(connection()->writer())
+      ->set_delegate(nullptr);
+  writer->set_delegate(this);
+  connection()->SetSelfAddress(self_address);
+
+  // Close streams that are not migratable to the probed |network|.
+  ResetNonMigratableStreams();
+
+  if (!migrate_idle_session_ && !HasActiveRequestStreams()) {
+    // If idle sessions won't be migrated, close the connection.
+    CloseSessionOnErrorLater(
+        ERR_NETWORK_CHANGED,
+        quic::QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS,
+        quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+    return;
+  }
+
+  if (migrate_idle_session_ && CheckIdleTimeExceedsIdleMigrationPeriod())
+    return;
+
+  // Migrate to the probed socket immediately: socket, writer and reader will
+  // be acquired by connection and used as default on success.
+  if (!MigrateToSocket(std::move(socket), std::move(reader),
+                       std::move(writer))) {
+    LogMigrateToSocketStatus(false);
+    net_log_.AddEvent(
+        NetLogEventType::QUIC_CONNECTION_MIGRATION_FAILURE_AFTER_PROBING);
+    return;
+  }
+
+  LogMigrateToSocketStatus(true);
+
+  // Notify the connection that migration succeeds after probing.
+  connection()->OnSuccessfulMigration();
 
   net_log_.AddEventWithInt64Params(
       NetLogEventType::QUIC_CONNECTION_MIGRATION_SUCCESS_AFTER_PROBING,
diff --git a/net/quic/quic_chromium_client_session.h b/net/quic/quic_chromium_client_session.h
index cd053d9..7fb3ac8 100644
--- a/net/quic/quic_chromium_client_session.h
+++ b/net/quic/quic_chromium_client_session.h
@@ -508,6 +508,22 @@
       std::unique_ptr<QuicChromiumPacketWriter> writer,
       std::unique_ptr<QuicChromiumPacketReader> reader) override;
 
+  void OnConnectionMigrationProbeSucceeded(
+      NetworkChangeNotifier::NetworkHandle network,
+      const quic::QuicSocketAddress& peer_address,
+      const quic::QuicSocketAddress& self_address,
+      std::unique_ptr<DatagramClientSocket> socket,
+      std::unique_ptr<QuicChromiumPacketWriter> writer,
+      std::unique_ptr<QuicChromiumPacketReader> reader);
+
+  void OnPortMigrationProbeSucceeded(
+      NetworkChangeNotifier::NetworkHandle network,
+      const quic::QuicSocketAddress& peer_address,
+      const quic::QuicSocketAddress& self_address,
+      std::unique_ptr<DatagramClientSocket> socket,
+      std::unique_ptr<QuicChromiumPacketWriter> writer,
+      std::unique_ptr<QuicChromiumPacketReader> reader);
+
   void OnProbeFailed(NetworkChangeNotifier::NetworkHandle network,
                      const quic::QuicSocketAddress& peer_address) override;
 
diff --git a/net/quic/quic_chromium_client_stream.cc b/net/quic/quic_chromium_client_stream.cc
index e999602..13ea707b 100644
--- a/net/quic/quic_chromium_client_stream.cc
+++ b/net/quic/quic_chromium_client_stream.cc
@@ -399,6 +399,15 @@
   return net_error_;
 }
 
+void QuicChromiumClientStream::Handle::SetRequestIdempotency(
+    Idempotency idempotency) {
+  idempotency_ = idempotency;
+}
+
+Idempotency QuicChromiumClientStream::Handle::GetRequestIdempotency() const {
+  return idempotency_;
+}
+
 QuicChromiumClientStream::QuicChromiumClientStream(
     quic::QuicStreamId id,
     quic::QuicSpdyClientSessionBase* session,
@@ -541,7 +550,9 @@
   if (!session()->OneRttKeysAvailable()) {
     auto entry = header_block.find(":method");
     DCHECK(entry != header_block.end());
-    DCHECK_NE("POST", entry->second);
+    DCHECK(
+        entry->second != "POST" ||
+        (handle_ != nullptr && handle_->GetRequestIdempotency() == IDEMPOTENT));
   }
   net_log_.AddEvent(
       NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
diff --git a/net/quic/quic_chromium_client_stream.h b/net/quic/quic_chromium_client_stream.h
index 74f129c..ee70dc3 100644
--- a/net/quic/quic_chromium_client_stream.h
+++ b/net/quic/quic_chromium_client_stream.h
@@ -15,6 +15,7 @@
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "net/base/completion_once_callback.h"
+#include "net/base/idempotency.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_export.h"
 #include "net/base/upload_data_stream.h"
@@ -134,6 +135,11 @@
 
     const NetLogWithSource& net_log() const;
 
+    // Sets the idempotency of the request.
+    void SetRequestIdempotency(Idempotency idempotency);
+    // Returns the idempotency of the request.
+    Idempotency GetRequestIdempotency() const;
+
    private:
     friend class QuicChromiumClientStream;
 
@@ -188,6 +194,7 @@
     bool is_done_reading_;
     bool is_first_stream_;
     size_t num_bytes_consumed_;
+    Idempotency idempotency_ = DEFAULT_IDEMPOTENCY;
 
     int net_error_;
 
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc
index 5b6498d3..15dc1629 100644
--- a/net/quic/quic_http_stream.cc
+++ b/net/quic/quic_http_stream.cc
@@ -791,4 +791,11 @@
   return ERR_QUIC_PROTOCOL_ERROR;
 }
 
+void QuicHttpStream::SetRequestIdempotency(Idempotency idempotency) {
+  if (stream_ == nullptr) {
+    return;
+  }
+  stream_->SetRequestIdempotency(idempotency);
+}
+
 }  // namespace net
diff --git a/net/quic/quic_http_stream.h b/net/quic/quic_http_stream.h
index aa2bd7be..d5b45617 100644
--- a/net/quic/quic_http_stream.h
+++ b/net/quic/quic_http_stream.h
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "net/base/completion_once_callback.h"
+#include "net/base/idempotency.h"
 #include "net/base/io_buffer.h"
 #include "net/base/load_timing_info.h"
 #include "net/base/net_export.h"
@@ -66,6 +67,7 @@
       AlternativeService* alternative_service) const override;
   void PopulateNetErrorDetails(NetErrorDetails* details) override;
   void SetPriority(RequestPriority priority) override;
+  void SetRequestIdempotency(Idempotency idempotency) override;
 
   static HttpResponseInfo::ConnectionInfo ConnectionInfoFromQuicVersion(
       quic::ParsedQuicVersion quic_version);
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 6364d72..552d8440 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -3369,160 +3369,6 @@
           "--test-runner-outdir",
           ".",
           "--client-outdir",
-          "../../weblayer_instrumentation_test_M85/out/Release",
-          "--implementation-outdir",
-          ".",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--client-version=85",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android29.textpb"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "weblayer_instrumentation_test_versions_apk_M85_Client_Library_Tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "weblayer_instrumentation_test_versions_apk_M85_Client_Library_Tests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/weblayer-x86",
-              "location": "weblayer_instrumentation_test_M85",
-              "revision": "version:85.0.4183.140"
-            },
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "avd_generic_android29",
-              "path": ".android"
-            },
-            {
-              "name": "system_images_android_29_google_apis_x86",
-              "path": ".emulator_sdk"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_instrumentation_test_versions_apk",
-        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_versions_apk/"
-      },
-      {
-        "args": [
-          "--test-runner-outdir",
-          ".",
-          "--client-outdir",
-          ".",
-          "--implementation-outdir",
-          "../../weblayer_instrumentation_test_M85/out/Release",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--impl-version=85",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android29.textpb"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "weblayer_instrumentation_test_versions_apk_M85_Implementation_Library_Tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "weblayer_instrumentation_test_versions_apk_M85_Implementation_Library_Tests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/weblayer-x86",
-              "location": "weblayer_instrumentation_test_M85",
-              "revision": "version:85.0.4183.140"
-            },
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "avd_generic_android29",
-              "path": ".android"
-            },
-            {
-              "name": "system_images_android_29_google_apis_x86",
-              "path": ".emulator_sdk"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_instrumentation_test_versions_apk",
-        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_versions_apk/"
-      },
-      {
-        "args": [
-          "--test-runner-outdir",
-          ".",
-          "--client-outdir",
           "../../weblayer_instrumentation_test_M86/out/Release",
           "--implementation-outdir",
           ".",
@@ -3979,6 +3825,160 @@
         },
         "test": "weblayer_instrumentation_test_versions_apk",
         "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_versions_apk/"
+      },
+      {
+        "args": [
+          "--test-runner-outdir",
+          ".",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M88/out/Release",
+          "--implementation-outdir",
+          ".",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--client-version=88",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android29.textpb"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "weblayer_instrumentation_test_versions_apk_M88_Client_Library_Tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "weblayer_instrumentation_test_versions_apk_M88_Client_Library_Tests",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "chromium/testing/weblayer-x86",
+              "location": "weblayer_instrumentation_test_M88",
+              "revision": "version:88.0.4324.29"
+            },
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4",
+              "os": "Ubuntu-16.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "avd_generic_android29",
+              "path": ".android"
+            },
+            {
+              "name": "system_images_android_29_google_apis_x86",
+              "path": ".emulator_sdk"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "weblayer_instrumentation_test_versions_apk",
+        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_versions_apk/"
+      },
+      {
+        "args": [
+          "--test-runner-outdir",
+          ".",
+          "--client-outdir",
+          ".",
+          "--implementation-outdir",
+          "../../weblayer_instrumentation_test_M88/out/Release",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--impl-version=88",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android29.textpb"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "weblayer_instrumentation_test_versions_apk_M88_Implementation_Library_Tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "weblayer_instrumentation_test_versions_apk_M88_Implementation_Library_Tests",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "chromium/testing/weblayer-x86",
+              "location": "weblayer_instrumentation_test_M88",
+              "revision": "version:88.0.4324.29"
+            },
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4",
+              "os": "Ubuntu-16.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "avd_generic_android29",
+              "path": ".android"
+            },
+            {
+              "name": "system_images_android_29_google_apis_x86",
+              "path": ".emulator_sdk"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "weblayer_instrumentation_test_versions_apk",
+        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_versions_apk/"
       }
     ]
   },
@@ -4052,160 +4052,6 @@
           "--test-runner-outdir",
           ".",
           "--client-outdir",
-          "../../weblayer_instrumentation_test_M85/out/Release",
-          "--implementation-outdir",
-          ".",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--client-version=85",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android23.textpb"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "weblayer_instrumentation_test_versions_apk_M85_Client_Library_Tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "weblayer_instrumentation_test_versions_apk_M85_Client_Library_Tests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/weblayer-x86",
-              "location": "weblayer_instrumentation_test_M85",
-              "revision": "version:85.0.4183.140"
-            },
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "avd_generic_android23",
-              "path": ".android"
-            },
-            {
-              "name": "system_images_android_23_google_apis_x86",
-              "path": ".emulator_sdk"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_instrumentation_test_versions_apk",
-        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_versions_apk/"
-      },
-      {
-        "args": [
-          "--test-runner-outdir",
-          ".",
-          "--client-outdir",
-          ".",
-          "--implementation-outdir",
-          "../../weblayer_instrumentation_test_M85/out/Release",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--impl-version=85",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android23.textpb"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "weblayer_instrumentation_test_versions_apk_M85_Implementation_Library_Tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "weblayer_instrumentation_test_versions_apk_M85_Implementation_Library_Tests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/weblayer-x86",
-              "location": "weblayer_instrumentation_test_M85",
-              "revision": "version:85.0.4183.140"
-            },
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "avd_generic_android23",
-              "path": ".android"
-            },
-            {
-              "name": "system_images_android_23_google_apis_x86",
-              "path": ".emulator_sdk"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_instrumentation_test_versions_apk",
-        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_versions_apk/"
-      },
-      {
-        "args": [
-          "--test-runner-outdir",
-          ".",
-          "--client-outdir",
           "../../weblayer_instrumentation_test_M86/out/Release",
           "--implementation-outdir",
           ".",
@@ -4662,6 +4508,160 @@
         },
         "test": "weblayer_instrumentation_test_versions_apk",
         "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_versions_apk/"
+      },
+      {
+        "args": [
+          "--test-runner-outdir",
+          ".",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M88/out/Release",
+          "--implementation-outdir",
+          ".",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--client-version=88",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android23.textpb"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "weblayer_instrumentation_test_versions_apk_M88_Client_Library_Tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "weblayer_instrumentation_test_versions_apk_M88_Client_Library_Tests",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "chromium/testing/weblayer-x86",
+              "location": "weblayer_instrumentation_test_M88",
+              "revision": "version:88.0.4324.29"
+            },
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4",
+              "os": "Ubuntu-16.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "avd_generic_android23",
+              "path": ".android"
+            },
+            {
+              "name": "system_images_android_23_google_apis_x86",
+              "path": ".emulator_sdk"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "weblayer_instrumentation_test_versions_apk",
+        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_versions_apk/"
+      },
+      {
+        "args": [
+          "--test-runner-outdir",
+          ".",
+          "--client-outdir",
+          ".",
+          "--implementation-outdir",
+          "../../weblayer_instrumentation_test_M88/out/Release",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--impl-version=88",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android23.textpb"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "weblayer_instrumentation_test_versions_apk_M88_Implementation_Library_Tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "weblayer_instrumentation_test_versions_apk_M88_Implementation_Library_Tests",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "chromium/testing/weblayer-x86",
+              "location": "weblayer_instrumentation_test_M88",
+              "revision": "version:88.0.4324.29"
+            },
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4",
+              "os": "Ubuntu-16.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "avd_generic_android23",
+              "path": ".android"
+            },
+            {
+              "name": "system_images_android_23_google_apis_x86",
+              "path": ".emulator_sdk"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "weblayer_instrumentation_test_versions_apk",
+        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_versions_apk/"
       }
     ]
   },
@@ -4735,160 +4735,6 @@
           "--test-runner-outdir",
           ".",
           "--client-outdir",
-          "../../weblayer_instrumentation_test_M85/out/Release",
-          "--implementation-outdir",
-          ".",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--client-version=85",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "weblayer_instrumentation_test_versions_apk_M85_Client_Library_Tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "weblayer_instrumentation_test_versions_apk_M85_Client_Library_Tests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/weblayer-x86",
-              "location": "weblayer_instrumentation_test_M85",
-              "revision": "version:85.0.4183.140"
-            },
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "avd_generic_android28",
-              "path": ".android"
-            },
-            {
-              "name": "system_images_android_28_google_apis_x86",
-              "path": ".emulator_sdk"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_instrumentation_test_versions_apk",
-        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_versions_apk/"
-      },
-      {
-        "args": [
-          "--test-runner-outdir",
-          ".",
-          "--client-outdir",
-          ".",
-          "--implementation-outdir",
-          "../../weblayer_instrumentation_test_M85/out/Release",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--impl-version=85",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "weblayer_instrumentation_test_versions_apk_M85_Implementation_Library_Tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "weblayer_instrumentation_test_versions_apk_M85_Implementation_Library_Tests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/testing/weblayer-x86",
-              "location": "weblayer_instrumentation_test_M85",
-              "revision": "version:85.0.4183.140"
-            },
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "avd_generic_android28",
-              "path": ".android"
-            },
-            {
-              "name": "system_images_android_28_google_apis_x86",
-              "path": ".emulator_sdk"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_instrumentation_test_versions_apk",
-        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_versions_apk/"
-      },
-      {
-        "args": [
-          "--test-runner-outdir",
-          ".",
-          "--client-outdir",
           "../../weblayer_instrumentation_test_M86/out/Release",
           "--implementation-outdir",
           ".",
@@ -5345,6 +5191,160 @@
         },
         "test": "weblayer_instrumentation_test_versions_apk",
         "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_versions_apk/"
+      },
+      {
+        "args": [
+          "--test-runner-outdir",
+          ".",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M88/out/Release",
+          "--implementation-outdir",
+          ".",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--client-version=88",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "weblayer_instrumentation_test_versions_apk_M88_Client_Library_Tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "weblayer_instrumentation_test_versions_apk_M88_Client_Library_Tests",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "chromium/testing/weblayer-x86",
+              "location": "weblayer_instrumentation_test_M88",
+              "revision": "version:88.0.4324.29"
+            },
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4",
+              "os": "Ubuntu-16.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "avd_generic_android28",
+              "path": ".android"
+            },
+            {
+              "name": "system_images_android_28_google_apis_x86",
+              "path": ".emulator_sdk"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "weblayer_instrumentation_test_versions_apk",
+        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_versions_apk/"
+      },
+      {
+        "args": [
+          "--test-runner-outdir",
+          ".",
+          "--client-outdir",
+          ".",
+          "--implementation-outdir",
+          "../../weblayer_instrumentation_test_M88/out/Release",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--impl-version=88",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "weblayer_instrumentation_test_versions_apk_M88_Implementation_Library_Tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "weblayer_instrumentation_test_versions_apk_M88_Implementation_Library_Tests",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "chromium/testing/weblayer-x86",
+              "location": "weblayer_instrumentation_test_M88",
+              "revision": "version:88.0.4324.29"
+            },
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4",
+              "os": "Ubuntu-16.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "avd_generic_android28",
+              "path": ".android"
+            },
+            {
+              "name": "system_images_android_28_google_apis_x86",
+              "path": ".emulator_sdk"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "weblayer_instrumentation_test_versions_apk",
+        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_versions_apk/"
       }
     ]
   }
diff --git a/testing/buildbot/filters/chromeos.unit_tests.filter b/testing/buildbot/filters/chromeos.unit_tests.filter
index 251853b..fec4cb0 100644
--- a/testing/buildbot/filters/chromeos.unit_tests.filter
+++ b/testing/buildbot/filters/chromeos.unit_tests.filter
@@ -1,6 +1,4 @@
 # TODO(crbug.com/970790): Enable this.
 -InputMethodManagerImplTest.SetLoginDefaultWithAllowedKeyboardLayouts
--InputMethodManagerImplTest.TestEnableLayoutsNonUsHardwareKeyboard
--InputMethodManagerImplTest.TestEnableMultipleHardwareKeyboardLayout
 # TODO(crbug.com/970806): Enable this.
 -KeyboardShortcutViewerMetadataTest.ModifyAcceleratorShouldUpdateMetadata
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 442ed96..70acc57 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -337,6 +337,29 @@
       '--client-outdir',
       '.',
       '--implementation-outdir',
+      '../../weblayer_instrumentation_test_M88/out/Release',
+      '--test-expectations',
+      '../../weblayer/browser/android/javatests/skew/expectations.txt',
+      '--impl-version=88',
+    ],
+    'identifier': 'M88_Implementation_Library_Tests',
+    'swarming': {
+      'cipd_packages': [
+        {
+          'cipd_package': 'chromium/testing/weblayer-x86',
+          'location': 'weblayer_instrumentation_test_M88',
+          'revision': 'version:88.0.4324.29',
+        }
+      ],
+    },
+  },
+  'WEBLAYER_IMPL_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
+    'args': [
+      '--test-runner-outdir',
+      '.',
+      '--client-outdir',
+      '.',
+      '--implementation-outdir',
       '../../weblayer_instrumentation_test_M87/out/Release',
       '--test-expectations',
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
@@ -353,7 +376,7 @@
       ],
     },
   },
-  'WEBLAYER_IMPL_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
+  'WEBLAYER_IMPL_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': {
     'args': [
       '--test-runner-outdir',
       '.',
@@ -376,29 +399,6 @@
       ],
     },
   },
-  'WEBLAYER_IMPL_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': {
-    'args': [
-      '--test-runner-outdir',
-      '.',
-      '--client-outdir',
-      '.',
-      '--implementation-outdir',
-      '../../weblayer_instrumentation_test_M85/out/Release',
-      '--test-expectations',
-      '../../weblayer/browser/android/javatests/skew/expectations.txt',
-      '--impl-version=85',
-    ],
-    'identifier': 'M85_Implementation_Library_Tests',
-    'swarming': {
-      'cipd_packages': [
-        {
-          'cipd_package': 'chromium/testing/weblayer-x86',
-          'location': 'weblayer_instrumentation_test_M85',
-          'revision': 'version:85.0.4183.140',
-        }
-      ],
-    },
-  },
   'WEBLAYER_M88_CLIENT_NIGHTLY_SKEW_TESTS': {
     'args': [
       '--test-runner-outdir',
@@ -427,6 +427,29 @@
       '--test-runner-outdir',
       '.',
       '--client-outdir',
+      '../../weblayer_instrumentation_test_M88/out/Release',
+      '--implementation-outdir',
+      '.',
+      '--test-expectations',
+      '../../weblayer/browser/android/javatests/skew/expectations.txt',
+      '--client-version=88',
+    ],
+    'identifier': 'M88_Client_Library_Tests',
+    'swarming': {
+      'cipd_packages': [
+        {
+          'cipd_package': 'chromium/testing/weblayer-x86',
+          'location': 'weblayer_instrumentation_test_M88',
+          'revision': 'version:88.0.4324.29',
+        }
+      ],
+    },
+  },
+  'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
+    'args': [
+      '--test-runner-outdir',
+      '.',
+      '--client-outdir',
       '../../weblayer_instrumentation_test_M87/out/Release',
       '--implementation-outdir',
       '.',
@@ -445,7 +468,7 @@
       ],
     },
   },
-  'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
+  'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': {
     'args': [
       '--test-runner-outdir',
       '.',
@@ -468,27 +491,4 @@
       ],
     },
   },
-  'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': {
-    'args': [
-      '--test-runner-outdir',
-      '.',
-      '--client-outdir',
-      '../../weblayer_instrumentation_test_M85/out/Release',
-      '--implementation-outdir',
-      '.',
-      '--test-expectations',
-      '../../weblayer/browser/android/javatests/skew/expectations.txt',
-      '--client-version=85',
-    ],
-    'identifier': 'M85_Client_Library_Tests',
-    'swarming': {
-      'cipd_packages': [
-        {
-          'cipd_package': 'chromium/testing/weblayer-x86',
-          'location': 'weblayer_instrumentation_test_M85',
-          'revision': 'version:85.0.4183.140',
-        }
-      ],
-    },
-  },
 }
\ No newline at end of file
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 3b4e2a3..407c1f3d 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2285,6 +2285,25 @@
             ]
         }
     ],
+    "DesktopNtpShoppingTasksModule": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "NtpModules",
+                        "NtpShoppingTasksModule"
+                    ]
+                }
+            ]
+        }
+    ],
     "DesktopTabGroupsCollapse": [
         {
             "platforms": [
@@ -4613,6 +4632,30 @@
             ]
         }
     ],
+    "NtpRepeatableQueriesDesktop": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "params": {
+                        "NtpRepeatableQueriesAgeThresholdDays": "180",
+                        "NtpRepeatableQueriesFrequencyExponent": "2",
+                        "NtpRepeatableQueriesInsertPosition": "start",
+                        "NtpRepeatableQueriesRecencyHalfLifeSeconds": "604800"
+                    },
+                    "enable_features": [
+                        "NtpRepeatableQueries"
+                    ]
+                }
+            ]
+        }
+    ],
     "NtpWebUIDesktop": [
         {
             "platforms": [
diff --git a/third_party/blink/common/input/web_input_event.cc b/third_party/blink/common/input/web_input_event.cc
index af7a5cc..d94f718 100644
--- a/third_party/blink/common/input/web_input_event.cc
+++ b/third_party/blink/common/input/web_input_event.cc
@@ -5,6 +5,12 @@
 #include "third_party/blink/public/common/input/web_input_event.h"
 
 namespace blink {
+namespace {
+constexpr int kButtonModifiers =
+    WebInputEvent::kLeftButtonDown | WebInputEvent::kMiddleButtonDown |
+    WebInputEvent::kRightButtonDown | WebInputEvent::kBackButtonDown |
+    WebInputEvent::kForwardButtonDown;
+}
 
 base::Optional<ui::ScrollInputType> WebInputEvent::GetScrollInputType() const {
   return base::nullopt;
@@ -31,7 +37,8 @@
     case WebInputEvent::Type::kMouseUp:
       return ui::EventType::ET_MOUSE_RELEASED;
     case WebInputEvent::Type::kMouseMove:
-      return ui::EventType::ET_MOUSE_MOVED;
+      return modifiers_ & kButtonModifiers ? ui::EventType::ET_MOUSE_DRAGGED
+                                           : ui::EventType::ET_MOUSE_MOVED;
     case WebInputEvent::Type::kMouseEnter:
       return ui::EventType::ET_MOUSE_ENTERED;
     case WebInputEvent::Type::kMouseLeave:
diff --git a/third_party/blink/public/mojom/prerender/prerender.mojom b/third_party/blink/public/mojom/prerender/prerender.mojom
index 8928ce3..704d5eff 100644
--- a/third_party/blink/public/mojom/prerender/prerender.mojom
+++ b/third_party/blink/public/mojom/prerender/prerender.mojom
@@ -8,24 +8,6 @@
 import "ui/gfx/geometry/mojom/geometry.mojom";
 import "url/mojom/url.mojom";
 
-// This interface is used to notify of events about prerendering from the
-// browser process to a renderer process that requested prerendering. This is
-// created per prerender request, for example, when a new <link rel=prerender>
-// element is added, when the element's href is changed, etc.
-interface PrerenderProcessorClient {
-  // Notifies that a prerender started.
-  OnPrerenderStart();
-
-  // Notifies that a prerender has stopped loading.
-  OnPrerenderStopLoading();
-
-  // Notifies that a prerender has had it's 'domcontentloaded' event.
-  OnPrerenderDomContentLoaded();
-
-  // Notifies that a prerender is no longer running.
-  OnPrerenderStop();
-};
-
 enum PrerenderRelType {
   // https://html.spec.whatwg.org/C/#link-type-prerender
   kPrerender,
@@ -47,15 +29,12 @@
 // changed, etc.
 interface PrerenderProcessor {
   // Requests the browesr process to start prerendering with
-  // |prerender_attribute|. |prerender_processor_client| will be notified as the
-  // prerendering makes progress. This must be called only one time before any
-  // other functions.
-  Start(PrerenderAttributes prerender_attribute,
-        pending_remote<PrerenderProcessorClient> prerender_processor_client);
+  // |prerender_attribute|. This must be called only one time before any other
+  // functions.
+  Start(PrerenderAttributes prerender_attribute);
 
   // Cancels the ongoing prerendering. This is supposed to be called when the
   // <link rel=prerender> element is removed, the element's href is changed,
-  // etc. This must be called after Start(). This does not trigger
-  // OnPrerenderStop() on PrerenderProcessorClient.
+  // etc. This must be called after Start().
   Cancel();
 };
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index f20a8e5..c86612d 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2798,10 +2798,6 @@
   // The above items are available in M86 branch.
 
   kWebTransport = 3472,
-  kWebkitPrerenderStartEventFired = 3473,
-  kWebkitPrerenderStopEventFired = 3474,
-  kWebkitPrerenderLoadEventFired = 3475,
-  kWebkitPrerenderDOMContentLoadedEventFired = 3476,
   kIdleDetectionPermissionRequested = 3477,
   kIdentifiabilityStudyReserved3478 = 3478,
   kSpeechSynthesis_GetVoices_Method = 3479,
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index 1fb8b21..6e5e6f2 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -2422,7 +2422,8 @@
       default_value: "ListStyleTypeData::CreateCounterStyle(\"disc\", nullptr)",
       type_name: "ListStyleTypeData",
       keywords: [
-        "disc", "circle", "square", "decimal", "decimal-leading-zero",
+        "disc", "circle", "square", "disclosure-open", "disclosure-closed",
+        "decimal", "decimal-leading-zero",
         "arabic-indic", "bengali", "cambodian", "khmer", "devanagari",
         "gujarati", "gurmukhi", "kannada", "lao", "malayalam", "mongolian",
         "myanmar", "oriya", "persian", "urdu", "telugu", "tibetan", "thai",
diff --git a/third_party/blink/renderer/core/css/css_value_id_mappings.h b/third_party/blink/renderer/core/css/css_value_id_mappings.h
index be6818e..7af488e7 100644
--- a/third_party/blink/renderer/core/css/css_value_id_mappings.h
+++ b/third_party/blink/renderer/core/css/css_value_id_mappings.h
@@ -185,6 +185,10 @@
       return EListStyleType::kCircle;
     case CSSValueID::kSquare:
       return EListStyleType::kSquare;
+    case CSSValueID::kDisclosureOpen:
+      return EListStyleType::kDisclosureOpen;
+    case CSSValueID::kDisclosureClosed:
+      return EListStyleType::kDisclosureClosed;
     case CSSValueID::kDecimal:
       return EListStyleType::kDecimal;
     case CSSValueID::kDecimalLeadingZero:
@@ -369,6 +373,10 @@
       return CSSValueID::kCircle;
     case EListStyleType::kSquare:
       return CSSValueID::kSquare;
+    case EListStyleType::kDisclosureOpen:
+      return CSSValueID::kDisclosureOpen;
+    case EListStyleType::kDisclosureClosed:
+      return CSSValueID::kDisclosureClosed;
     case EListStyleType::kDecimal:
       return CSSValueID::kDecimal;
     case EListStyleType::kDecimalLeadingZero:
diff --git a/third_party/blink/renderer/core/css/css_value_keywords.json5 b/third_party/blink/renderer/core/css/css_value_keywords.json5
index afe28fcc..550e8d2 100644
--- a/third_party/blink/renderer/core/css/css_value_keywords.json5
+++ b/third_party/blink/renderer/core/css/css_value_keywords.json5
@@ -435,6 +435,8 @@
     "disc",
     "circle",
     "square",
+    "disclosure-open",
+    "disclosure-closed",
     "decimal",
     "decimal-leading-zero",
     "arabic-indic",
@@ -1435,6 +1437,14 @@
     "single-fold-vertical",
     "single-fold-horizontal",
 
+    // (screen-fold-posture) media feature
+    "no-fold",
+    "laptop",
+    // flat,
+    "tent",
+    "tablet",
+    "book",
+
     // scrollbar-gutter
     // auto
     "stable",
diff --git a/third_party/blink/renderer/core/css/media_feature_names.json5 b/third_party/blink/renderer/core/css/media_feature_names.json5
index 464d2a23..babc3d59 100644
--- a/third_party/blink/renderer/core/css/media_feature_names.json5
+++ b/third_party/blink/renderer/core/css/media_feature_names.json5
@@ -59,6 +59,7 @@
     "resolution",
     "-webkit-transform-3d",
     "scan",
+    "screen-fold-posture",
     "screen-spanning",
   ],
 }
diff --git a/third_party/blink/renderer/core/css/media_query_evaluator.cc b/third_party/blink/renderer/core/css/media_query_evaluator.cc
index d67e83e9..697684dc 100644
--- a/third_party/blink/renderer/core/css/media_query_evaluator.cc
+++ b/third_party/blink/renderer/core/css/media_query_evaluator.cc
@@ -987,6 +987,37 @@
           value.id == CSSValueID::kSingleFoldHorizontal);
 }
 
+static bool ScreenFoldPostureMediaFeatureEval(const MediaQueryExpValue& value,
+                                              MediaFeaturePrefix,
+                                              const MediaValues& media_values) {
+  // isValid() is false if there is no parameter. Without parameter we should
+  // return true to indicate that screenFoldPosture is enabled in the
+  // browser.
+  if (!value.IsValid())
+    return true;
+
+  DCHECK(value.is_id);
+
+  ScreenFoldPosture screen_fold_posture = media_values.GetScreenFoldPosture();
+  switch (value.id) {
+    case CSSValueID::kNoFold:
+      return screen_fold_posture == ScreenFoldPosture::kNoFold;
+    case CSSValueID::kLaptop:
+      return screen_fold_posture == ScreenFoldPosture::kLaptop;
+    case CSSValueID::kFlat:
+      return screen_fold_posture == ScreenFoldPosture::kFlat;
+    case CSSValueID::kTent:
+      return screen_fold_posture == ScreenFoldPosture::kTent;
+    case CSSValueID::kTablet:
+      return screen_fold_posture == ScreenFoldPosture::kTablet;
+    case CSSValueID::kBook:
+      return screen_fold_posture == ScreenFoldPosture::kBook;
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
 void MediaQueryEvaluator::Init() {
   // Create the table.
   g_function_map = new FunctionMap;
diff --git a/third_party/blink/renderer/core/css/media_query_evaluator_test.cc b/third_party/blink/renderer/core/css/media_query_evaluator_test.cc
index 3f0434b..d473d62 100644
--- a/third_party/blink/renderer/core/css/media_query_evaluator_test.cc
+++ b/third_party/blink/renderer/core/css/media_query_evaluator_test.cc
@@ -279,6 +279,75 @@
     {nullptr, 0}  // Do not remove the terminator line.
 };
 
+MediaQueryEvaluatorTestCase g_screen_fold_posture_none_cases[] = {
+    {"(screen-fold-posture)", 1},
+    {"(screen-fold-posture: laptop)", 0},
+    {"(screen-fold-posture: flat)", 0},
+    {"(screen-fold-posture: tent)", 0},
+    {"(screen-fold-posture: tablet)", 0},
+    {"(screen-fold-posture: book)", 0},
+    {"(screen-fold-posture: no-fold)", 1},
+    {"(screen-fold-posture: 15)", 0},
+    {"(screen-fold-posture: 2px)", 0},
+    {"(screen-fold-posture: 16/9)", 0},
+    {nullptr, 0}  // Do not remove the terminator line.
+};
+
+MediaQueryEvaluatorTestCase g_screen_fold_posture_laptop_cases[] = {
+    {"(screen-fold-posture)", 1},
+    {"(screen-fold-posture: laptop)", 1},
+    {"(screen-fold-posture: flat)", 0},
+    {"(screen-fold-posture: tent)", 0},
+    {"(screen-fold-posture: tablet)", 0},
+    {"(screen-fold-posture: book)", 0},
+    {"(screen-fold-posture: no-fold)", 0},
+    {nullptr, 0}  // Do not remove the terminator line.
+};
+
+MediaQueryEvaluatorTestCase g_screen_fold_posture_flat_cases[] = {
+    {"(screen-fold-posture)", 1},
+    {"(screen-fold-posture: laptop)", 0},
+    {"(screen-fold-posture: flat)", 1},
+    {"(screen-fold-posture: tent)", 0},
+    {"(screen-fold-posture: tablet)", 0},
+    {"(screen-fold-posture: book)", 0},
+    {"(screen-fold-posture: no-fold)", 0},
+    {nullptr, 0}  // Do not remove the terminator line.
+};
+
+MediaQueryEvaluatorTestCase g_screen_fold_posture_tent_cases[] = {
+    {"(screen-fold-posture)", 1},
+    {"(screen-fold-posture: laptop)", 0},
+    {"(screen-fold-posture: flat)", 0},
+    {"(screen-fold-posture: tent)", 1},
+    {"(screen-fold-posture: tablet)", 0},
+    {"(screen-fold-posture: book)", 0},
+    {"(screen-fold-posture: no-fold)", 0},
+    {nullptr, 0}  // Do not remove the terminator line.
+};
+
+MediaQueryEvaluatorTestCase g_screen_fold_posture_tablet_cases[] = {
+    {"(screen-fold-posture)", 1},
+    {"(screen-fold-posture: laptop)", 0},
+    {"(screen-fold-posture: flat)", 0},
+    {"(screen-fold-posture: tent)", 0},
+    {"(screen-fold-posture: tablet)", 1},
+    {"(screen-fold-posture: book)", 0},
+    {"(screen-fold-posture: no-fold)", 0},
+    {nullptr, 0}  // Do not remove the terminator line.
+};
+
+MediaQueryEvaluatorTestCase g_screen_fold_posture_book_cases[] = {
+    {"(screen-fold-posture)", 1},
+    {"(screen-fold-posture: laptop)", 0},
+    {"(screen-fold-posture: flat)", 0},
+    {"(screen-fold-posture: tent)", 0},
+    {"(screen-fold-posture: tablet)", 0},
+    {"(screen-fold-posture: book)", 1},
+    {"(screen-fold-posture: no-fold)", 0},
+    {nullptr, 0}  // Do not remove the terminator line.
+};
+
 void TestMQEvaluator(MediaQueryEvaluatorTestCase* test_cases,
                      const MediaQueryEvaluator& media_query_evaluator,
                      CSSParserMode mode) {
@@ -536,4 +605,52 @@
   }
 }
 
+TEST(MediaQueryEvaluatorTest, CachedScreenFoldPosture) {
+  ScopedScreenFoldForTest scoped_feature(true);
+
+  MediaValuesCached::MediaValuesCachedData data;
+  {
+    data.screen_fold_posture = ScreenFoldPosture::kNoFold;
+    MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
+
+    MediaQueryEvaluator media_query_evaluator(*media_values);
+    TestMQEvaluator(g_screen_fold_posture_none_cases, media_query_evaluator);
+  }
+
+  {
+    data.screen_fold_posture = ScreenFoldPosture::kLaptop;
+    MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
+    MediaQueryEvaluator media_query_evaluator(*media_values);
+    TestMQEvaluator(g_screen_fold_posture_laptop_cases, media_query_evaluator);
+  }
+
+  {
+    data.screen_fold_posture = ScreenFoldPosture::kFlat;
+    MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
+    MediaQueryEvaluator media_query_evaluator(*media_values);
+    TestMQEvaluator(g_screen_fold_posture_flat_cases, media_query_evaluator);
+  }
+
+  {
+    data.screen_fold_posture = ScreenFoldPosture::kTent;
+    MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
+    MediaQueryEvaluator media_query_evaluator(*media_values);
+    TestMQEvaluator(g_screen_fold_posture_tent_cases, media_query_evaluator);
+  }
+
+  {
+    data.screen_fold_posture = ScreenFoldPosture::kTablet;
+    MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
+    MediaQueryEvaluator media_query_evaluator(*media_values);
+    TestMQEvaluator(g_screen_fold_posture_tablet_cases, media_query_evaluator);
+  }
+
+  {
+    data.screen_fold_posture = ScreenFoldPosture::kBook;
+    MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
+    MediaQueryEvaluator media_query_evaluator(*media_values);
+    TestMQEvaluator(g_screen_fold_posture_book_cases, media_query_evaluator);
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/media_query_exp.cc b/third_party/blink/renderer/core/css/media_query_exp.cc
index 60177fab7..c2704b68 100644
--- a/third_party/blink/renderer/core/css/media_query_exp.cc
+++ b/third_party/blink/renderer/core/css/media_query_exp.cc
@@ -114,6 +114,14 @@
     }
   }
 
+  if (RuntimeEnabledFeatures::ScreenFoldEnabled()) {
+    if (media_feature == media_feature_names::kScreenFoldPostureMediaFeature) {
+      return ident == CSSValueID::kNoFold || ident == CSSValueID::kLaptop ||
+             ident == CSSValueID::kFlat || ident == CSSValueID::kTent ||
+             ident == CSSValueID::kTablet || ident == CSSValueID::kBook;
+    }
+  }
+
   return false;
 }
 
@@ -242,7 +250,10 @@
           RuntimeEnabledFeatures::OriginTrialsSampleAPIEnabled(
               execution_context)) ||
          (media_feature == media_feature_names::kScreenSpanningMediaFeature &&
-          RuntimeEnabledFeatures::CSSFoldablesEnabled());
+          RuntimeEnabledFeatures::CSSFoldablesEnabled()) ||
+         (media_feature ==
+              media_feature_names::kScreenFoldPostureMediaFeature &&
+          RuntimeEnabledFeatures::ScreenFoldEnabled());
 }
 
 bool MediaQueryExp::IsViewportDependent() const {
diff --git a/third_party/blink/renderer/core/css/media_query_set_test.cc b/third_party/blink/renderer/core/css/media_query_set_test.cc
index 6573f3e..69f675b 100644
--- a/third_party/blink/renderer/core/css/media_query_set_test.cc
+++ b/third_party/blink/renderer/core/css/media_query_set_test.cc
@@ -193,6 +193,7 @@
   ScopedForcedColorsForTest forced_colors_flag(false);
   ScopedMediaQueryNavigationControlsForTest navigation_controls_flag(false);
   ScopedCSSFoldablesForTest foldables_flag(false);
+  ScopedScreenFoldForTest screen_fold_flag(false);
 
   // The first string represents the input string, the second string represents
   // the output string.
@@ -200,10 +201,12 @@
       {"(forced-colors)", "not all"},
       {"(navigation-controls)", "not all"},
       {"(screen-spanning)", "not all"},
+      {"(screen-fold-posture)", "not all"},
       {"(shape: rect)", "not all"},
       {"(forced-colors: none)", "not all"},
       {"(navigation-controls: none)", "not all"},
       {"(screen-spanning:none)", "not all"},
+      {"(screen-fold-posture:none)", "not all"},
       {nullptr, nullptr}  // Do not remove the terminator line.
   };
 
diff --git a/third_party/blink/renderer/core/css/media_values.cc b/third_party/blink/renderer/core/css/media_values.cc
index 8214cef..0cd0675e 100644
--- a/third_party/blink/renderer/core/css/media_values.cc
+++ b/third_party/blink/renderer/core/css/media_values.cc
@@ -263,6 +263,11 @@
   return ScreenSpanning::kNone;
 }
 
+ScreenFoldPosture MediaValues::CalculateScreenFoldPosture(LocalFrame* frame) {
+  // TODO(darktears): Retrieve information from the host.
+  return ScreenFoldPosture::kNoFold;
+}
+
 bool MediaValues::ComputeLengthImpl(double value,
                                     CSSPrimitiveValue::UnitType type,
                                     unsigned default_font_size,
diff --git a/third_party/blink/renderer/core/css/media_values.h b/third_party/blink/renderer/core/css/media_values.h
index ce13d87..babd2eb 100644
--- a/third_party/blink/renderer/core/css/media_values.h
+++ b/third_party/blink/renderer/core/css/media_values.h
@@ -24,6 +24,7 @@
 enum class ForcedColors;
 enum class NavigationControls;
 enum class ScreenSpanning { kNone, kSingleFoldHorizontal, kSingleFoldVertical };
+enum class ScreenFoldPosture { kNoFold, kLaptop, kFlat, kTent, kTablet, kBook };
 
 mojom::blink::PreferredColorScheme CSSValueIDToPreferredColorScheme(
     CSSValueID id);
@@ -92,6 +93,7 @@
   virtual ForcedColors GetForcedColors() const = 0;
   virtual NavigationControls GetNavigationControls() const = 0;
   virtual ScreenSpanning GetScreenSpanning() const = 0;
+  virtual ScreenFoldPosture GetScreenFoldPosture() const = 0;
 
  protected:
   static double CalculateViewportWidth(LocalFrame*);
@@ -121,6 +123,7 @@
   static ForcedColors CalculateForcedColors();
   static NavigationControls CalculateNavigationControls(LocalFrame*);
   static ScreenSpanning CalculateScreenSpanning(LocalFrame*);
+  static ScreenFoldPosture CalculateScreenFoldPosture(LocalFrame*);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/media_values_cached.cc b/third_party/blink/renderer/core/css/media_values_cached.cc
index 2c5094a..44d8d0b 100644
--- a/third_party/blink/renderer/core/css/media_values_cached.cc
+++ b/third_party/blink/renderer/core/css/media_values_cached.cc
@@ -40,7 +40,8 @@
       prefers_reduced_motion(false),
       forced_colors(ForcedColors::kNone),
       navigation_controls(NavigationControls::kNone),
-      screen_spanning(ScreenSpanning::kNone) {}
+      screen_spanning(ScreenSpanning::kNone),
+      screen_fold_posture(ScreenFoldPosture::kNoFold) {}
 
 MediaValuesCached::MediaValuesCachedData::MediaValuesCachedData(
     Document& document)
@@ -85,6 +86,7 @@
     forced_colors = MediaValues::CalculateForcedColors();
     navigation_controls = MediaValues::CalculateNavigationControls(frame);
     screen_spanning = MediaValues::CalculateScreenSpanning(frame);
+    screen_fold_posture = MediaValues::CalculateScreenFoldPosture(frame);
   }
 }
 
@@ -225,4 +227,8 @@
   return data_.screen_spanning;
 }
 
+ScreenFoldPosture MediaValuesCached::GetScreenFoldPosture() const {
+  return data_.screen_fold_posture;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/media_values_cached.h b/third_party/blink/renderer/core/css/media_values_cached.h
index 4e152a3..76439c8 100644
--- a/third_party/blink/renderer/core/css/media_values_cached.h
+++ b/third_party/blink/renderer/core/css/media_values_cached.h
@@ -42,6 +42,7 @@
     ForcedColors forced_colors;
     NavigationControls navigation_controls;
     ScreenSpanning screen_spanning;
+    ScreenFoldPosture screen_fold_posture;
 
     MediaValuesCachedData();
     explicit MediaValuesCachedData(Document&);
@@ -73,6 +74,7 @@
       data.forced_colors = forced_colors;
       data.navigation_controls = navigation_controls;
       data.screen_spanning = screen_spanning;
+      data.screen_fold_posture = screen_fold_posture;
       return data;
     }
   };
@@ -115,6 +117,7 @@
   ForcedColors GetForcedColors() const override;
   NavigationControls GetNavigationControls() const override;
   ScreenSpanning GetScreenSpanning() const override;
+  ScreenFoldPosture GetScreenFoldPosture() const override;
 
   void OverrideViewportDimensions(double width, double height) override;
 
diff --git a/third_party/blink/renderer/core/css/media_values_dynamic.cc b/third_party/blink/renderer/core/css/media_values_dynamic.cc
index 9aaf3f35..b75305e 100644
--- a/third_party/blink/renderer/core/css/media_values_dynamic.cc
+++ b/third_party/blink/renderer/core/css/media_values_dynamic.cc
@@ -169,6 +169,10 @@
   return CalculateScreenSpanning(frame_);
 }
 
+ScreenFoldPosture MediaValuesDynamic::GetScreenFoldPosture() const {
+  return CalculateScreenFoldPosture(frame_);
+}
+
 Document* MediaValuesDynamic::GetDocument() const {
   return frame_->GetDocument();
 }
diff --git a/third_party/blink/renderer/core/css/media_values_dynamic.h b/third_party/blink/renderer/core/css/media_values_dynamic.h
index 56ed154..b78c855 100644
--- a/third_party/blink/renderer/core/css/media_values_dynamic.h
+++ b/third_party/blink/renderer/core/css/media_values_dynamic.h
@@ -54,6 +54,7 @@
   ForcedColors GetForcedColors() const override;
   NavigationControls GetNavigationControls() const override;
   ScreenSpanning GetScreenSpanning() const override;
+  ScreenFoldPosture GetScreenFoldPosture() const override;
   Document* GetDocument() const override;
   bool HasValues() const override;
   void OverrideViewportDimensions(double width, double height) override;
diff --git a/third_party/blink/renderer/core/dom/events/event_target.cc b/third_party/blink/renderer/core/dom/events/event_target.cc
index db26349c..5f3ff521f 100644
--- a/third_party/blink/renderer/core/dom/events/event_target.cc
+++ b/third_party/blink/renderer/core/dom/events/event_target.cc
@@ -208,14 +208,6 @@
       {event_type_names::kPointerover, WebFeature::kPointerOverOutFired},
       {event_type_names::kPointerout, WebFeature::kPointerOverOutFired},
       {event_type_names::kSearch, WebFeature::kSearchEventFired},
-      {event_type_names::kWebkitprerenderstart,
-       WebFeature::kWebkitPrerenderStartEventFired},
-      {event_type_names::kWebkitprerenderstop,
-       WebFeature::kWebkitPrerenderStopEventFired},
-      {event_type_names::kWebkitprerenderload,
-       WebFeature::kWebkitPrerenderLoadEventFired},
-      {event_type_names::kWebkitprerenderdomcontentloaded,
-       WebFeature::kWebkitPrerenderDOMContentLoadedEventFired},
   };
   for (const auto& counted_event : counted_events) {
     if (CheckTypeThenUseCount(event, counted_event.event_type,
diff --git a/third_party/blink/renderer/core/editing/OWNERS b/third_party/blink/renderer/core/editing/OWNERS
index 9dae515..0cf35cfbc 100644
--- a/third_party/blink/renderer/core/editing/OWNERS
+++ b/third_party/blink/renderer/core/editing/OWNERS
@@ -1,8 +1,5 @@
 yosin@chromium.org
 xiaochengh@chromium.org
 
-# IME-related changes
-changwan@chromium.org
-
 # TEAM: layout-dev@chromium.org
 # COMPONENT: Blink>Editing
diff --git a/third_party/blink/renderer/core/events/event_type_names.json5 b/third_party/blink/renderer/core/events/event_type_names.json5
index ef4697a..b6bf973 100644
--- a/third_party/blink/renderer/core/events/event_type_names.json5
+++ b/third_party/blink/renderer/core/events/event_type_names.json5
@@ -338,10 +338,6 @@
     "webkitTransitionEnd",
     "webkitfullscreenchange",
     "webkitfullscreenerror",
-    "webkitprerenderdomcontentloaded",
-    "webkitprerenderload",
-    "webkitprerenderstart",
-    "webkitprerenderstop",
     "webkitspeechchange",
     "webkitvisibilitychange",
     "wheel",
diff --git a/third_party/blink/renderer/core/html/html_link_element.cc b/third_party/blink/renderer/core/html/html_link_element.cc
index 9aee0c7..8ae0f2ff 100644
--- a/third_party/blink/renderer/core/html/html_link_element.cc
+++ b/third_party/blink/renderer/core/html/html_link_element.cc
@@ -363,23 +363,6 @@
   DispatchEvent(*Event::Create(event_type_names::kError));
 }
 
-void HTMLLinkElement::DidStartLinkPrerender() {
-  DispatchEvent(*Event::Create(event_type_names::kWebkitprerenderstart));
-}
-
-void HTMLLinkElement::DidStopLinkPrerender() {
-  DispatchEvent(*Event::Create(event_type_names::kWebkitprerenderstop));
-}
-
-void HTMLLinkElement::DidSendLoadForLinkPrerender() {
-  DispatchEvent(*Event::Create(event_type_names::kWebkitprerenderload));
-}
-
-void HTMLLinkElement::DidSendDOMContentLoadedForLinkPrerender() {
-  DispatchEvent(
-      *Event::Create(event_type_names::kWebkitprerenderdomcontentloaded));
-}
-
 scoped_refptr<base::SingleThreadTaskRunner>
 HTMLLinkElement::GetLoadingTaskRunner() {
   return GetDocument().GetTaskRunner(TaskType::kNetworking);
diff --git a/third_party/blink/renderer/core/html/html_link_element.h b/third_party/blink/renderer/core/html/html_link_element.h
index d7231b6..8bb59ce 100644
--- a/third_party/blink/renderer/core/html/html_link_element.h
+++ b/third_party/blink/renderer/core/html/html_link_element.h
@@ -162,10 +162,6 @@
   // From LinkLoaderClient
   void LinkLoaded() override;
   void LinkLoadingErrored() override;
-  void DidStartLinkPrerender() override;
-  void DidStopLinkPrerender() override;
-  void DidSendLoadForLinkPrerender() override;
-  void DidSendDOMContentLoadedForLinkPrerender() override;
   scoped_refptr<base::SingleThreadTaskRunner> GetLoadingTaskRunner() override;
 
   Member<LinkResource> link_;
diff --git a/third_party/blink/renderer/core/layout/layout_details_marker.cc b/third_party/blink/renderer/core/layout/layout_details_marker.cc
index 5e9899de..de7309d 100644
--- a/third_party/blink/renderer/core/layout/layout_details_marker.cc
+++ b/third_party/blink/renderer/core/layout/layout_details_marker.cc
@@ -31,20 +31,21 @@
 LayoutDetailsMarker::LayoutDetailsMarker(Element* element)
     : LayoutBlockFlow(element) {}
 
-LayoutDetailsMarker::Orientation LayoutDetailsMarker::GetOrientation() const {
-  NOT_DESTROYED();
+LayoutDetailsMarker::Orientation LayoutDetailsMarker::GetOrientation(
+    const ComputedStyle& style,
+    bool is_open) {
   // TODO(layout-dev): Sideways-lr and sideways-rl are not yet supported.
-  const auto mode = StyleRef().GetWritingMode();
+  const auto mode = style.GetWritingMode();
   DCHECK(mode != WritingMode::kSidewaysRl && mode != WritingMode::kSidewaysLr);
 
-  if (IsOpen()) {
-    if (mode == WritingMode::kHorizontalTb)
+  if (is_open) {
+    if (blink::IsHorizontalWritingMode(mode))
       return kDown;
-    return (mode == WritingMode::kVerticalRl) ? kLeft : kRight;
+    return IsFlippedBlocksWritingMode(mode) ? kLeft : kRight;
   }
-  if (mode == WritingMode::kHorizontalTb)
-    return StyleRef().IsLeftToRightDirection() ? kRight : kLeft;
-  return StyleRef().IsLeftToRightDirection() ? kDown : kUp;
+  if (blink::IsHorizontalWritingMode(mode))
+    return style.IsLeftToRightDirection() ? kRight : kLeft;
+  return style.IsLeftToRightDirection() ? kDown : kUp;
 }
 
 void LayoutDetailsMarker::Paint(const PaintInfo& paint_info) const {
diff --git a/third_party/blink/renderer/core/layout/layout_details_marker.h b/third_party/blink/renderer/core/layout/layout_details_marker.h
index fd7d461..79871fc 100644
--- a/third_party/blink/renderer/core/layout/layout_details_marker.h
+++ b/third_party/blink/renderer/core/layout/layout_details_marker.h
@@ -31,7 +31,8 @@
 
   enum Orientation { kUp, kDown, kLeft, kRight };
 
-  Orientation GetOrientation() const;
+  static Orientation GetOrientation(const ComputedStyle& style, bool is_open);
+  bool IsOpen() const;
 
   bool CreatesNewFormattingContext() const override {
     NOT_DESTROYED();
@@ -50,8 +51,6 @@
            LayoutBlockFlow::IsOfType(type);
   }
   void Paint(const PaintInfo&) const override;
-
-  bool IsOpen() const;
 };
 
 template <>
diff --git a/third_party/blink/renderer/core/layout/layout_tree_as_text.cc b/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
index 3d9ec79..04ade91 100644
--- a/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
@@ -235,7 +235,8 @@
 
   if (o.IsDetailsMarker()) {
     ts << ": ";
-    switch (To<LayoutDetailsMarker>(o).GetOrientation()) {
+    const auto& marker = To<LayoutDetailsMarker>(o);
+    switch (marker.GetOrientation(marker.StyleRef(), marker.IsOpen())) {
       case LayoutDetailsMarker::kLeft:
         ts << "left";
         break;
diff --git a/third_party/blink/renderer/core/layout/list_marker.cc b/third_party/blink/renderer/core/layout/list_marker.cc
index 7662e71..e910870 100644
--- a/third_party/blink/renderer/core/layout/list_marker.cc
+++ b/third_party/blink/renderer/core/layout/list_marker.cc
@@ -23,6 +23,15 @@
 // Recommended UA margin for list markers.
 const int kCUAMarkerMarginEm = 1;
 
+namespace {
+
+LayoutUnit DisclosureSymbolSize(const FontMetrics& font_metrics) {
+  LayoutUnit font_height(font_metrics.Height());
+  return font_height * 2 / 3;
+}
+
+}  // namespace
+
 ListMarker::ListMarker() : marker_text_type_(kNotText) {}
 
 const ListMarker* ListMarker::Get(const LayoutObject* marker) {
@@ -281,6 +290,11 @@
   DCHECK(font_data);
   if (!font_data)
     return LayoutUnit();
+  const auto type = style.ListStyleType();
+  if (type == EListStyleType::kDisclosureOpen ||
+      type == EListStyleType::kDisclosureClosed) {
+    return 1 + DisclosureSymbolSize(font_data->GetFontMetrics()) + 1;
+  }
   return LayoutUnit((font_data->GetFontMetrics().Ascent() * 2 / 3 + 1) / 2 + 2);
 }
 
@@ -313,7 +327,8 @@
     margin_start = -marker_inline_size - kCMarkerPaddingPx;
     margin_end = LayoutUnit(kCMarkerPaddingPx);
   } else {
-    switch (GetListStyleCategory(list_item_style.ListStyleType())) {
+    auto type = list_item_style.ListStyleType();
+    switch (GetListStyleCategory(type)) {
       case ListStyleCategory::kNone:
         break;
       case ListStyleCategory::kSymbol: {
@@ -322,8 +337,11 @@
         if (!font_data)
           return {};
         const FontMetrics& font_metrics = font_data->GetFontMetrics();
-        int offset = font_metrics.Ascent() * 2 / 3;
-        margin_start = LayoutUnit(-offset - kCMarkerPaddingPx - 1);
+        LayoutUnit offset = (type == EListStyleType::kDisclosureOpen ||
+                             type == EListStyleType::kDisclosureClosed)
+                                ? DisclosureSymbolSize(font_metrics)
+                                : LayoutUnit(font_metrics.Ascent() * 2 / 3);
+        margin_start = -offset - kCMarkerPaddingPx - 1;
         margin_end = offset + kCMarkerPaddingPx + 1 - marker_inline_size;
         break;
       }
@@ -346,10 +364,18 @@
   // TODO(wkorman): Review and clean up/document the calculations below.
   // http://crbug.com/543193
   const FontMetrics& font_metrics = font_data->GetFontMetrics();
-  int ascent = font_metrics.Ascent();
-  int bullet_width = (ascent * 2 / 3 + 1) / 2;
-  relative_rect = LayoutRect(1, 3 * (ascent - ascent * 2 / 3) / 2, bullet_width,
-                             bullet_width);
+  const auto type = style.ListStyleType();
+  if (type == EListStyleType::kDisclosureOpen ||
+      type == EListStyleType::kDisclosureClosed) {
+    LayoutUnit marker_size = DisclosureSymbolSize(font_metrics);
+    relative_rect =
+        LayoutRect(LayoutUnit(1), marker_size / 4, marker_size, marker_size);
+  } else {
+    int ascent = font_metrics.Ascent();
+    int bullet_width = (ascent * 2 / 3 + 1) / 2;
+    relative_rect = LayoutRect(1, 3 * (ascent - ascent * 2 / 3) / 2,
+                               bullet_width, bullet_width);
+  }
   if (!style.IsHorizontalWritingMode()) {
     relative_rect = relative_rect.TransposedRect();
     relative_rect.SetX(width - relative_rect.X() - relative_rect.Width());
@@ -367,6 +393,8 @@
     case EListStyleType::kDisc:
     case EListStyleType::kCircle:
     case EListStyleType::kSquare:
+    case EListStyleType::kDisclosureOpen:
+    case EListStyleType::kDisclosureClosed:
       return ListStyleCategory::kSymbol;
     case EListStyleType::kArabicIndic:
     case EListStyleType::kArmenian:
diff --git a/third_party/blink/renderer/core/layout/list_marker_text.cc b/third_party/blink/renderer/core/layout/list_marker_text.cc
index 174c83e..3a8e58f8 100644
--- a/third_party/blink/renderer/core/layout/list_marker_text.cc
+++ b/third_party/blink/renderer/core/layout/list_marker_text.cc
@@ -461,6 +461,8 @@
     case EListStyleType::kDecimal:
     case EListStyleType::kDevanagari:
     case EListStyleType::kDisc:
+    case EListStyleType::kDisclosureClosed:
+    case EListStyleType::kDisclosureOpen:
     case EListStyleType::kGujarati:
     case EListStyleType::kGurmukhi:
     case EListStyleType::kKannada:
@@ -535,6 +537,8 @@
   switch (effective_type) {
     case EListStyleType::kCircle:
     case EListStyleType::kDisc:
+    case EListStyleType::kDisclosureClosed:
+    case EListStyleType::kDisclosureOpen:
     case EListStyleType::kNone:
     case EListStyleType::kSquare:
       return ' ';
@@ -616,6 +620,14 @@
       return String(&kWhiteBulletCharacter, 1);
     case EListStyleType::kDisc:
       return String(&kBulletCharacter, 1);
+
+    // TODO(layout-dev): Text for disclosure-* should not depend on physical
+    // shape?
+    case EListStyleType::kDisclosureClosed:
+      return String(&kBlackRightPointingSmallTriangle, 1);
+    case EListStyleType::kDisclosureOpen:
+      return String(&kBlackDownPointingSmallTriangle, 1);
+
     case EListStyleType::kSquare:
       // The CSS 2.1 test suite uses U+25EE BLACK MEDIUM SMALL SQUARE
       // instead, but I think this looks better.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
index d69c8c1..273dfa1 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
@@ -1076,7 +1076,8 @@
       MinimumValueForLength(style.PaddingBefore(), percentage_resolution_size),
       MinimumValueForLength(style.PaddingAfter(), percentage_resolution_size)};
 
-  if (style.Display() == EDisplay::kTableCell) {
+  if (!RuntimeEnabledFeatures::LayoutNGTableEnabled() &&
+      style.Display() == EDisplay::kTableCell) {
     // Compatibility hack to mach legacy layout. Legacy layout floors padding on
     // the block sides, but not on the inline sides. o.O
     padding.block_start = LayoutUnit(padding.block_start.Floor());
diff --git a/third_party/blink/renderer/core/loader/build.gni b/third_party/blink/renderer/core/loader/build.gni
index c99a873..d74d3ebc 100644
--- a/third_party/blink/renderer/core/loader/build.gni
+++ b/third_party/blink/renderer/core/loader/build.gni
@@ -104,7 +104,6 @@
   "previews_resource_loading_hints.h",
   "private/frame_client_hints_preferences_context.cc",
   "private/frame_client_hints_preferences_context.h",
-  "private/prerender_client.h",
   "private/prerender_handle.cc",
   "private/prerender_handle.h",
   "progress_tracker.cc",
diff --git a/third_party/blink/renderer/core/loader/link_loader.cc b/third_party/blink/renderer/core/loader/link_loader.cc
index e60fbda..a9cff32 100644
--- a/third_party/blink/renderer/core/loader/link_loader.cc
+++ b/third_party/blink/renderer/core/loader/link_loader.cc
@@ -149,22 +149,6 @@
     client_->LinkLoaded();
 }
 
-void LinkLoader::DidStartPrerender() {
-  client_->DidStartLinkPrerender();
-}
-
-void LinkLoader::DidStopPrerender() {
-  client_->DidStopLinkPrerender();
-}
-
-void LinkLoader::DidSendLoadForPrerender() {
-  client_->DidSendLoadForLinkPrerender();
-}
-
-void LinkLoader::DidSendDOMContentLoadedForPrerender() {
-  client_->DidSendDOMContentLoadedForLinkPrerender();
-}
-
 Resource* LinkLoader::GetResourceForTesting() {
   return finish_observer_ ? finish_observer_->GetResource() : nullptr;
 }
@@ -201,8 +185,8 @@
   if (prerender_rel_type) {
     // The previous prerender should already be aborted by Abort().
     DCHECK(!prerender_);
-    prerender_ = PrerenderHandle::Create(document, this, params.href,
-                                         *prerender_rel_type);
+    prerender_ =
+        PrerenderHandle::Create(document, params.href, *prerender_rel_type);
   }
   return true;
 }
@@ -269,7 +253,6 @@
   visitor->Trace(client_);
   visitor->Trace(prerender_);
   SingleModuleClient::Trace(visitor);
-  PrerenderClient::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/link_loader.h b/third_party/blink/renderer/core/loader/link_loader.h
index 5b0fbaf..510f37dc 100644
--- a/third_party/blink/renderer/core/loader/link_loader.h
+++ b/third_party/blink/renderer/core/loader/link_loader.h
@@ -34,7 +34,6 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/loader/link_load_parameters.h"
-#include "third_party/blink/renderer/core/loader/private/prerender_client.h"
 #include "third_party/blink/renderer/core/script/modulator.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
 
@@ -48,18 +47,11 @@
 
 // The LinkLoader can load link rel types icon, dns-prefetch, prefetch, and
 // prerender.
-class CORE_EXPORT LinkLoader final : public SingleModuleClient,
-                                     public PrerenderClient {
+class CORE_EXPORT LinkLoader final : public SingleModuleClient {
  public:
   LinkLoader(LinkLoaderClient*, scoped_refptr<base::SingleThreadTaskRunner>);
   ~LinkLoader() override;
 
-  // from PrerenderClient
-  void DidStartPrerender() override;
-  void DidStopPrerender() override;
-  void DidSendLoadForPrerender() override;
-  void DidSendDOMContentLoadedForPrerender() override;
-
   void Abort();
   bool LoadLink(const LinkLoadParameters&, Document&);
   void LoadStylesheet(const LinkLoadParameters&,
diff --git a/third_party/blink/renderer/core/loader/link_loader_client.h b/third_party/blink/renderer/core/loader/link_loader_client.h
index 7a1b0ac..d6cca52 100644
--- a/third_party/blink/renderer/core/loader/link_loader_client.h
+++ b/third_party/blink/renderer/core/loader/link_loader_client.h
@@ -49,10 +49,6 @@
   virtual void LinkLoadingErrored() = 0;
   // There is no notification for cancellation.
 
-  virtual void DidStartLinkPrerender() = 0;
-  virtual void DidStopLinkPrerender() = 0;
-  virtual void DidSendLoadForLinkPrerender() = 0;
-  virtual void DidSendDOMContentLoadedForLinkPrerender() = 0;
   virtual bool IsLinkCreatedByParser() = 0;
 
   virtual scoped_refptr<base::SingleThreadTaskRunner>
diff --git a/third_party/blink/renderer/core/loader/link_loader_test.cc b/third_party/blink/renderer/core/loader/link_loader_test.cc
index 2ce7173..1693ea5b 100644
--- a/third_party/blink/renderer/core/loader/link_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/link_loader_test.cc
@@ -52,10 +52,6 @@
 
   void LinkLoaded() override {}
   void LinkLoadingErrored() override {}
-  void DidStartLinkPrerender() override {}
-  void DidStopLinkPrerender() override {}
-  void DidSendLoadForLinkPrerender() override {}
-  void DidSendDOMContentLoadedForLinkPrerender() override {}
 
   scoped_refptr<base::SingleThreadTaskRunner> GetLoadingTaskRunner() override {
     return Thread::Current()->GetTaskRunner();
diff --git a/third_party/blink/renderer/core/loader/prerender_test.cc b/third_party/blink/renderer/core/loader/prerender_test.cc
index c28ee0a..96d02a7 100644
--- a/third_party/blink/renderer/core/loader/prerender_test.cc
+++ b/third_party/blink/renderer/core/loader/prerender_test.cc
@@ -76,11 +76,8 @@
   ~MockPrerenderProcessor() override = default;
 
   // mojom::blink::PrerenderProcessor implementation
-  void Start(mojom::blink::PrerenderAttributesPtr attributes,
-             mojo::PendingRemote<mojom::blink::PrerenderProcessorClient> client)
-      override {
+  void Start(mojom::blink::PrerenderAttributesPtr attributes) override {
     attributes_ = std::move(attributes);
-    client_.Bind(std::move(client));
   }
   void Cancel() override { cancel_count_++; }
 
@@ -92,29 +89,8 @@
     return attributes_->rel_type;
   }
 
-  // Used to simulate state changes of the mock prerendered web page. These
-  // calls spin the message loop so that the client's receiver side gets a
-  // chance to run.
-  void NotifyDidStartPrerender() {
-    client_->OnPrerenderStart();
-    test::RunPendingTasks();
-  }
-  void NotifyDidSendDOMContentLoadedForPrerender() {
-    client_->OnPrerenderDomContentLoaded();
-    test::RunPendingTasks();
-  }
-  void NotifyDidSendLoadForPrerender() {
-    client_->OnPrerenderStopLoading();
-    test::RunPendingTasks();
-  }
-  void NotifyDidStopPrerender() {
-    client_->OnPrerenderStop();
-    test::RunPendingTasks();
-  }
-
  private:
   mojom::blink::PrerenderAttributesPtr attributes_;
-  mojo::Remote<mojom::blink::PrerenderProcessorClient> client_;
   mojo::Receiver<mojom::blink::PrerenderProcessor> receiver_{this};
 
   size_t cancel_count_ = 0;
@@ -172,34 +148,6 @@
     test::RunPendingTasks();
   }
 
-  Element& Console() {
-    Document* document =
-        web_view_helper_.LocalMainFrame()->GetFrame()->GetDocument();
-    Element* console = document->getElementById("console");
-    DCHECK(IsA<HTMLUListElement>(console));
-    return *console;
-  }
-
-  unsigned ConsoleLength() { return Console().CountChildren() - 1; }
-
-  WebString ConsoleAt(unsigned i) {
-    DCHECK_GT(ConsoleLength(), i);
-
-    Node* item = NodeTraversal::ChildAt(Console(), 1 + i);
-
-    DCHECK(item);
-    DCHECK(IsA<HTMLLIElement>(item));
-    DCHECK(item->hasChildren());
-
-    return item->textContent();
-  }
-
-  bool IsUseCounted(mojom::WebFeature web_feature) {
-    Document* document =
-        web_view_helper_.LocalMainFrame()->GetFrame()->GetDocument();
-    return document->IsUseCounted(web_feature);
-  }
-
   void ExecuteScript(const char* code) {
     web_view_helper_.LocalMainFrame()->ExecuteScript(
         WebScriptSource(WebString::FromUTF8(code)));
@@ -237,32 +185,6 @@
   EXPECT_EQ(mojom::blink::PrerenderRelType::kPrerender, processor.RelType());
 
   EXPECT_EQ(0u, processor.CancelCount());
-
-  EXPECT_FALSE(IsUseCounted(WebFeature::kWebkitPrerenderStartEventFired));
-  processor.NotifyDidStartPrerender();
-  EXPECT_EQ(1u, ConsoleLength());
-  EXPECT_EQ("webkitprerenderstart", ConsoleAt(0));
-  EXPECT_TRUE(IsUseCounted(WebFeature::kWebkitPrerenderStartEventFired));
-
-  EXPECT_FALSE(
-      IsUseCounted(WebFeature::kWebkitPrerenderDOMContentLoadedEventFired));
-  processor.NotifyDidSendDOMContentLoadedForPrerender();
-  EXPECT_EQ(2u, ConsoleLength());
-  EXPECT_EQ("webkitprerenderdomcontentloaded", ConsoleAt(1));
-  EXPECT_TRUE(
-      IsUseCounted(WebFeature::kWebkitPrerenderDOMContentLoadedEventFired));
-
-  EXPECT_FALSE(IsUseCounted(WebFeature::kWebkitPrerenderLoadEventFired));
-  processor.NotifyDidSendLoadForPrerender();
-  EXPECT_EQ(3u, ConsoleLength());
-  EXPECT_EQ("webkitprerenderload", ConsoleAt(2));
-  EXPECT_TRUE(IsUseCounted(WebFeature::kWebkitPrerenderLoadEventFired));
-
-  EXPECT_FALSE(IsUseCounted(WebFeature::kWebkitPrerenderStopEventFired));
-  processor.NotifyDidStopPrerender();
-  EXPECT_EQ(4u, ConsoleLength());
-  EXPECT_EQ("webkitprerenderstop", ConsoleAt(3));
-  EXPECT_TRUE(IsUseCounted(WebFeature::kWebkitPrerenderStopEventFired));
 }
 
 TEST_F(PrerenderTest, CancelPrerender) {
@@ -271,9 +193,7 @@
   MockPrerenderProcessor& processor = *processors()[0];
 
   EXPECT_EQ(0u, processor.CancelCount());
-
   ExecuteScript("removePrerender()");
-
   EXPECT_EQ(1u, processor.CancelCount());
 }
 
@@ -288,14 +208,6 @@
 
   EXPECT_EQ(0u, first_processor.CancelCount());
   EXPECT_EQ(0u, second_processor.CancelCount());
-
-  first_processor.NotifyDidStartPrerender();
-  EXPECT_EQ(1u, ConsoleLength());
-  EXPECT_EQ("first_webkitprerenderstart", ConsoleAt(0));
-
-  second_processor.NotifyDidStartPrerender();
-  EXPECT_EQ(2u, ConsoleLength());
-  EXPECT_EQ("second_webkitprerenderstart", ConsoleAt(1));
 }
 
 TEST_F(PrerenderTest, TwoPrerendersRemovingFirstThenNavigating) {
@@ -339,40 +251,6 @@
   EXPECT_EQ(0u, third_processor.CancelCount());
 }
 
-TEST_F(PrerenderTest, ShortLivedClient) {
-  Initialize("http://www.foo.com/", "prerender/single_prerender.html");
-  ASSERT_EQ(processors().size(), 1u);
-  MockPrerenderProcessor& processor = *processors()[0];
-
-  EXPECT_EQ(0u, processor.CancelCount());
-
-  NavigateAway();
-  Close();
-
-  // This test passes if this next line doesn't crash.
-  processor.NotifyDidStartPrerender();
-}
-
-TEST_F(PrerenderTest, FastRemoveElement) {
-  Initialize("http://www.foo.com/", "prerender/single_prerender.html");
-  ASSERT_EQ(processors().size(), 1u);
-  MockPrerenderProcessor& processor = *processors()[0];
-
-  EXPECT_EQ(0u, processor.CancelCount());
-
-  // Race removing & starting the prerender against each other, as if the
-  // element was removed very quickly.
-  ExecuteScript("removePrerender()");
-  processor.NotifyDidStartPrerender();
-
-  // Removing the element should cancel prerendering.
-  EXPECT_EQ(1u, processor.CancelCount());
-
-  // The page should be totally disconnected from the Prerender at this point,
-  // so the console should not have updated.
-  EXPECT_EQ(0u, ConsoleLength());
-}
-
 TEST_F(PrerenderTest, MutateTarget) {
   Initialize("http://www.foo.com/", "prerender/single_prerender.html");
   ASSERT_EQ(processors().size(), 1u);
diff --git a/third_party/blink/renderer/core/loader/private/prerender_client.h b/third_party/blink/renderer/core/loader/private/prerender_client.h
deleted file mode 100644
index 9965225..0000000
--- a/third_party/blink/renderer/core/loader/private/prerender_client.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRIVATE_PRERENDER_CLIENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRIVATE_PRERENDER_CLIENT_H_
-
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-
-namespace blink {
-
-class PLATFORM_EXPORT PrerenderClient : public GarbageCollectedMixin {
- public:
-  virtual ~PrerenderClient() = default;
-
-  virtual void DidStartPrerender() = 0;
-  virtual void DidStopPrerender() = 0;
-  virtual void DidSendLoadForPrerender() = 0;
-  virtual void DidSendDOMContentLoadedForPrerender() = 0;
-
-  void Trace(Visitor* visitor) const override {}
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PRIVATE_PRERENDER_CLIENT_H_
diff --git a/third_party/blink/renderer/core/loader/private/prerender_handle.cc b/third_party/blink/renderer/core/loader/private/prerender_handle.cc
index 0033081..62e0521a 100644
--- a/third_party/blink/renderer/core/loader/private/prerender_handle.cc
+++ b/third_party/blink/renderer/core/loader/private/prerender_handle.cc
@@ -35,7 +35,6 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
-#include "third_party/blink/renderer/core/loader/private/prerender_client.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
 
@@ -44,7 +43,6 @@
 // static
 PrerenderHandle* PrerenderHandle::Create(
     Document& document,
-    PrerenderClient* client,
     const KURL& url,
     mojom::blink::PrerenderRelType prerender_rel_type) {
   // Prerenders are unlike requests in most ways (for instance, they pass down
@@ -70,32 +68,18 @@
       prerender_processor.BindNewPipeAndPassReceiver(
           context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
 
-  mojo::PendingRemote<mojom::blink::PrerenderProcessorClient>
-      prerender_processor_client;
-  auto receiver = prerender_processor_client.InitWithNewPipeAndPassReceiver();
+  prerender_processor->Start(std::move(attributes));
 
-  prerender_processor->Start(std::move(attributes),
-                             std::move(prerender_processor_client));
-
-  return MakeGarbageCollected<PrerenderHandle>(PassKey(), context, client, url,
-                                               std::move(prerender_processor),
-                                               std::move(receiver));
+  return MakeGarbageCollected<PrerenderHandle>(PassKey(), context, url,
+                                               std::move(prerender_processor));
 }
 
 PrerenderHandle::PrerenderHandle(
     PassKey pass_key,
     ExecutionContext* context,
-    PrerenderClient* client,
     const KURL& url,
-    HeapMojoRemote<mojom::blink::PrerenderProcessor> remote_processor,
-    mojo::PendingReceiver<mojom::blink::PrerenderProcessorClient> receiver)
-    : url_(url),
-      client_(client),
-      remote_processor_(std::move(remote_processor)),
-      receiver_(this, context) {
-  receiver_.Bind(std::move(receiver),
-                 context->GetTaskRunner(TaskType::kMiscPlatformAPI));
-}
+    HeapMojoRemote<mojom::blink::PrerenderProcessor> remote_processor)
+    : url_(url), remote_processor_(std::move(remote_processor)) {}
 
 PrerenderHandle::~PrerenderHandle() = default;
 
@@ -103,37 +87,14 @@
   if (remote_processor_.is_bound())
     remote_processor_->Cancel();
   remote_processor_.reset();
-  receiver_.reset();
 }
 
 const KURL& PrerenderHandle::Url() const {
   return url_;
 }
 
-void PrerenderHandle::OnPrerenderStart() {
-  if (client_)
-    client_->DidStartPrerender();
-}
-
-void PrerenderHandle::OnPrerenderStopLoading() {
-  if (client_)
-    client_->DidSendLoadForPrerender();
-}
-
-void PrerenderHandle::OnPrerenderDomContentLoaded() {
-  if (client_)
-    client_->DidSendDOMContentLoadedForPrerender();
-}
-
-void PrerenderHandle::OnPrerenderStop() {
-  if (client_)
-    client_->DidStopPrerender();
-}
-
 void PrerenderHandle::Trace(Visitor* visitor) const {
-  visitor->Trace(client_);
   visitor->Trace(remote_processor_);
-  visitor->Trace(receiver_);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/private/prerender_handle.h b/third_party/blink/renderer/core/loader/private/prerender_handle.h
index 3cea0252..9382fa3 100644
--- a/third_party/blink/renderer/core/loader/private/prerender_handle.h
+++ b/third_party/blink/renderer/core/loader/private/prerender_handle.h
@@ -37,7 +37,6 @@
 #include "third_party/blink/public/mojom/prerender/prerender.mojom-blink.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 
@@ -45,13 +44,11 @@
 
 class ExecutionContext;
 class Document;
-class PrerenderClient;
 
 // This is the Blink-side liaison of mojom::PrerenderProcessor to request the
-// browser process to start prerendering, and implements
-// mojom::PrerenderProcessorClient to observe events about prerendering. This is
-// instantiated per prerender request, for example, when a new <link
-// rel=prerender> element is added, when the element's href is changed etc.
+// browser process to start prerendering. This is instantiated per prerender
+// request, for example, when a new <link rel=prerender> element is added, when
+// the element's href is changed etc.
 //
 // When you no longer need the prerendering page (e.g., when the
 // <link rel=prerender> element is removed), you can ask the browser process to
@@ -61,44 +58,30 @@
 // navigation occurs to that URL shortly after.
 //
 // TODO(https://crbug.com/1126305): Rename this to PrerenderProcessorClient.
-class PrerenderHandle final : public GarbageCollected<PrerenderHandle>,
-                              public mojom::blink::PrerenderProcessorClient {
+class PrerenderHandle final : public GarbageCollected<PrerenderHandle> {
  public:
   static PrerenderHandle* Create(
       Document&,
-      PrerenderClient*,
       const KURL&,
       mojom::blink::PrerenderRelType prerender_rel_type);
 
   using PassKey = base::PassKey<PrerenderHandle>;
-  PrerenderHandle(
-      PassKey,
-      ExecutionContext*,
-      PrerenderClient*,
-      const KURL&,
-      HeapMojoRemote<mojom::blink::PrerenderProcessor>,
-      mojo::PendingReceiver<mojom::blink::PrerenderProcessorClient>);
-  ~PrerenderHandle() override;
+  PrerenderHandle(PassKey,
+                  ExecutionContext*,
+                  const KURL&,
+                  HeapMojoRemote<mojom::blink::PrerenderProcessor>);
+  ~PrerenderHandle();
 
   // Asks the browser process to cancel the running prerender.
   void Cancel();
 
   const KURL& Url() const;
 
-  // mojom::blink::PrerenderProcessorClient:
-  void OnPrerenderStart() override;
-  void OnPrerenderStopLoading() override;
-  void OnPrerenderDomContentLoaded() override;
-  void OnPrerenderStop() override;
-
   virtual void Trace(Visitor*) const;
 
  private:
   const KURL url_;
-  const WeakMember<PrerenderClient> client_;
   HeapMojoRemote<mojom::blink::PrerenderProcessor> remote_processor_;
-  HeapMojoReceiver<mojom::blink::PrerenderProcessorClient, PrerenderHandle>
-      receiver_;
 
   DISALLOW_COPY_AND_ASSIGN(PrerenderHandle);
 };
diff --git a/third_party/blink/renderer/core/paint/details_marker_painter.cc b/third_party/blink/renderer/core/paint/details_marker_painter.cc
index b22caa8f..ef16b9a 100644
--- a/third_party/blink/renderer/core/paint/details_marker_painter.cc
+++ b/third_party/blink/renderer/core/paint/details_marker_painter.cc
@@ -78,8 +78,9 @@
   return CreatePath(points);
 }
 
-Path DetailsMarkerPainter::GetCanonicalPath() const {
-  switch (layout_details_marker_.GetOrientation()) {
+Path DetailsMarkerPainter::GetCanonicalPath(const ComputedStyle& style,
+                                            bool is_open) {
+  switch (LayoutDetailsMarker::GetOrientation(style, is_open)) {
     case LayoutDetailsMarker::kLeft:
       return CreateLeftArrowPath();
     case LayoutDetailsMarker::kRight:
@@ -94,7 +95,8 @@
 }
 
 Path DetailsMarkerPainter::GetPath(const PhysicalOffset& origin) const {
-  Path result = GetCanonicalPath();
+  Path result = GetCanonicalPath(layout_details_marker_.StyleRef(),
+                                 layout_details_marker_.IsOpen());
   result.Transform(AffineTransform().Scale(
       layout_details_marker_.ContentWidth().ToFloat(),
       layout_details_marker_.ContentHeight().ToFloat()));
diff --git a/third_party/blink/renderer/core/paint/details_marker_painter.h b/third_party/blink/renderer/core/paint/details_marker_painter.h
index e5b1064..6593b73e 100644
--- a/third_party/blink/renderer/core/paint/details_marker_painter.h
+++ b/third_party/blink/renderer/core/paint/details_marker_painter.h
@@ -9,6 +9,7 @@
 
 namespace blink {
 
+class ComputedStyle;
 class Path;
 class LayoutDetailsMarker;
 struct PaintInfo;
@@ -22,9 +23,9 @@
       : layout_details_marker_(layout_details_marker) {}
 
   void Paint(const PaintInfo&);
+  static Path GetCanonicalPath(const ComputedStyle& style, bool is_open);
 
  private:
-  Path GetCanonicalPath() const;
   Path GetPath(const PhysicalOffset& origin) const;
 
   const LayoutDetailsMarker& layout_details_marker_;
diff --git a/third_party/blink/renderer/core/paint/list_marker_painter.cc b/third_party/blink/renderer/core/paint/list_marker_painter.cc
index 603dd4a..9c8e1cf8 100644
--- a/third_party/blink/renderer/core/paint/list_marker_painter.cc
+++ b/third_party/blink/renderer/core/paint/list_marker_painter.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/core/layout/list_marker_text.h"
 #include "third_party/blink/renderer/core/paint/box_model_object_painter.h"
 #include "third_party/blink/renderer/core/paint/box_painter.h"
+#include "third_party/blink/renderer/core/paint/details_marker_painter.h"
 #include "third_party/blink/renderer/core/paint/highlight_painting_utils.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
 #include "third_party/blink/renderer/core/paint/scoped_paint_state.h"
@@ -48,6 +49,15 @@
     case EListStyleType::kSquare:
       context.FillRect(marker);
       break;
+    case EListStyleType::kDisclosureOpen:
+    case EListStyleType::kDisclosureClosed: {
+      Path path = DetailsMarkerPainter::GetCanonicalPath(
+          style, style.ListStyleType() == EListStyleType::kDisclosureOpen);
+      path.Transform(AffineTransform().Scale(marker.Width(), marker.Height()));
+      path.Translate(FloatSize(marker.X(), marker.Y()));
+      context.FillPath(path);
+      break;
+    }
     default:
       NOTREACHED();
       break;
diff --git a/third_party/blink/renderer/core/script/document_modulator_impl.cc b/third_party/blink/renderer/core/script/document_modulator_impl.cc
index aaddc37..75b2adf5 100644
--- a/third_party/blink/renderer/core/script/document_modulator_impl.cc
+++ b/third_party/blink/renderer/core/script/document_modulator_impl.cc
@@ -4,11 +4,7 @@
 
 #include "third_party/blink/renderer/core/script/document_modulator_impl.h"
 
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
 
 namespace blink {
 
@@ -26,12 +22,4 @@
   return false;
 }
 
-mojom::blink::V8CacheOptions DocumentModulatorImpl::GetV8CacheOptions() const {
-  LocalDOMWindow* window = To<LocalDOMWindow>(GetExecutionContext());
-  const Settings* settings = window->GetFrame()->GetSettings();
-  if (settings)
-    return settings->GetV8CacheOptions();
-  return mojom::blink::V8CacheOptions::kDefault;
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/script/document_modulator_impl.h b/third_party/blink/renderer/core/script/document_modulator_impl.h
index dd26eb7..a4846d2 100644
--- a/third_party/blink/renderer/core/script/document_modulator_impl.h
+++ b/third_party/blink/renderer/core/script/document_modulator_impl.h
@@ -31,7 +31,6 @@
  private:
   // Implements ModulatorImplBase.
   bool IsDynamicImportForbidden(String* reason) override;
-  mojom::blink::V8CacheOptions GetV8CacheOptions() const override;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/script/modulator_impl_base.cc b/third_party/blink/renderer/core/script/modulator_impl_base.cc
index 87b4419..7a62238 100644
--- a/third_party/blink/renderer/core/script/modulator_impl_base.cc
+++ b/third_party/blink/renderer/core/script/modulator_impl_base.cc
@@ -57,6 +57,10 @@
   return RuntimeEnabledFeatures::ImportMapsEnabled(GetExecutionContext());
 }
 
+mojom::blink::V8CacheOptions ModulatorImplBase::GetV8CacheOptions() const {
+  return GetExecutionContext()->GetV8CacheOptions();
+}
+
 // <specdef label="fetch-a-module-script-tree"
 // href="https://html.spec.whatwg.org/C/#fetch-a-module-script-tree">
 // <specdef label="fetch-a-module-worker-script-tree"
diff --git a/third_party/blink/renderer/core/script/modulator_impl_base.h b/third_party/blink/renderer/core/script/modulator_impl_base.h
index ce455c8..2e3ac50 100644
--- a/third_party/blink/renderer/core/script/modulator_impl_base.h
+++ b/third_party/blink/renderer/core/script/modulator_impl_base.h
@@ -44,6 +44,8 @@
 
   bool ImportMapsEnabled() const override;
 
+  mojom::blink::V8CacheOptions GetV8CacheOptions() const final;
+
   ModuleRecordResolver* GetModuleRecordResolver() override {
     return module_record_resolver_.Get();
   }
diff --git a/third_party/blink/renderer/core/script/worker_modulator_impl.cc b/third_party/blink/renderer/core/script/worker_modulator_impl.cc
index 66ec2bff..c93b05f 100644
--- a/third_party/blink/renderer/core/script/worker_modulator_impl.cc
+++ b/third_party/blink/renderer/core/script/worker_modulator_impl.cc
@@ -4,12 +4,10 @@
 
 #include "third_party/blink/renderer/core/script/worker_modulator_impl.h"
 
-#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h"
 #include "third_party/blink/renderer/core/loader/modulescript/installed_service_worker_module_script_fetcher.h"
 #include "third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.h"
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
-#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
@@ -55,9 +53,4 @@
   return true;
 }
 
-mojom::blink::V8CacheOptions WorkerModulatorImpl::GetV8CacheOptions() const {
-  auto* scope = To<WorkerGlobalScope>(GetExecutionContext());
-  return scope->GetV8CacheOptions();
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/script/worker_modulator_impl.h b/third_party/blink/renderer/core/script/worker_modulator_impl.h
index 2f4c458..fa327d7 100644
--- a/third_party/blink/renderer/core/script/worker_modulator_impl.h
+++ b/third_party/blink/renderer/core/script/worker_modulator_impl.h
@@ -27,7 +27,6 @@
  private:
   // Implements ModulatorImplBase.
   bool IsDynamicImportForbidden(String* reason) override;
-  mojom::blink::V8CacheOptions GetV8CacheOptions() const override;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/script/worklet_modulator_impl.cc b/third_party/blink/renderer/core/script/worklet_modulator_impl.cc
index fa50886f..c78d70a 100644
--- a/third_party/blink/renderer/core/script/worklet_modulator_impl.cc
+++ b/third_party/blink/renderer/core/script/worklet_modulator_impl.cc
@@ -27,9 +27,4 @@
   return true;
 }
 
-mojom::blink::V8CacheOptions WorkletModulatorImpl::GetV8CacheOptions() const {
-  auto* scope = To<WorkletGlobalScope>(GetExecutionContext());
-  return scope->GetV8CacheOptions();
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/script/worklet_modulator_impl.h b/third_party/blink/renderer/core/script/worklet_modulator_impl.h
index 58bf1f37c..8784abd 100644
--- a/third_party/blink/renderer/core/script/worklet_modulator_impl.h
+++ b/third_party/blink/renderer/core/script/worklet_modulator_impl.h
@@ -29,7 +29,6 @@
  private:
   // Implements ModulatorImplBase.
   bool IsDynamicImportForbidden(String* reason) override;
-  mojom::blink::V8CacheOptions GetV8CacheOptions() const override;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/style/computed_style_constants.h b/third_party/blink/renderer/core/style/computed_style_constants.h
index f8d6919..2fda3cbc 100644
--- a/third_party/blink/renderer/core/style/computed_style_constants.h
+++ b/third_party/blink/renderer/core/style/computed_style_constants.h
@@ -282,9 +282,14 @@
 
 // https://drafts.csswg.org/css-counter-styles-3/#predefined-counters
 enum class EListStyleType : unsigned {
+  // https://drafts.csswg.org/css-counter-styles-3/#simple-symbolic
   kDisc,
   kCircle,
   kSquare,
+  kDisclosureOpen,
+  kDisclosureClosed,
+
+  // https://drafts.csswg.org/css-counter-styles-3/#simple-numeric
   kDecimal,
   kDecimalLeadingZero,
   kArabicIndic,
@@ -307,13 +312,18 @@
   kThai,
   kLowerRoman,
   kUpperRoman,
+
+  // https://drafts.csswg.org/css-counter-styles-3/#simple-alphabetic
   kLowerGreek,
   kLowerAlpha,
   kLowerLatin,
   kUpperAlpha,
   kUpperLatin,
+
+  // https://drafts.csswg.org/css-counter-styles-3/#simple-fixed
   kCjkEarthlyBranch,
   kCjkHeavenlyStem,
+
   kEthiopicHalehame,
   kEthiopicHalehameAm,
   kEthiopicHalehameTiEr,
diff --git a/third_party/blink/renderer/core/testing/data/prerender/multiple_prerenders.html b/third_party/blink/renderer/core/testing/data/prerender/multiple_prerenders.html
index faa7084..088169a 100644
--- a/third_party/blink/renderer/core/testing/data/prerender/multiple_prerenders.html
+++ b/third_party/blink/renderer/core/testing/data/prerender/multiple_prerenders.html
@@ -1,20 +1,6 @@
 <html>
-  <head>
-    <script>
-      function log(message)
-      {
-          var item = document.createElement("li");
-          item.appendChild(document.createTextNode(message));
-          document.getElementById("console").appendChild(item);
-      }
-
-    </script>
-
-  </head>
+  <head></head>
   <body>
-    <ul id=console>
-    </ul>
-
     <link id="firstPrerender" rel=prerender href="http://first-prerender.com/"/>
     <link id="secondPrerender" rel=prerender href="http://second-prerender.com/"/>
 
@@ -42,26 +28,11 @@
           link.parentElement.removeChild(link);
       }
 
-      firstPrerender.addEventListener('webkitprerenderstart', function() { log("first_webkitprerenderstart"); }, false);
-      firstPrerender.addEventListener('webkitprerenderstop', function() { log("first_webkitprerenderstop"); }, false);
-      firstPrerender.addEventListener('webkitprerenderload', function() { log("first_webkitprerenderload"); }, false);
-      firstPrerender.addEventListener('webkitprerenderdomcontentloaded', function() { log("first_webkitprerenderdomcontentloaded"); }, false);
-
-      secondPrerender.addEventListener('webkitprerenderstart', function() { log("second_webkitprerenderstart"); }, false);
-      secondPrerender.addEventListener('webkitprerenderstop', function() { log("second_webkitprerenderstop"); }, false);
-      secondPrerender.addEventListener('webkitprerenderload', function() { log("second_webkitprerenderload"); }, false);
-      secondPrerender.addEventListener('webkitprerenderdomcontentloaded', function() { log("second_webkitprerenderdomcontentloaded"); }, false);
-
       function addThirdPrerender()
       {
           var emptyParagraph = document.getElementById("emptyParagraph");
           emptyParagraph.innerHTML = '<link id="thirdPrerender" rel=prerender href="http://third-prererender.com/"/>';
           var thirdPrerender = document.getElementById('thirdPrerender');
-
-          thirdPrerender.addEventListener('webkitprerenderstart', function() { log("third_webkitprerenderstart"); }, false);
-          thirdPrerender.addEventListener('webkitprerenderstop', function() { log("third_webkitprerenderstop"); }, false);
-          thirdPrerender.addEventListener('webkitprerenderload', function() { log("third_webkitprerenderload"); }, false);
-          thirdPrerender.addEventListener('webkitprerenderdomcontentloaded', function() { log("third_webkitprerenderdomcontentloaded"); }, false);
       }
     </script>
   </body>
diff --git a/third_party/blink/renderer/core/testing/data/prerender/single_prerender.html b/third_party/blink/renderer/core/testing/data/prerender/single_prerender.html
index 00d42c0..df50011 100644
--- a/third_party/blink/renderer/core/testing/data/prerender/single_prerender.html
+++ b/third_party/blink/renderer/core/testing/data/prerender/single_prerender.html
@@ -1,18 +1,6 @@
 <html>
-  <head>
-    <script>
-      function log(message)
-      {
-          var item = document.createElement("li");
-          item.appendChild(document.createTextNode(message));
-          document.getElementById("console").appendChild(item);
-      }
-    </script>
-  </head>
+  <head></head>
   <body>
-    <ul id=console>
-    </ul>
-
     <link id="theprerender" rel=prerender href="http://prerender.com/"/>
 
     <script>
@@ -35,11 +23,6 @@
           var link = document.getElementById('theprerender');
           link.rel = "something-else";
       }
-
-      prerender.addEventListener('webkitprerenderstart', function() { log("webkitprerenderstart"); }, false);
-      prerender.addEventListener('webkitprerenderstop', function() { log("webkitprerenderstop"); }, false);
-      prerender.addEventListener('webkitprerenderload', function() { log("webkitprerenderload"); }, false);
-      prerender.addEventListener('webkitprerenderdomcontentloaded', function() { log("webkitprerenderdomcontentloaded"); }, false);
     </script>
   </body>
 </html>
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 f4c8ab4..8bae393b 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -92,6 +92,7 @@
 namespace blink {
 
 constexpr uint32_t ResourceFetcher::kKeepaliveInflightBytesQuota;
+constexpr int kDefaultTimeToLiveWhileInBackForwardCacheInSeconds = 15;
 
 namespace {
 
@@ -618,6 +619,11 @@
   InstanceCounters::IncrementCounter(InstanceCounters::kResourceFetcherCounter);
   if (IsMainThread())
     MainThreadFetchersSet().insert(this);
+
+  back_forward_cache_timeout_ =
+      base::TimeDelta::FromSeconds(base::GetFieldTrialParamByFeatureAsInt(
+          blink::features::kLoadingTasksUnfreezable, "max_time_to_live",
+          kDefaultTimeToLiveWhileInBackForwardCacheInSeconds));
 }
 
 ResourceFetcher::~ResourceFetcher() {
@@ -2094,6 +2100,36 @@
     loader->SetDefersLoading(defers);
   for (const auto& loader : loaders_)
     loader->SetDefersLoading(defers);
+  if (defers == WebURLLoader::DeferType::kDeferredWithBackForwardCache &&
+      !back_forward_cache_eviction_timer_.IsRunning()) {
+    back_forward_cache_eviction_timer_.SetTaskRunner(unfreezable_task_runner_);
+    back_forward_cache_eviction_timer_.Start(
+        FROM_HERE, back_forward_cache_timeout_,
+        base::BindOnce(&ResourceFetcher::OnBackForwardCacheEvictionTimerFired,
+                       weak_ptr_factory_.GetWeakPtr()));
+  } else if (defers != WebURLLoader::DeferType::kDeferredWithBackForwardCache) {
+    // The page associated with this ResourceFetcher is no longer in the
+    // back-forward cache, so stop the back-forward cache eviction timer if it's
+    // currently running.
+    if (back_forward_cache_eviction_timer_.IsRunning())
+      back_forward_cache_eviction_timer_.Stop();
+  }
+}
+
+void ResourceFetcher::OnBackForwardCacheEvictionTimerFired() {
+  // If all the loaders are keepalive, we don't need to evict.
+  bool all_loaders_are_keepalive = true;
+  for (const auto& loader : loaders_) {
+    all_loaders_are_keepalive &= loader->ShouldBeKeptAliveWhenDetached();
+  }
+  for (const auto& loader : non_blocking_loaders_) {
+    all_loaders_are_keepalive &= loader->ShouldBeKeptAliveWhenDetached();
+  }
+  if (all_loaders_are_keepalive)
+    return;
+
+  StopFetching();
+  EvictFromBackForwardCache();
 }
 
 void ResourceFetcher::UpdateAllImageResourcePriorities() {
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 793721fd..9fdcad9 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
@@ -415,6 +415,8 @@
 
   void WarnUnusedPreloads();
 
+  void OnBackForwardCacheEvictionTimerFired();
+
   Member<DetachableResourceFetcherProperties> properties_;
   Member<ResourceLoadObserver> resource_load_observer_;
   Member<FetchContext> context_;
@@ -468,6 +470,9 @@
 
   HeapHashSet<Member<SubresourceWebBundle>> subresource_web_bundles_;
 
+  base::OneShotTimer back_forward_cache_eviction_timer_;
+  base::TimeDelta back_forward_cache_timeout_;
+
   // This is not in the bit field below because we want to use AutoReset.
   bool is_in_request_resource_ = false;
 
@@ -482,6 +487,9 @@
 
   static constexpr uint32_t kKeepaliveInflightBytesQuota = 64 * 1024;
 
+  // NOTE: This must be the last member.
+  base::WeakPtrFactory<ResourceFetcher> weak_ptr_factory_{this};
+
   DISALLOW_COPY_AND_ASSIGN(ResourceFetcher);
 };
 
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 26a855be..33d1f48 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1752,6 +1752,10 @@
       status: "test",
     },
     {
+      name: "ScreenFold",
+      status: "experimental",
+    },
+    {
       name: "ScreenWakeLock",
       status: "stable",
     },
diff --git a/third_party/blink/renderer/platform/widget/widget_base.cc b/third_party/blink/renderer/platform/widget/widget_base.cc
index 8af3dda..1f2e1654 100644
--- a/third_party/blink/renderer/platform/widget/widget_base.cc
+++ b/third_party/blink/renderer/platform/widget/widget_base.cc
@@ -854,6 +854,8 @@
   ui::mojom::VirtualKeyboardVisibilityRequest last_vk_visibility_request =
       ui::mojom::VirtualKeyboardVisibilityRequest::NONE;
   bool always_hide_ime = false;
+  base::Optional<gfx::Rect> control_bounds;
+  base::Optional<gfx::Rect> selection_bounds;
   if (frame_widget) {
     new_info = frame_widget->TextInputInfo();
     // This will be used to decide whether or not to show VK when VK policy is
@@ -864,6 +866,8 @@
     // Check whether the keyboard should always be hidden for the currently
     // focused element.
     always_hide_ime = frame_widget->ShouldSuppressKeyboardForFocusedElement();
+    frame_widget->GetEditContextBoundsInWindow(&control_bounds,
+                                               &selection_bounds);
   }
   const ui::TextInputMode new_mode =
       ConvertWebTextInputMode(new_info.input_mode);
@@ -880,7 +884,9 @@
       always_hide_ime_ != always_hide_ime || vk_policy_ != new_vk_policy ||
       (new_vk_policy == ui::mojom::VirtualKeyboardPolicy::MANUAL &&
        (last_vk_visibility_request !=
-        ui::mojom::VirtualKeyboardVisibilityRequest::NONE))) {
+        ui::mojom::VirtualKeyboardVisibilityRequest::NONE)) ||
+      (control_bounds && frame_control_bounds_ != control_bounds) ||
+      (selection_bounds && frame_selection_bounds_ != selection_bounds)) {
     ui::mojom::blink::TextInputStatePtr params =
         ui::mojom::blink::TextInputState::New();
     params->type = new_type;
@@ -889,15 +895,13 @@
     params->flags = new_info.flags;
     params->vk_policy = new_vk_policy;
     params->last_vk_visibility_request = last_vk_visibility_request;
+    params->edit_context_control_bounds = control_bounds;
+    params->edit_context_selection_bounds = selection_bounds;
+
     if (!new_info.ime_text_spans.empty()) {
       params->ime_text_spans_info =
           frame_widget->GetImeTextSpansInfo(new_info.ime_text_spans);
     }
-    if (frame_widget) {
-      frame_widget->GetEditContextBoundsInWindow(
-          &params->edit_context_control_bounds,
-          &params->edit_context_selection_bounds);
-    }
 #if defined(OS_ANDROID)
     if (next_previous_flags_ == kInvalidNextPreviousFlagsValue) {
       // Due to a focus change, values will be reset by the frame.
@@ -939,6 +943,10 @@
     can_compose_inline_ = new_can_compose_inline;
     always_hide_ime_ = always_hide_ime;
     text_input_flags_ = new_info.flags;
+    frame_control_bounds_ = control_bounds.value_or(gfx::Rect());
+    // Selection bounds are not populated in non-EditContext scenarios.
+    // It is communicated to IMEs via |WidgetBase::UpdateSelectionBounds|.
+    frame_selection_bounds_ = selection_bounds.value_or(gfx::Rect());
     // Reset the show/hide state in the InputMethodController.
     if (frame_widget) {
       if (last_vk_visibility_request !=
diff --git a/third_party/blink/renderer/platform/widget/widget_base.h b/third_party/blink/renderer/platform/widget/widget_base.h
index 9774ec4..836d29d 100644
--- a/third_party/blink/renderer/platform/widget/widget_base.h
+++ b/third_party/blink/renderer/platform/widget/widget_base.h
@@ -405,6 +405,13 @@
   ui::mojom::VirtualKeyboardPolicy vk_policy_ =
       ui::mojom::VirtualKeyboardPolicy::AUTO;
 
+  // Stores the current control and selection bounds of |webwidget_|
+  // that are used to position the candidate window during IME composition.
+  // These are stored in DIPs if use-zoom-for-dsf is disabled and are relative
+  // to the widget
+  gfx::Rect frame_control_bounds_;
+  gfx::Rect frame_selection_bounds_;
+
   // Stores the current text input flags of |webwidget_|.
   int text_input_flags_ = 0;
 
diff --git a/third_party/blink/renderer/platform/wtf/text/character_names.h b/third_party/blink/renderer/platform/wtf/text/character_names.h
index 8868cd56..71cda3a 100644
--- a/third_party/blink/renderer/platform/wtf/text/character_names.h
+++ b/third_party/blink/renderer/platform/wtf/text/character_names.h
@@ -44,6 +44,8 @@
 const UChar32 kArabicMathematicalOperatorMeemWithHahWithTatweel = 0x1EEF0;
 const UChar32 kArabicMathematicalOperatorHahWithDal = 0x1EEF1;
 const UChar kBlackCircleCharacter = 0x25CF;
+const UChar kBlackDownPointingSmallTriangle = 0x25BE;
+const UChar kBlackRightPointingSmallTriangle = 0x25B8;
 const UChar kBlackSquareCharacter = 0x25A0;
 const UChar kBlackUpPointingTriangleCharacter = 0x25B2;
 const UChar kBulletCharacter = 0x2022;
@@ -200,6 +202,8 @@
 using WTF::unicode::kArabicMathematicalOperatorHahWithDal;
 using WTF::unicode::kArabicMathematicalOperatorMeemWithHahWithTatweel;
 using WTF::unicode::kBlackCircleCharacter;
+using WTF::unicode::kBlackDownPointingSmallTriangle;
+using WTF::unicode::kBlackRightPointingSmallTriangle;
 using WTF::unicode::kBlackSquareCharacter;
 using WTF::unicode::kBlackUpPointingTriangleCharacter;
 using WTF::unicode::kBulletCharacter;
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index 8d9bad2..916346ea 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -2038,8 +2038,6 @@
 crbug.com/626703 [ Mac ] external/wpt/payment-method-basic-card/billing-address-is-null-manual.https.html [ Skip ]
 crbug.com/626703 [ Win ] external/wpt/payment-method-basic-card/billing-address-is-null-manual.https.html [ Skip ]
 
-crbug.com/626703 [ Win7 ] external/wpt/pointerevents/pointerevent_fractional_coordinates-manual.html [ Skip ]
-
 crbug.com/626703 [ Linux ] external/wpt/payment-request/dynamically-change-shipping-options-manual.https.html [ Skip ]
 crbug.com/626703 [ Mac ] external/wpt/payment-request/dynamically-change-shipping-options-manual.https.html [ Skip ]
 crbug.com/626703 [ Win ] external/wpt/payment-request/dynamically-change-shipping-options-manual.https.html [ Skip ]
@@ -2187,8 +2185,8 @@
 # These tests require a physical device connected.
 external/wpt/webusb/usbDevice_claimInterface-manual.https.html [ Skip ]
 wpt_internal/hid/hidDevice_collections-manual.https.html [ Skip ]
-wpt_internal/serial/serialPort_loopback-manual.https.html [ Skip ]
-wpt_internal/serial/serialPort_disconnect-manual.https.html [ Skip ]
+external/wpt/serial/serialPort_loopback-manual.https.html [ Skip ]
+external/wpt/serial/serialPort_disconnect-manual.https.html [ Skip ]
 
 # CPU test is enough for this one as there are gradient issues on the GPU
 virtual/gpu/fast/canvas/conic-gradient.html [ Skip ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index d45d69b..b3b35de 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -5814,38 +5814,6 @@
 crbug.com/1057060 virtual/scroll-unification/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Pass Failure Timeout ]
 crbug.com/1045599 fast/css-grid-layout/flex-content-sized-columns-resize.html [ Pass Failure Timeout ]
 
-# TODO(michaelludwig) - Remove after Skia roll and rebaseline
-crbug.com/1143929 compositing/reflections/animation-inside-reflection.html [ Pass Failure ]
-crbug.com/1143929 compositing/reflections/nested-reflection-transformed.html [ Pass Failure ]
-crbug.com/1143929 compositing/reflections/nested-reflection-transformed2.html [ Pass Failure ]
-crbug.com/1143929 compositing/reflections/reflection-in-composited.html [ Pass Failure ]
-crbug.com/1143929 css3/filters/effect-combined-hw.html [ Pass Failure ]
-crbug.com/1143929 css3/filters/effect-combined.html [ Pass Failure ]
-crbug.com/1143929 css3/filters/regions-expanding.html [ Pass Failure ]
-crbug.com/1143929 fast/css/background-clip-radius-values.html [ Pass Failure ]
-crbug.com/1143929 fast/css/transformed-mask.html [ Pass Failure ]
-crbug.com/1143929 fast/reflections/opacity-reflection-transform.html [ Pass Failure ]
-crbug.com/1143929 images/color-profile-image-filter-all.html [ Pass Failure ]
-crbug.com/1143929 paint/invalidation/reflection/reflection-with-rotation.html [ Pass Failure ]
-crbug.com/1143929 svg/W3C-SVG-1.1/filters-blend-01-b.svg [ Pass Failure ]
-crbug.com/1143929 svg/W3C-SVG-1.1/filters-example-01-b.svg [ Pass Failure ]
-crbug.com/1143929 svg/W3C-SVG-1.1/filters-morph-01-f.svg [ Pass Failure ]
-crbug.com/1143929 svg/W3C-SVG-1.1/filters-offset-01-b.svg [ Pass Failure ]
-crbug.com/1143929 svg/W3C-SVG-1.1/filters-turb-02-f.svg [ Pass Failure ]
-crbug.com/1143929 svg/batik/filters/feTile.svg [ Pass Failure ]
-crbug.com/1143929 svg/batik/text/smallFonts.svg [ Pass Failure ]
-crbug.com/1143929 svg/batik/text/textFeatures.svg [ Pass Failure ]
-crbug.com/1143929 svg/custom/grayscale-gradient-mask-2.svg [ Pass Failure ]
-crbug.com/1143929 svg/dynamic-updates/SVGFEBlendElement-dom-in-attr.html [ Pass Failure ]
-crbug.com/1143929 svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr.html [ Pass Failure ]
-crbug.com/1143929 svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr.html [ Pass Failure ]
-crbug.com/1143929 svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop.html [ Pass Failure ]
-crbug.com/1143929 svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop.html [ Pass Failure ]
-crbug.com/1143929 svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop.html [ Pass Failure ]
-crbug.com/1143929 svg/dynamic-updates/SVGFECompositeElement-dom-in-attr.html [ Pass Failure ]
-crbug.com/1143929 svg/dynamic-updates/SVGFECompositeElement-svgdom-in-prop.html [ Pass Failure ]
-crbug.com/1143929 svg/transforms/text-with-mask-with-svg-transform.svg [ Pass Failure ]
-
 # Sheriff 2020-09-29
 crbug.com/1133342 external/wpt/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html [ Pass Failure Timeout ]
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-computed-expected.txt
index 24d8b1a6..5e8dad6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-computed-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-computed-expected.txt
@@ -3,6 +3,8 @@
 PASS Property list-style-type value 'disc'
 PASS Property list-style-type value 'circle'
 PASS Property list-style-type value 'square'
+PASS Property list-style-type value 'disclosure-open'
+PASS Property list-style-type value 'disclosure-closed'
 PASS Property list-style-type value 'decimal'
 PASS Property list-style-type value 'decimal-leading-zero'
 PASS Property list-style-type value 'lower-roman'
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-computed.html b/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-computed.html
index 21230f3..1f25e520 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-computed.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-computed.html
@@ -17,6 +17,8 @@
 test_computed_value('list-style-type', 'disc');
 test_computed_value('list-style-type', 'circle');
 test_computed_value('list-style-type', 'square');
+test_computed_value('list-style-type', 'disclosure-open');
+test_computed_value('list-style-type', 'disclosure-closed');
 test_computed_value('list-style-type', 'decimal');
 test_computed_value('list-style-type', 'decimal-leading-zero');
 test_computed_value('list-style-type', 'lower-roman');
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-valid-expected.txt
index 59eca290..9eced25 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-valid-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-valid-expected.txt
@@ -3,6 +3,8 @@
 PASS e.style['list-style-type'] = "disc" should set the property value
 PASS e.style['list-style-type'] = "circle" should set the property value
 PASS e.style['list-style-type'] = "square" should set the property value
+PASS e.style['list-style-type'] = "disclosure-open" should set the property value
+PASS e.style['list-style-type'] = "disclosure-closed" should set the property value
 PASS e.style['list-style-type'] = "decimal" should set the property value
 PASS e.style['list-style-type'] = "decimal-leading-zero" should set the property value
 PASS e.style['list-style-type'] = "lower-roman" should set the property value
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-valid.html b/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-valid.html
index 66067ca4..dde0bee8 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-type-valid.html
@@ -17,6 +17,8 @@
 test_valid_value('list-style-type', 'disc');
 test_valid_value('list-style-type', 'circle');
 test_valid_value('list-style-type', 'square');
+test_valid_value('list-style-type', 'disclosure-open');
+test_valid_value('list-style-type', 'disclosure-closed');
 test_valid_value('list-style-type', 'decimal');
 test_valid_value('list-style-type', 'decimal-leading-zero');
 test_valid_value('list-style-type', 'lower-roman');
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/serialize-values-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom/serialize-values-expected.txt
index 1ae8263..f9c57d1a 100644
--- a/third_party/blink/web_tests/external/wpt/css/cssom/serialize-values-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/serialize-values-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 678 tests; 677 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 680 tests; 679 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS background-attachment: scroll
 PASS background-attachment: fixed
 PASS background-attachment: inherit
@@ -451,6 +451,8 @@
 PASS list-style-type: disc
 PASS list-style-type: circle
 PASS list-style-type: square
+PASS list-style-type: disclosure-open
+PASS list-style-type: disclosure-closed
 PASS list-style-type: decimal
 PASS list-style-type: decimal-leading-zero
 PASS list-style-type: lower-roman
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/serialize-values.html b/third_party/blink/web_tests/external/wpt/css/cssom/serialize-values.html
index 7334424..31f5f64 100644
--- a/third_party/blink/web_tests/external/wpt/css/cssom/serialize-values.html
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/serialize-values.html
@@ -433,7 +433,8 @@
         'initial': 'outside',
       }],
       ['list-style-type', {
-        'values': ['disc', 'circle', 'square', 'decimal', 'decimal-leading-zero', 'lower-roman',
+        'values': ['disc', 'circle', 'square', 'disclosure-open', 'disclosure-closed',
+                   'decimal', 'decimal-leading-zero', 'lower-roman',
                    'upper-roman', 'lower-greek', 'lower-latin', 'upper-latin', 'armenian', 'georgian',
                    'lower-alpha', 'upper-alpha', 'none', 'inherit'],
         'initial': 'disc',
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-004-manual.html b/third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-004.html
similarity index 89%
rename from third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-004-manual.html
rename to third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-004.html
index 4d7878e..1c3fb3fc 100644
--- a/third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-004-manual.html
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-004.html
@@ -7,6 +7,9 @@
   <link rel="help" href="https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo" />
   <script src="/resources/testharness.js"></script>
   <script src="/resources/testharnessreport.js"></script>
+  <script src="/resources/testdriver.js"></script>
+  <script src="/resources/testdriver-actions.js"></script>
+  <script src="/resources/testdriver-vendor.js"></script>
   <style>
     :focus-visible {
       outline: red dotted 1px; /* fallback for Edge */
@@ -40,7 +43,7 @@
     <button data-tested="false" id="el-4">Focus me</span>
   </div>
   <div>
-    <input data-tested="false" id="el-5" type="button" value="Focus me"</input>
+    <input data-tested="false" id="el-5" type="button" value="Focus me"></input>
   </div>
   <div>
     <input data-tested="false" id="el-6" type="image" alt="Focus me."></input>
@@ -71,6 +74,11 @@
     <label><input data-tested="false" id="el-11" type="color"></input> Focus me.</label>
   </div>
   <script>
+    function mouseClickInTarget(selector) {
+       let target = document.querySelector(selector);
+       return test_driver.click(target);
+    }
+
     async_test(function(t) {
         document.querySelectorAll("[data-tested]").forEach((el) => {
             el.addEventListener("click", t.step_func((e) => {
@@ -84,6 +92,8 @@
                 }
             }));
         });
+
+        mouseClickInTarget("[data-tested=false]");
     }, "Mouse focus on input elements which do not show a virtual keyboard should NOT match :focus-visible - not affected by -webkit-appearance");
   </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_capture_suppressing_mouse-manual.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_capture_suppressing_mouse.html
similarity index 89%
rename from third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_capture_suppressing_mouse-manual.html
rename to third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_capture_suppressing_mouse.html
index 127b07a..080ca15 100644
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_capture_suppressing_mouse-manual.html
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_capture_suppressing_mouse.html
@@ -6,6 +6,9 @@
         <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
+        <script src="/resources/testdriver.js"></script>
+        <script src="/resources/testdriver-actions.js"></script>
+        <script src="/resources/testdriver-vendor.js"></script>
         <!-- Additional helper script for common checks across event types -->
         <script type="text/javascript" src="pointerevent_support.js"></script>
     </head>
@@ -53,6 +56,7 @@
             var test_lostpointercapture = async_test("lostpointercapture event received");
 
             var test_pointerover_no_capture = async_test("pointerover event without capture received");
+
             var test_pointerover_capture = async_test("pointerover event with capture received");
 
             var test_pointerout_no_capture = async_test("pointerout event without capture received");
@@ -64,6 +68,8 @@
             var test_pointerleave_no_capture = async_test("pointerleave event without capture received");
             var test_pointerleave_after_capture = async_test("pointerleave event after lostpointercapture received");
 
+            var actions_promise;
+
             window.onload = function() {
                 on_event(captureButton, 'pointerdown', function(e) {
                     if(isPointerCapture == false) {
@@ -147,7 +153,10 @@
                     }
                     else {
                         if (lostPointerCaptureReceived) {
-                            test_pointerleave_after_capture.done();
+                            // Make sure the test finishes after all the input actions are completed.
+                            actions_promise.then( () => {
+                                test_pointerleave_after_capture.done();
+                            });
                         } else {
                             test_pointerleave_no_capture.done();
                         }
@@ -190,6 +199,20 @@
                         }, "pointerleave shouldn't trigger for the purple rectangle while the black rectangle has capture");
                     }
                 });
+
+                actions_promise = new test_driver.Actions()
+                    .pointerMove(0, 0, {origin: target0})
+                    .pointerMove(0, 0, {origin: target1})
+                    .pointerMove(0, 0, {origin: btnCapture})
+                    .pointerDown()
+                    .pointerMove(0, 0, {origin: btnCapture})
+                    .pointerMove(10, 0, {origin: btnCapture})
+                    .pointerMove(0, 0, {origin: target1})
+                    .pointerMove(0, 0, {origin: target0})
+                    .pointerMove(0, 0, {origin: target1})
+                    .pointerUp()
+                    .pointerMove(0, 0, {origin: target1})
+                    .send();
             }
         </script>
         <h1>Pointer Events Capture Test</h1>
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_fractional_coordinates-manual.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_fractional_coordinates.html
similarity index 66%
rename from third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_fractional_coordinates-manual.html
rename to third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_fractional_coordinates.html
index e0e2fdcd..b106340 100644
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_fractional_coordinates-manual.html
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_fractional_coordinates.html
@@ -6,6 +6,9 @@
         <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
+        <script src="/resources/testdriver.js"></script>
+        <script src="/resources/testdriver-actions.js"></script>
+        <script src="/resources/testdriver-vendor.js"></script>
         <script type="text/javascript" src="pointerevent_support.js"></script>
         <style>
             #innerFrame {
@@ -43,6 +46,48 @@
                 eventsRecieved[event.type] = true;
             }
 
+            function testInputType(inputSource) {
+              const scale = 5;
+              const width = 3;
+              const height = 3;
+              var targetFrame = document.querySelector('#innerFrame');
+              var frameRect = targetFrame.getBoundingClientRect();
+              frameLeft = frameRect.left;
+              frameTop = frameRect.top;
+
+              target = [{x: 10, y: 10}, {x: 30, y: 50}, {x: 50, y: 30}]
+              xPosition = []
+              yPosition = []
+              for (var i = 0; i < target.length; i++) {
+                xPosition.push((target[i].x + width / 2.0) * scale + frameLeft);
+                yPosition.push((target[i].y + height / 2.0) * scale + frameTop);
+              }
+              return sendInputAt(inputSource, xPosition[0], yPosition[0]).then(function() {
+                return sendInputAt(inputSource, xPosition[1], yPosition[1]);
+              }).then(function() {
+                return sendInputAt(inputSource, xPosition[2], yPosition[2]);
+              });
+
+            }
+
+            function sendInputAt(inputSource, xPosition, yPosition) {
+              if (inputSource == "touch") {
+                return new test_driver.Actions()
+                  .addPointer("touchPointer1", "touch")
+                  .pointerMove(Math.ceil(xPosition), Math.ceil(yPosition))
+                  .pointerDown()
+                  .pointerMove(Math.ceil(xPosition + 1), Math.ceil(yPosition + 1))
+                  .pointerUp()
+                  .send();
+              } else {
+                return new test_driver.Actions()
+                  .pointerMove(Math.ceil(xPosition), Math.ceil(yPosition))
+                  .pointerDown()
+                  .pointerUp()
+                  .send();
+              }
+            }
+
             function run() {
                 var test_pointerEvent = setup_pointerevent_test("pointerevent events in capturing", ALL_POINTERS);
                 var innerFrame = document.getElementById('innerFrame');
@@ -70,6 +115,12 @@
                       }
                     });
                 });
+
+                testInputType("mouse").then(function() {
+                    return testInputType("touch");
+                }).then(function() {
+                    return testInputType("pen");
+                });
             }
         </script>
     </head>
diff --git a/third_party/blink/web_tests/wpt_internal/serial/resources/common.js b/third_party/blink/web_tests/external/wpt/serial/resources/common.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/serial/resources/common.js
rename to third_party/blink/web_tests/external/wpt/serial/resources/common.js
diff --git a/third_party/blink/web_tests/wpt_internal/serial/resources/manual.js b/third_party/blink/web_tests/external/wpt/serial/resources/manual.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/serial/resources/manual.js
rename to third_party/blink/web_tests/external/wpt/serial/resources/manual.js
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_disconnect-manual.https.html b/third_party/blink/web_tests/external/wpt/serial/serialPort_disconnect-manual.https.html
similarity index 96%
rename from third_party/blink/web_tests/wpt_internal/serial/serialPort_disconnect-manual.https.html
rename to third_party/blink/web_tests/external/wpt/serial/serialPort_disconnect-manual.https.html
index a6b1b1c5..3a2e134 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_disconnect-manual.https.html
+++ b/third_party/blink/web_tests/external/wpt/serial/serialPort_disconnect-manual.https.html
@@ -40,7 +40,7 @@
         assert_equals(port.readable, null);
 
         let event = await disconnectPromise;
-        assert_equals(event.port, port);
+        assert_equals(event.target, port);
 
         disconnectMessage.remove();
 
@@ -72,7 +72,7 @@
         assert_equals(port.writable, null);
 
         let event = await disconnectPromise;
-        assert_equals(event.port, port);
+        assert_equals(event.target, port);
 
         disconnectMessage.remove();
 
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_loopback-manual.https.html b/third_party/blink/web_tests/external/wpt/serial/serialPort_loopback-manual.https.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/serial/serialPort_loopback-manual.https.html
rename to third_party/blink/web_tests/external/wpt/serial/serialPort_loopback-manual.https.html
diff --git a/third_party/blink/web_tests/external/wpt_automation/css/selectors/focus-visible-004-manual-automation.js b/third_party/blink/web_tests/external/wpt_automation/css/selectors/focus-visible-004-manual-automation.js
deleted file mode 100644
index 36cd490..0000000
--- a/third_party/blink/web_tests/external/wpt_automation/css/selectors/focus-visible-004-manual-automation.js
+++ /dev/null
@@ -1,5 +0,0 @@
-importAutomationScript('/pointerevents/pointerevent_common_input.js');
-
-function inject_input() {
-  return mouseClickInTarget("[data-tested=false]");
-};
diff --git a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_capture_suppressing_mouse-manual-automation.js b/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_capture_suppressing_mouse-manual-automation.js
deleted file mode 100644
index ad1a2e9..0000000
--- a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_capture_suppressing_mouse-manual-automation.js
+++ /dev/null
@@ -1,12 +0,0 @@
-importAutomationScript('/pointerevents/pointerevent_common_input.js');
-
-function inject_input() {
-  return mouseMoveIntoTarget('#target0').then(function() {
-    return mouseMoveIntoTarget('#target1');
-  }).then(function() {
-    return mouseDragInTargets(['#btnCapture', '#btnCapture', '#target1', '#target0', '#target1']);
-  }).then(function() {
-    return mouseMoveIntoTarget('#target1');
-  });
-}
-
diff --git a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_fractional_coordinates-manual-automation.js b/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_fractional_coordinates-manual-automation.js
deleted file mode 100644
index 367733c..0000000
--- a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_fractional_coordinates-manual-automation.js
+++ /dev/null
@@ -1,58 +0,0 @@
-importAutomationScript('/pointerevents/pointerevent_common_input.js');
-const scale = 5;
-const width = 3;
-const height = 3;
-function inject_input() {
-  return testInputType("mouse").then(function() {
-    return testInputType("touch");
-  }).then(function() {
-    return testInputType("pen");
-  });
-}
-
-function testInputType(inputSource) {
-  var targetFrame = document.querySelector('#innerFrame');
-  var frameRect = targetFrame.getBoundingClientRect();
-  frameLeft = frameRect.left;
-  frameTop = frameRect.top;
-
-  target = [{x: 10, y: 10}, {x: 30, y: 50}, {x: 50, y: 30}]
-  xPosition = []
-  yPosition = []
-  for (var i = 0; i < target.length; i++) {
-    xPosition.push((target[i].x + width / 2.0) * scale + frameLeft);
-    yPosition.push((target[i].y + height / 2.0) * scale + frameTop);
-  }
-  return sendInputAt(inputSource, xPosition[0], yPosition[0]).then(function() {
-    return sendInputAt(inputSource, xPosition[1], yPosition[1]);
-  }).then(function() {
-    return sendInputAt(inputSource, xPosition[2], yPosition[2]);
-  });
-
-}
-
-function sendInputAt(inputSource, xPosition, yPosition) {
-  if (inputSource == "touch") {
-    pointerActions = [{name: 'pointerDown', x: xPosition, y: yPosition},
-                      {name: 'pointerMove', x: xPosition + 1, y: yPosition + 1},
-                      {name: 'pointerUp'}]
-  }
-  else {
-    pointerActions = [{name: 'pointerMove', x: xPosition, y: yPosition},
-                      {name: 'pointerDown', x: xPosition, y: yPosition},
-                      {name: 'pointerUp'}]
-  }
-
-  return new Promise(function(resolve, reject) {
-    if (window.chrome && chrome.gpuBenchmarking) {
-      chrome.gpuBenchmarking.pointerActionSequence(
-          [{
-            source: inputSource,
-            actions: pointerActions
-          }],
-          resolve);
-    } else {
-      reject();
-    }
-  });
-}
diff --git a/third_party/blink/web_tests/fast/lists/ol-display-types.html b/third_party/blink/web_tests/fast/lists/ol-display-types.html
index 1c3eea1..b63d873 100644
--- a/third_party/blink/web_tests/fast/lists/ol-display-types.html
+++ b/third_party/blink/web_tests/fast/lists/ol-display-types.html
@@ -23,6 +23,8 @@
 <li>Should be 14</li>
 <li style="list-style-type: circle;">Should have a circle</li>
 <li>Should be 16</li>
+<li style="list-style-type: disclosure-open;">Should have a triangle</li>
+<li style="list-style-type: disclosure-closed;">Should have another triangle</li>
 </ol>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/lists/ol-display-types-expected.png b/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/lists/ol-display-types-expected.png
index 5ccc42a..78b23d0 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/lists/ol-display-types-expected.png
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/lists/ol-display-types-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/lists/ol-display-types-expected.png b/third_party/blink/web_tests/platform/linux/fast/lists/ol-display-types-expected.png
index f3ea5f4..e7e2f810 100644
--- a/third_party/blink/web_tests/platform/linux/fast/lists/ol-display-types-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/lists/ol-display-types-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png b/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
index e77df3abf..0b296b3 100644
--- a/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/batik/text/smallFonts-expected.png b/third_party/blink/web_tests/platform/linux/svg/batik/text/smallFonts-expected.png
index 162685a2..e975d755 100644
--- a/third_party/blink/web_tests/platform/linux/svg/batik/text/smallFonts-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/batik/text/smallFonts-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/transforms/text-with-mask-with-svg-transform-expected.png b/third_party/blink/web_tests/platform/linux/svg/transforms/text-with-mask-with-svg-transform-expected.png
index 0a7bd0fb..d0995b6 100644
--- a/third_party/blink/web_tests/platform/linux/svg/transforms/text-with-mask-with-svg-transform-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/transforms/text-with-mask-with-svg-transform-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/fast/css/background-clip-radius-values-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/fast/css/background-clip-radius-values-expected.png
new file mode 100644
index 0000000..4ae04482
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/fast/css/background-clip-radius-values-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
new file mode 100644
index 0000000..a90bb4c
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/fast/css/background-clip-radius-values-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/fast/css/background-clip-radius-values-expected.png
new file mode 100644
index 0000000..4ae04482
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/synchronous_html_parser/fast/css/background-clip-radius-values-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/css/background-clip-radius-values-expected.png b/third_party/blink/web_tests/platform/mac/fast/css/background-clip-radius-values-expected.png
index 4ae04482..535ab74 100644
--- a/third_party/blink/web_tests/platform/mac/fast/css/background-clip-radius-values-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/css/background-clip-radius-values-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/lists/ol-display-types-expected.png b/third_party/blink/web_tests/platform/mac/fast/lists/ol-display-types-expected.png
index 8021f55..5c06b07 100644
--- a/third_party/blink/web_tests/platform/mac/fast/lists/ol-display-types-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/lists/ol-display-types-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png b/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
index a90bb4c..b8265557 100644
--- a/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/transforms/text-with-mask-with-svg-transform-expected.png b/third_party/blink/web_tests/platform/mac/svg/transforms/text-with-mask-with-svg-transform-expected.png
index 5150644c..97fa837 100644
--- a/third_party/blink/web_tests/platform/mac/svg/transforms/text-with-mask-with-svg-transform-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/transforms/text-with-mask-with-svg-transform-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/css/background-clip-radius-values-expected.png b/third_party/blink/web_tests/platform/win/fast/css/background-clip-radius-values-expected.png
index 6d12cb6b..fdb7e52 100644
--- a/third_party/blink/web_tests/platform/win/fast/css/background-clip-radius-values-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/css/background-clip-radius-values-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/lists/ol-display-types-expected.png b/third_party/blink/web_tests/platform/win/fast/lists/ol-display-types-expected.png
index 4d6eeed..63a4313 100644
--- a/third_party/blink/web_tests/platform/win/fast/lists/ol-display-types-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/lists/ol-display-types-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png b/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
index e27c388..463957d 100644
--- a/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/transforms/text-with-mask-with-svg-transform-expected.png b/third_party/blink/web_tests/platform/win/svg/transforms/text-with-mask-with-svg-transform-expected.png
index a1f3736..2449232e 100644
--- a/third_party/blink/web_tests/platform/win/svg/transforms/text-with-mask-with-svg-transform-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/transforms/text-with-mask-with-svg-transform-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/custom/grayscale-gradient-mask-2-expected.png b/third_party/blink/web_tests/svg/custom/grayscale-gradient-mask-2-expected.png
index e5e3c01c..491124b 100644
--- a/third_party/blink/web_tests/svg/custom/grayscale-gradient-mask-2-expected.png
+++ b/third_party/blink/web_tests/svg/custom/grayscale-gradient-mask-2-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_close.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_close.https.window.js
index 2c6d95a..766b8b2 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_close.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_close.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_events.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_events.https.window.js
index 710a2107..80acc69 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_events.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_events.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_getInfo.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_getInfo.https.window.js
index 97ddcb2d..d6a5264 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_getInfo.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_getInfo.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_getSignals.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_getSignals.https.window.js
index e7165bb..30494d3 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_getSignals.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_getSignals.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_ondisconnect.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_ondisconnect.https.window.js
index 1097300a..267ab53 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_ondisconnect.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_ondisconnect.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_open.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_open.https.window.js
index f9a92b77..498a11c 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_open.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_open.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_cancel.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_cancel.https.window.js
index d919b9c..6b2ca96 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_cancel.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_cancel.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_chain.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_chain.https.window.js
index d8bd73a..3f1b79d 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_chain.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_chain.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_closeLocked.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_closeLocked.https.window.js
index fa904e4..bc03091 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_closeLocked.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_closeLocked.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_disconnect.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_disconnect.https.window.js
index 681d35c..f5e111e 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_disconnect.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_disconnect.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_gc.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_gc.https.window.js
index c45a716..c986f62e 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_gc.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_gc.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_largeRead.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_largeRead.https.window.js
index b02b80b..f6721a0 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_largeRead.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_largeRead.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_open.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_open.https.window.js
index dc3e6cd..f6ee00f 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_open.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_open.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_parityError.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_parityError.https.window.js
index 5943c8b8..b078a3e 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_parityError.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_parityError.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 // ParityError is not (as of 2020/03/23) a valid DOMException, so cannot use
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_pipeThrough.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_pipeThrough.https.window.js
index fc2796d..bb48301 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_pipeThrough.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_pipeThrough.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_smallRead.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_smallRead.https.window.js
index f4da5617..0c0fb45 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_smallRead.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_readable_smallRead.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_setSignals.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_setSignals.https.window.js
index 417af5e0..fbc2c2ba 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_setSignals.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_setSignals.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serialPort_writable.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serialPort_writable.https.window.js
index 2433d66a..c5a3bdd 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serialPort_writable.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serialPort_writable.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serial_getPorts.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serial_getPorts.https.window.js
index 3d08bbfb..fe67e9e 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serial_getPorts.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serial_getPorts.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 promise_test(async () => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serial_onconnect.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serial_onconnect.https.window.js
index 7cca589..58d8534 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serial_onconnect.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serial_onconnect.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serial_ondisconnect.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serial_ondisconnect.https.window.js
index 3c78e80..57fb1e9 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serial_ondisconnect.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serial_ondisconnect.https.window.js
@@ -3,7 +3,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 serial_test(async (t, fake) => {
diff --git a/third_party/blink/web_tests/wpt_internal/serial/serial_requestPort.https.window.js b/third_party/blink/web_tests/wpt_internal/serial/serial_requestPort.https.window.js
index 99f95b1b..083a7352 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/serial_requestPort.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/serial/serial_requestPort.https.window.js
@@ -5,7 +5,7 @@
 // META: script=/gen/layout_test_data/mojo/public/js/mojo_bindings.js
 // META: script=/gen/mojo/public/mojom/base/unguessable_token.mojom.js
 // META: script=/gen/third_party/blink/public/mojom/serial/serial.mojom.js
-// META: script=resources/common.js
+// META: script=/serial/resources/common.js
 // META: script=resources/automation.js
 
 promise_test((t) => {
diff --git a/third_party/brotli/BUILD.gn b/third_party/brotli/BUILD.gn
index f2c816f..fb22ed45 100644
--- a/third_party/brotli/BUILD.gn
+++ b/third_party/brotli/BUILD.gn
@@ -22,10 +22,13 @@
 }
 
 common_sources = [
+  "common/constants.c",
   "common/constants.h",
+  "common/context.c",
   "common/context.h",
   "common/dictionary.c",
   "common/dictionary.h",
+  "common/platform.c",
   "common/platform.h",
   "common/transform.c",
   "common/transform.h",
@@ -57,63 +60,65 @@
 ]
 
 enc_sources = [
-  "enc/backward_references.c",
-  "enc/backward_references.h",
   "enc/backward_references_hq.c",
   "enc/backward_references_hq.h",
   "enc/backward_references_inc.h",
+  "enc/backward_references.c",
+  "enc/backward_references.h",
+  "enc/bit_cost_inc.h",
   "enc/bit_cost.c",
   "enc/bit_cost.h",
-  "enc/bit_cost_inc.h",
   "enc/block_encoder_inc.h",
+  "enc/block_splitter_inc.h",
   "enc/block_splitter.c",
   "enc/block_splitter.h",
-  "enc/block_splitter_inc.h",
   "enc/brotli_bit_stream.c",
   "enc/brotli_bit_stream.h",
+  "enc/cluster_inc.h",
   "enc/cluster.c",
   "enc/cluster.h",
-  "enc/cluster_inc.h",
+  "enc/command.c",
   "enc/command.h",
-  "enc/compress_fragment.c",
-  "enc/compress_fragment.h",
   "enc/compress_fragment_two_pass.c",
   "enc/compress_fragment_two_pass.h",
+  "enc/compress_fragment.c",
+  "enc/compress_fragment.h",
   "enc/dictionary_hash.c",
   "enc/dictionary_hash.h",
   "enc/encode.c",
   "enc/encoder_dict.c",
   "enc/encoder_dict.h",
+  "enc/entropy_encode_static.h",
   "enc/entropy_encode.c",
   "enc/entropy_encode.h",
-  "enc/entropy_encode_static.h",
+  "enc/fast_log.c",
   "enc/fast_log.h",
   "enc/find_match_length.h",
-  "enc/hash.h",
   "enc/hash_composite_inc.h",
   "enc/hash_forgetful_chain_inc.h",
-  "enc/hash_longest_match64_inc.h",
   "enc/hash_longest_match_inc.h",
   "enc/hash_longest_match_quickly_inc.h",
+  "enc/hash_longest_match64_inc.h",
   "enc/hash_rolling_inc.h",
   "enc/hash_to_binary_tree_inc.h",
+  "enc/hash.h",
+  "enc/histogram_inc.h",
   "enc/histogram.c",
   "enc/histogram.h",
-  "enc/histogram_inc.h",
   "enc/literal_cost.c",
   "enc/literal_cost.h",
   "enc/memory.c",
   "enc/memory.h",
+  "enc/metablock_inc.h",
   "enc/metablock.c",
   "enc/metablock.h",
-  "enc/metablock_inc.h",
   "enc/params.h",
   "enc/prefix.h",
   "enc/quality.h",
   "enc/ringbuffer.h",
+  "enc/static_dict_lut.h",
   "enc/static_dict.c",
   "enc/static_dict.h",
-  "enc/static_dict_lut.h",
   "enc/utf8_util.c",
   "enc/utf8_util.h",
   "enc/write_bits.h",
diff --git a/third_party/brotli/README.chromium b/third_party/brotli/README.chromium
index 599ea03..5ad69e8 100644
--- a/third_party/brotli/README.chromium
+++ b/third_party/brotli/README.chromium
@@ -1,6 +1,6 @@
 Name: Brotli
 URL: https://github.com/google/brotli
-Version: d6d98957ca8ccb1ef45922e978bb10efca0ea541
+Version: e61745a6b7add50d380cfd7d3883dd6c62fc2c71
 License: MIT
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/brotli/common/constants.c b/third_party/brotli/common/constants.c
new file mode 100644
index 0000000..6bad9f6
--- /dev/null
+++ b/third_party/brotli/common/constants.c
@@ -0,0 +1,15 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+   Distributed under MIT license.
+   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#include "./constants.h"
+
+const BrotliPrefixCodeRange
+    _kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
+        {1, 2},     {5, 2},     {9, 2},   {13, 2},    {17, 3},    {25, 3},
+        {33, 3},    {41, 3},    {49, 4},  {65, 4},    {81, 4},    {97, 4},
+        {113, 5},   {145, 5},   {177, 5}, {209, 5},   {241, 6},   {305, 6},
+        {369, 7},   {497, 8},   {753, 9}, {1265, 10}, {2289, 11}, {4337, 12},
+        {8433, 13}, {16625, 24}};
diff --git a/third_party/brotli/common/constants.h b/third_party/brotli/common/constants.h
index d1b88d12..e848195 100644
--- a/third_party/brotli/common/constants.h
+++ b/third_party/brotli/common/constants.h
@@ -4,9 +4,18 @@
    See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
 */
 
+/**
+ * @file
+ * Common constants used in decoder and encoder API.
+ */
+
 #ifndef BROTLI_COMMON_CONSTANTS_H_
 #define BROTLI_COMMON_CONSTANTS_H_
 
+#include "./platform.h"
+#include <brotli/port.h>
+#include <brotli/types.h>
+
 /* Specification: 7.3. Encoding of the context map */
 #define BROTLI_CONTEXT_MAP_MAX_RLE 16
 
@@ -29,12 +38,31 @@
 #define BROTLI_INITIAL_REPEATED_CODE_LENGTH 8
 
 /* "Large Window Brotli" */
+
+/**
+ * The theoretical maximum number of distance bits specified for large window
+ * brotli, for 64-bit encoders and decoders. Even when in practice 32-bit
+ * encoders and decoders only support up to 30 max distance bits, the value is
+ * set to 62 because it affects the large window brotli file format.
+ * Specifically, it affects the encoding of simple huffman tree for distances,
+ * see Specification RFC 7932 chapter 3.4.
+ */
 #define BROTLI_LARGE_MAX_DISTANCE_BITS 62U
 #define BROTLI_LARGE_MIN_WBITS 10
+/**
+ * The maximum supported large brotli window bits by the encoder and decoder.
+ * Large window brotli allows up to 62 bits, however the current encoder and
+ * decoder, designed for 32-bit integers, only support up to 30 bits maximum.
+ */
 #define BROTLI_LARGE_MAX_WBITS 30
 
 /* Specification: 4. Encoding of distances */
 #define BROTLI_NUM_DISTANCE_SHORT_CODES 16
+/**
+ * Maximal number of "postfix" bits.
+ *
+ * Number of "postfix" bits is stored as 2 bits in meta-block header.
+ */
 #define BROTLI_MAX_NPOSTFIX 3
 #define BROTLI_MAX_NDIRECT 120
 #define BROTLI_MAX_DISTANCE_BITS 24U
@@ -45,9 +73,22 @@
 #define BROTLI_NUM_DISTANCE_SYMBOLS \
     BROTLI_DISTANCE_ALPHABET_SIZE(  \
         BROTLI_MAX_NDIRECT, BROTLI_MAX_NPOSTFIX, BROTLI_LARGE_MAX_DISTANCE_BITS)
+
+/* ((1 << 26) - 4) is the maximal distance that can be expressed in RFC 7932
+   brotli stream using NPOSTFIX = 0 and NDIRECT = 0. With other NPOSTFIX and
+   NDIRECT values distances up to ((1 << 29) + 88) could be expressed. */
 #define BROTLI_MAX_DISTANCE 0x3FFFFFC
+
+/* ((1 << 31) - 4) is the safe distance limit. Using this number as a limit
+   allows safe distance calculation without overflows, given the distance
+   alphabet size is limited to corresponding size
+   (see kLargeWindowDistanceCodeLimits). */
 #define BROTLI_MAX_ALLOWED_DISTANCE 0x7FFFFFFC
 
+
+/* Specification: 4. Encoding of Literal Insertion Lengths and Copy Lengths */
+#define BROTLI_NUM_INS_COPY_CODES 24
+
 /* 7.1. Context modes and context ID lookup for literals */
 /* "context IDs for literals are in the range of 0..63" */
 #define BROTLI_LITERAL_CONTEXT_BITS 6
@@ -61,4 +102,99 @@
 #define BROTLI_WINDOW_GAP 16
 #define BROTLI_MAX_BACKWARD_LIMIT(W) (((size_t)1 << (W)) - BROTLI_WINDOW_GAP)
 
+typedef struct BrotliDistanceCodeLimit {
+  uint32_t max_alphabet_size;
+  uint32_t max_distance;
+} BrotliDistanceCodeLimit;
+
+/* This function calculates maximal size of distance alphabet, such that the
+   distances greater than the given values can not be represented.
+
+   This limits are designed to support fast and safe 32-bit decoders.
+   "32-bit" means that signed integer values up to ((1 << 31) - 1) could be
+   safely expressed.
+
+   Brotli distance alphabet symbols do not represent consecutive distance
+   ranges. Each distance alphabet symbol (excluding direct distances and short
+   codes), represent interleaved (for NPOSTFIX > 0) range of distances.
+   A "group" of consecutive (1 << NPOSTFIX) symbols represent non-interleaved
+   range. Two consecutive groups require the same amount of "extra bits".
+
+   It is important that distance alphabet represents complete "groups".
+   To avoid complex logic on encoder side about interleaved ranges
+   it was decided to restrict both sides to complete distance code "groups".
+ */
+BROTLI_UNUSED_FUNCTION BrotliDistanceCodeLimit BrotliCalculateDistanceCodeLimit(
+    uint32_t max_distance, uint32_t npostfix, uint32_t ndirect) {
+  BrotliDistanceCodeLimit result;
+  /* Marking this function as unused, because not all files
+     including "constants.h" use it -> compiler warns about that. */
+  BROTLI_UNUSED(&BrotliCalculateDistanceCodeLimit);
+  if (max_distance <= ndirect) {
+    /* This case never happens / exists only for the sake of completeness. */
+    result.max_alphabet_size = max_distance + BROTLI_NUM_DISTANCE_SHORT_CODES;
+    result.max_distance = max_distance;
+    return result;
+  } else {
+    /* The first prohibited value. */
+    uint32_t forbidden_distance = max_distance + 1;
+    /* Subtract "directly" encoded region. */
+    uint32_t offset = forbidden_distance - ndirect - 1;
+    uint32_t ndistbits = 0;
+    uint32_t tmp;
+    uint32_t half;
+    uint32_t group;
+    /* Postfix for the last dcode in the group. */
+    uint32_t postfix = (1u << npostfix) - 1;
+    uint32_t extra;
+    uint32_t start;
+    /* Remove postfix and "head-start". */
+    offset = (offset >> npostfix) + 4;
+    /* Calculate the number of distance bits. */
+    tmp = offset / 2;
+    /* Poor-man's log2floor, to avoid extra dependencies. */
+    while (tmp != 0) {ndistbits++; tmp = tmp >> 1;}
+    /* One bit is covered with subrange addressing ("half"). */
+    ndistbits--;
+    /* Find subrange. */
+    half = (offset >> ndistbits) & 1;
+    /* Calculate the "group" part of dcode. */
+    group = ((ndistbits - 1) << 1) | half;
+    /* Calculated "group" covers the prohibited distance value. */
+    if (group == 0) {
+      /* This case is added for correctness; does not occur for limit > 128. */
+      result.max_alphabet_size = ndirect + BROTLI_NUM_DISTANCE_SHORT_CODES;
+      result.max_distance = ndirect;
+      return result;
+    }
+    /* Decrement "group", so it is the last permitted "group". */
+    group--;
+    /* After group was decremented, ndistbits and half must be recalculated. */
+    ndistbits = (group >> 1) + 1;
+    /* The last available distance in the subrange has all extra bits set. */
+    extra = (1u << ndistbits) - 1;
+    /* Calculate region start. NB: ndistbits >= 1. */
+    start = (1u << (ndistbits + 1)) - 4;
+    /* Move to subregion. */
+    start += (group & 1) << ndistbits;
+    /* Calculate the alphabet size. */
+    result.max_alphabet_size = ((group << npostfix) | postfix) + ndirect +
+        BROTLI_NUM_DISTANCE_SHORT_CODES + 1;
+    /* Calculate the maximal distance representable by alphabet. */
+    result.max_distance = ((start + extra) << npostfix) + postfix + ndirect + 1;
+    return result;
+  }
+}
+
+/* Represents the range of values belonging to a prefix code:
+   [offset, offset + 2^nbits) */
+typedef struct {
+  uint16_t offset;
+  uint8_t nbits;
+} BrotliPrefixCodeRange;
+
+/* "Soft-private", it is exported, but not "advertised" as API. */
+BROTLI_COMMON_API extern const BrotliPrefixCodeRange
+    _kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS];
+
 #endif  /* BROTLI_COMMON_CONSTANTS_H_ */
diff --git a/third_party/brotli/common/context.c b/third_party/brotli/common/context.c
new file mode 100644
index 0000000..2c2dceb
--- /dev/null
+++ b/third_party/brotli/common/context.c
@@ -0,0 +1,156 @@
+#include "./context.h"
+
+#include <brotli/types.h>
+
+/* Common context lookup table for all context modes. */
+const uint8_t _kBrotliContextLookupTable[2048] = {
+  /* CONTEXT_LSB6, last byte. */
+   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+
+  /* CONTEXT_LSB6, second last byte, */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+  /* CONTEXT_MSB6, last byte. */
+   0,  0,  0,  0,  1,  1,  1,  1,  2,  2,  2,  2,  3,  3,  3,  3,
+   4,  4,  4,  4,  5,  5,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,
+   8,  8,  8,  8,  9,  9,  9,  9, 10, 10, 10, 10, 11, 11, 11, 11,
+  12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
+  16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
+  20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
+  24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
+  28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
+  32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
+  36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
+  40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
+  44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
+  48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
+  52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
+  56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
+  60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63,
+
+  /* CONTEXT_MSB6, second last byte, */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+  /* CONTEXT_UTF8, last byte. */
+  /* ASCII range. */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  4,  4,  0,  0,  4,  0,  0,
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+   8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12,
+  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12,
+  12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48,
+  52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12,
+  12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56,
+  60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12,  0,
+  /* UTF8 continuation byte range. */
+  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+  /* UTF8 lead byte range. */
+  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
+  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
+  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
+  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
+
+  /* CONTEXT_UTF8 second last byte. */
+  /* ASCII range. */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
+  1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
+  1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0,
+  /* UTF8 continuation byte range. */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  /* UTF8 lead byte range. */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+
+  /* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */
+   0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+  16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+  16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+  16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+  40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+  40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+  40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+  48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56,
+
+  /* CONTEXT_SIGNED, second last byte. */
+  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
+};
diff --git a/third_party/brotli/common/context.h b/third_party/brotli/common/context.h
index 24b3eb4..685a279d 100644
--- a/third_party/brotli/common/context.h
+++ b/third_party/brotli/common/context.h
@@ -88,6 +88,7 @@
 #ifndef BROTLI_COMMON_CONTEXT_H_
 #define BROTLI_COMMON_CONTEXT_H_
 
+#include <brotli/port.h>
 #include <brotli/types.h>
 
 typedef enum ContextType {
@@ -97,163 +98,14 @@
   CONTEXT_SIGNED = 3
 } ContextType;
 
+/* "Soft-private", it is exported, but not "advertised" as API. */
 /* Common context lookup table for all context modes. */
-static const uint8_t kContextLookup[2048] = {
-  /* CONTEXT_LSB6, last byte. */
-   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
-  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
-  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
-  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
-  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-
-  /* CONTEXT_LSB6, second last byte, */
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
-  /* CONTEXT_MSB6, last byte. */
-   0,  0,  0,  0,  1,  1,  1,  1,  2,  2,  2,  2,  3,  3,  3,  3,
-   4,  4,  4,  4,  5,  5,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,
-   8,  8,  8,  8,  9,  9,  9,  9, 10, 10, 10, 10, 11, 11, 11, 11,
-  12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
-  16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
-  20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
-  24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
-  28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
-  32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
-  36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
-  40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
-  44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
-  48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
-  52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
-  56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
-  60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63,
-
-  /* CONTEXT_MSB6, second last byte, */
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
-  /* CONTEXT_UTF8, last byte. */
-  /* ASCII range. */
-   0,  0,  0,  0,  0,  0,  0,  0,  0,  4,  4,  0,  0,  4,  0,  0,
-   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-   8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12,
-  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12,
-  12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48,
-  52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12,
-  12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56,
-  60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12,  0,
-  /* UTF8 continuation byte range. */
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  /* UTF8 lead byte range. */
-  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
-  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
-  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
-  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
-
-  /* CONTEXT_UTF8 second last byte. */
-  /* ASCII range. */
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
-  1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
-  1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0,
-  /* UTF8 continuation byte range. */
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  /* UTF8 lead byte range. */
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-
-  /* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */
-   0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-  16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
-  16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
-  16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
-  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-  40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
-  40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
-  40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
-  48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56,
-
-  /* CONTEXT_SIGNED, second last byte. */
-  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
-};
+BROTLI_COMMON_API extern const uint8_t _kBrotliContextLookupTable[2048];
 
 typedef const uint8_t* ContextLut;
 
 /* typeof(MODE) == ContextType; returns ContextLut */
-#define BROTLI_CONTEXT_LUT(MODE) (&kContextLookup[(MODE) << 9])
+#define BROTLI_CONTEXT_LUT(MODE) (&_kBrotliContextLookupTable[(MODE) << 9])
 
 /* typeof(LUT) == ContextLut */
 #define BROTLI_CONTEXT(P1, P2, LUT) ((LUT)[P1] | ((LUT) + 256)[P2])
diff --git a/third_party/brotli/common/dictionary.c b/third_party/brotli/common/dictionary.c
index 64822a38..f9e3041 100644
--- a/third_party/brotli/common/dictionary.c
+++ b/third_party/brotli/common/dictionary.c
@@ -5,12 +5,13 @@
 */
 
 #include "./dictionary.h"
+#include "./platform.h"
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
 
-#ifndef BROTLI_EXTERNAL_DICTIONARY_DATA
+#if !defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
 static const uint8_t kBrotliDictionaryData[] =
 {
 116,105,109,101,100,111,119,110,108,105,102,101,108,101,102,116,98,97,99,107,99,
@@ -5862,7 +5863,11 @@
 ;
 #endif  /* !BROTLI_EXTERNAL_DICTIONARY_DATA */
 
+#if !defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
+static const BrotliDictionary kBrotliDictionary = {
+#else
 static BrotliDictionary kBrotliDictionary = {
+#endif
   /* size_bits_by_length */
   {
     0, 0, 0, 0, 10, 10, 11, 11,
@@ -5895,9 +5900,13 @@
 }
 
 void BrotliSetDictionaryData(const uint8_t* data) {
+#if defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
   if (!!data && !kBrotliDictionary.data) {
     kBrotliDictionary.data = data;
   }
+#else
+  BROTLI_UNUSED(data);  // Appease -Werror=unused-parameter
+#endif
 }
 
 #if defined(__cplusplus) || defined(c_plusplus)
diff --git a/third_party/brotli/common/platform.c b/third_party/brotli/common/platform.c
new file mode 100644
index 0000000..aef39e9
--- /dev/null
+++ b/third_party/brotli/common/platform.c
@@ -0,0 +1,22 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+   Distributed under MIT license.
+   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#include <stdlib.h>
+
+#include "./platform.h"
+#include <brotli/types.h>
+
+/* Default brotli_alloc_func */
+void* BrotliDefaultAllocFunc(void* opaque, size_t size) {
+  BROTLI_UNUSED(opaque);
+  return malloc(size);
+}
+
+/* Default brotli_free_func */
+void BrotliDefaultFreeFunc(void* opaque, void* address) {
+  BROTLI_UNUSED(opaque);
+  free(address);
+}
diff --git a/third_party/brotli/common/platform.h b/third_party/brotli/common/platform.h
index 4113a4be..f5ca443 100644
--- a/third_party/brotli/common/platform.h
+++ b/third_party/brotli/common/platform.h
@@ -24,16 +24,15 @@
 #define BROTLI_COMMON_PLATFORM_H_
 
 #include <string.h>  /* memcpy */
-#include <stdlib.h>  /* malloc, free */
 
 #include <brotli/port.h>
 #include <brotli/types.h>
 
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_CYGWIN)
+#if defined(OS_LINUX) || defined(OS_CYGWIN) || defined(__EMSCRIPTEN__)
 #include <endian.h>
 #elif defined(OS_FREEBSD)
 #include <machine/endian.h>
-#elif defined(OS_APPLE)
+#elif defined(OS_MACOSX)
 #include <machine/endian.h>
 /* Let's try and follow the Linux convention */
 #define BROTLI_X_BYTE_ORDER BYTE_ORDER
@@ -41,6 +40,10 @@
 #define BROTLI_X_BIG_ENDIAN BIG_ENDIAN
 #endif
 
+#if BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
+#include <intrin.h>
+#endif
+
 #if defined(BROTLI_ENABLE_LOG) || defined(BROTLI_DEBUG)
 #include <assert.h>
 #include <stdio.h>
@@ -69,11 +72,13 @@
   }
 
 */
-#if BROTLI_GNUC_HAS_BUILTIN(__builtin_expect, 3, 0, 0) ||                      \
-    BROTLI_INTEL_VERSION_CHECK(16, 0, 0) ||                                    \
-    BROTLI_SUNPRO_VERSION_CHECK(5, 15, 0) ||                                   \
-    BROTLI_ARM_VERSION_CHECK(4, 1, 0) || BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
-    BROTLI_TI_VERSION_CHECK(7, 3, 0) || BROTLI_TINYC_VERSION_CHECK(0, 9, 27)
+#if BROTLI_GNUC_HAS_BUILTIN(__builtin_expect, 3, 0, 0) || \
+    BROTLI_INTEL_VERSION_CHECK(16, 0, 0) ||               \
+    BROTLI_SUNPRO_VERSION_CHECK(5, 15, 0) ||              \
+    BROTLI_ARM_VERSION_CHECK(4, 1, 0) ||                  \
+    BROTLI_IBM_VERSION_CHECK(10, 1, 0) ||                 \
+    BROTLI_TI_VERSION_CHECK(7, 3, 0) ||                   \
+    BROTLI_TINYC_VERSION_CHECK(0, 9, 27)
 #define BROTLI_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
 #define BROTLI_PREDICT_FALSE(x) (__builtin_expect(x, 0))
 #else
@@ -84,12 +89,14 @@
 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
     !defined(__cplusplus)
 #define BROTLI_RESTRICT restrict
-#elif BROTLI_GNUC_VERSION_CHECK(3, 1, 0) ||                                    \
-    BROTLI_MSVC_VERSION_CHECK(14, 0, 0) ||                                     \
-    BROTLI_INTEL_VERSION_CHECK(16, 0, 0) ||                                    \
-    BROTLI_ARM_VERSION_CHECK(4, 1, 0) || BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
-    BROTLI_PGI_VERSION_CHECK(17, 10, 0) || BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
-    BROTLI_IAR_VERSION_CHECK(8, 0, 0) ||                                       \
+#elif BROTLI_GNUC_VERSION_CHECK(3, 1, 0) ||                         \
+    BROTLI_MSVC_VERSION_CHECK(14, 0, 0) ||                          \
+    BROTLI_INTEL_VERSION_CHECK(16, 0, 0) ||                         \
+    BROTLI_ARM_VERSION_CHECK(4, 1, 0) ||                            \
+    BROTLI_IBM_VERSION_CHECK(10, 1, 0) ||                           \
+    BROTLI_PGI_VERSION_CHECK(17, 10, 0) ||                          \
+    BROTLI_TI_VERSION_CHECK(8, 0, 0) ||                             \
+    BROTLI_IAR_VERSION_CHECK(8, 0, 0) ||                            \
     (BROTLI_SUNPRO_VERSION_CHECK(5, 14, 0) && defined(__cplusplus))
 #define BROTLI_RESTRICT __restrict
 #elif BROTLI_SUNPRO_VERSION_CHECK(5, 3, 0) && !defined(__cplusplus)
@@ -114,10 +121,10 @@
 #if BROTLI_GNUC_HAS_ATTRIBUTE(always_inline, 4, 0, 0) ||                       \
     BROTLI_INTEL_VERSION_CHECK(16, 0, 0) ||                                    \
     BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) ||                                   \
-    BROTLI_ARM_VERSION_CHECK(4, 1, 0) || BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
+    BROTLI_ARM_VERSION_CHECK(4, 1, 0) ||                                       \
+    BROTLI_IBM_VERSION_CHECK(10, 1, 0) ||                                      \
     BROTLI_TI_VERSION_CHECK(8, 0, 0) ||                                        \
-    (BROTLI_TI_VERSION_CHECK(7, 3, 0) &&                                       \
-     defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
+    (BROTLI_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
 #define BROTLI_INLINE BROTLI_MAYBE_INLINE __attribute__((__always_inline__))
 #elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
 #define BROTLI_INLINE BROTLI_MAYBE_INLINE __forceinline
@@ -132,10 +139,10 @@
 #if BROTLI_GNUC_HAS_ATTRIBUTE(noinline, 4, 0, 0) ||                            \
     BROTLI_INTEL_VERSION_CHECK(16, 0, 0) ||                                    \
     BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) ||                                   \
-    BROTLI_ARM_VERSION_CHECK(4, 1, 0) || BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
+    BROTLI_ARM_VERSION_CHECK(4, 1, 0) ||                                       \
+    BROTLI_IBM_VERSION_CHECK(10, 1, 0) ||                                      \
     BROTLI_TI_VERSION_CHECK(8, 0, 0) ||                                        \
-    (BROTLI_TI_VERSION_CHECK(7, 3, 0) &&                                       \
-     defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
+    (BROTLI_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
 #define BROTLI_NOINLINE __attribute__((__noinline__))
 #elif BROTLI_MSVC_VERSION_CHECK(13, 10, 0)
 #define BROTLI_NOINLINE __declspec(noinline)
@@ -153,12 +160,13 @@
 #if !defined(BROTLI_INTERNAL)
 #if defined(_WIN32) || defined(__CYGWIN__)
 #define BROTLI_INTERNAL
-#elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) ||                                    \
-    BROTLI_TI_VERSION_CHECK(8, 0, 0) ||                                        \
-    BROTLI_INTEL_VERSION_CHECK(16, 0, 0) ||                                    \
-    BROTLI_ARM_VERSION_CHECK(4, 1, 0) || BROTLI_IBM_VERSION_CHECK(13, 1, 0) || \
-    BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) ||                                   \
-    (BROTLI_TI_VERSION_CHECK(7, 3, 0) &&                                       \
+#elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) ||                         \
+    BROTLI_TI_VERSION_CHECK(8, 0, 0) ||                             \
+    BROTLI_INTEL_VERSION_CHECK(16, 0, 0) ||                         \
+    BROTLI_ARM_VERSION_CHECK(4, 1, 0) ||                            \
+    BROTLI_IBM_VERSION_CHECK(13, 1, 0) ||                           \
+    BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) ||                        \
+    (BROTLI_TI_VERSION_CHECK(7, 3, 0) &&                            \
      defined(__TI_GNU_ATTRIBUTE_SUPPORT__) && defined(__TI_EABI__))
 #define BROTLI_INTERNAL __attribute__ ((visibility ("hidden")))
 #else
@@ -186,8 +194,8 @@
 #define BROTLI_TARGET_ARMV7
 #endif  /* ARMv7 */
 
-#if (defined(__ARM_ARCH) && (__ARM_ARCH == 8)) || defined(__aarch64__) || \
-    defined(__ARM64_ARCH_8__)
+#if (defined(__ARM_ARCH) && (__ARM_ARCH == 8)) || \
+    defined(__aarch64__) || defined(__ARM64_ARCH_8__)
 #define BROTLI_TARGET_ARMV8_ANY
 
 #if defined(__ARM_32BIT_STATE)
@@ -272,7 +280,7 @@
 
 #if defined(BROTLI_BUILD_PORTABLE)
 #define BROTLI_ALIGNED_READ (!!1)
-#elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) ||       \
+#elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \
     defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY) || \
     defined(BROTLI_TARGET_RISCV64)
 /* Allow unaligned read only for white-listed CPUs. */
@@ -303,8 +311,7 @@
 }
 #else  /* BROTLI_ALIGNED_READ */
 /* Unaligned memory access is allowed: just cast pointer to requested type. */
-#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
-    defined(MEMORY_SANITIZER)
+#if BROTLI_SANITIZED
 /* Consider we have an unaligned load/store of 4 bytes from address 0x...05.
    AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
    will miss a bug if 08 is the first unaddressable byte.
@@ -329,7 +336,7 @@
 #define BrotliUnalignedRead32 __sanitizer_unaligned_load32
 #define BrotliUnalignedRead64 __sanitizer_unaligned_load64
 #define BrotliUnalignedWrite64 __sanitizer_unaligned_store64
-#else
+#else  /* BROTLI_SANITIZED */
 static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
   return *(const uint16_t*)p;
 }
@@ -351,7 +358,7 @@
 typedef BROTLI_ALIGNED(1) uint64_t brotli_unaligned_uint64_t;
 
 static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
-  return (uint64_t) ((brotli_unaligned_uint64_t*) p)[0];
+  return (uint64_t) ((const brotli_unaligned_uint64_t*) p)[0];
 }
 static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
   brotli_unaligned_uint64_t* dwords = (brotli_unaligned_uint64_t*) p;
@@ -369,7 +376,7 @@
 }
 #endif  /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
 #endif  /* BROTLI_64_BITS */
-#endif  /* ASAN / TSAN / MSAN */
+#endif  /* BROTLI_SANITIZED */
 #endif  /* BROTLI_ALIGNED_READ */
 
 #if BROTLI_LITTLE_ENDIAN
@@ -461,20 +468,20 @@
 #endif
 
 #if defined(BROTLI_ENABLE_LOG)
-#define BROTLI_DCHECK(x) assert(x)
 #define BROTLI_LOG(x) printf x
 #else
-#define BROTLI_DCHECK(x)
 #define BROTLI_LOG(x)
 #endif
 
 #if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG)
+#define BROTLI_DCHECK(x) assert(x)
 static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) {
   fprintf(stderr, "%s:%d (%s)\n", f, l, fn);
   fflush(stderr);
 }
 #define BROTLI_DUMP() BrotliDump(__FILE__, __LINE__, __FUNCTION__)
 #else
+#define BROTLI_DCHECK(x)
 #define BROTLI_DUMP() (void)(0)
 #endif
 
@@ -518,17 +525,41 @@
   (A)[(J)] = __brotli_swap_tmp;   \
 }
 
-/* Default brotli_alloc_func */
-static void* BrotliDefaultAllocFunc(void* opaque, size_t size) {
-  BROTLI_UNUSED(opaque);
-  return malloc(size);
+#if BROTLI_64_BITS
+#if BROTLI_GNUC_HAS_BUILTIN(__builtin_ctzll, 3, 4, 0) || \
+    BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
+#define BROTLI_TZCNT64 __builtin_ctzll
+#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
+#if defined(BROTLI_TARGET_X64)
+#define BROTLI_TZCNT64 _tzcnt_u64
+#else /* BROTLI_TARGET_X64 */
+static BROTLI_INLINE uint32_t BrotliBsf64Msvc(uint64_t x) {
+  uint32_t lsb;
+  _BitScanForward64(&lsb, x);
+  return lsb;
 }
+#define BROTLI_TZCNT64 BrotliBsf64Msvc
+#endif /* BROTLI_TARGET_X64 */
+#endif /* __builtin_ctzll */
+#endif /* BROTLI_64_BITS */
+
+#if BROTLI_GNUC_HAS_BUILTIN(__builtin_clz, 3, 4, 0) || \
+    BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
+#define BROTLI_BSR32(x) (31u ^ (uint32_t)__builtin_clz(x))
+#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
+static BROTLI_INLINE uint32_t BrotliBsr32Msvc(uint32_t x) {
+  unsigned long msb;
+  _BitScanReverse(&msb, x);
+  return (uint32_t)msb;
+}
+#define BROTLI_BSR32 BrotliBsr32Msvc
+#endif /* __builtin_clz */
+
+/* Default brotli_alloc_func */
+BROTLI_COMMON_API void* BrotliDefaultAllocFunc(void* opaque, size_t size);
 
 /* Default brotli_free_func */
-static void BrotliDefaultFreeFunc(void* opaque, void* address) {
-  BROTLI_UNUSED(opaque);
-  free(address);
-}
+BROTLI_COMMON_API void BrotliDefaultFreeFunc(void* opaque, void* address);
 
 BROTLI_UNUSED_FUNCTION void BrotliSuppressUnusedFunctions(void) {
   BROTLI_UNUSED(&BrotliSuppressUnusedFunctions);
diff --git a/third_party/brotli/common/transform.c b/third_party/brotli/common/transform.c
index 426e635f..f8fa433 100644
--- a/third_party/brotli/common/transform.c
+++ b/third_party/brotli/common/transform.c
@@ -24,8 +24,8 @@
 /* 8x  _0 _ _3    _8   _C _E _ _1     _7       _F */
       " not \3er \3al \4ful \4ive \5less \4es"
 /* Ax       _5   _9   _D    _2    _7     _D */
-      "t \4ize \2\xc2\xa0\4ous \5 the \2e \0";
-/* Cx    _2    _7___ ___ _A    _F     _5  _8 */
+      "t \4ize \2\xc2\xa0\4ous \5 the \2e "; /* \0 - implicit trailing zero. */
+/* Cx    _2    _7___ ___ _A    _F     _5        _8 */
 
 static const uint16_t kPrefixSuffixMap[50] = {
   0x00, 0x02, 0x05, 0x0E, 0x13, 0x16, 0x18, 0x1E, 0x23, 0x25,
@@ -160,12 +160,13 @@
    0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 34,
 };
 
-static BrotliTransforms kBrotliTransforms = {
+static const BrotliTransforms kBrotliTransforms = {
   sizeof(kPrefixSuffix),
   (const uint8_t*)kPrefixSuffix,
   kPrefixSuffixMap,
   sizeof(kTransformsData) / (3 * sizeof(kTransformsData[0])),
   kTransformsData,
+  NULL,  /* no extra parameters */
   {0, 12, 27, 23, 42, 63, 56, 48, 59, 64}
 };
 
@@ -190,6 +191,48 @@
   return 3;
 }
 
+static int Shift(uint8_t* word, int word_len, uint16_t parameter) {
+  /* Limited sign extension: scalar < (1 << 24). */
+  uint32_t scalar =
+      (parameter & 0x7FFFu) + (0x1000000u - (parameter & 0x8000u));
+  if (word[0] < 0x80) {
+    /* 1-byte rune / 0sssssss / 7 bit scalar (ASCII). */
+    scalar += (uint32_t)word[0];
+    word[0] = (uint8_t)(scalar & 0x7Fu);
+    return 1;
+  } else if (word[0] < 0xC0) {
+    /* Continuation / 10AAAAAA. */
+    return 1;
+  } else if (word[0] < 0xE0) {
+    /* 2-byte rune / 110sssss AAssssss / 11 bit scalar. */
+    if (word_len < 2) return 1;
+    scalar += (uint32_t)((word[1] & 0x3Fu) | ((word[0] & 0x1Fu) << 6u));
+    word[0] = (uint8_t)(0xC0 | ((scalar >> 6u) & 0x1F));
+    word[1] = (uint8_t)((word[1] & 0xC0) | (scalar & 0x3F));
+    return 2;
+  } else if (word[0] < 0xF0) {
+    /* 3-byte rune / 1110ssss AAssssss BBssssss / 16 bit scalar. */
+    if (word_len < 3) return word_len;
+    scalar += (uint32_t)((word[2] & 0x3Fu) | ((word[1] & 0x3Fu) << 6u) |
+        ((word[0] & 0x0Fu) << 12u));
+    word[0] = (uint8_t)(0xE0 | ((scalar >> 12u) & 0x0F));
+    word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 6u) & 0x3F));
+    word[2] = (uint8_t)((word[2] & 0xC0) | (scalar & 0x3F));
+    return 3;
+  } else if (word[0] < 0xF8) {
+    /* 4-byte rune / 11110sss AAssssss BBssssss CCssssss / 21 bit scalar. */
+    if (word_len < 4) return word_len;
+    scalar += (uint32_t)((word[3] & 0x3Fu) | ((word[2] & 0x3Fu) << 6u) |
+        ((word[1] & 0x3Fu) << 12u) | ((word[0] & 0x07u) << 18u));
+    word[0] = (uint8_t)(0xF0 | ((scalar >> 18u) & 0x07));
+    word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 12u) & 0x3F));
+    word[2] = (uint8_t)((word[2] & 0xC0) | ((scalar >> 6u) & 0x3F));
+    word[3] = (uint8_t)((word[3] & 0xC0) | (scalar & 0x3F));
+    return 4;
+  }
+  return 1;
+}
+
 int BrotliTransformDictionaryWord(uint8_t* dst, const uint8_t* word, int len,
     const BrotliTransforms* transforms, int transform_idx) {
   int idx = 0;
@@ -221,6 +264,19 @@
         uppercase += step;
         len -= step;
       }
+    } else if (t == BROTLI_TRANSFORM_SHIFT_FIRST) {
+      uint16_t param = (uint16_t)(transforms->params[transform_idx * 2]
+          + (transforms->params[transform_idx * 2 + 1] << 8u));
+      Shift(&dst[idx - len], len, param);
+    } else if (t == BROTLI_TRANSFORM_SHIFT_ALL) {
+      uint16_t param = (uint16_t)(transforms->params[transform_idx * 2]
+          + (transforms->params[transform_idx * 2 + 1] << 8u));
+      uint8_t* shift = &dst[idx - len];
+      while (len > 0) {
+        int step = Shift(shift, len, param);
+        shift += step;
+        len -= step;
+      }
     }
   }
   {
diff --git a/third_party/brotli/common/transform.h b/third_party/brotli/common/transform.h
index 456c12d..b6f86cc7 100644
--- a/third_party/brotli/common/transform.h
+++ b/third_party/brotli/common/transform.h
@@ -37,6 +37,8 @@
   BROTLI_TRANSFORM_OMIT_FIRST_7 = 18,
   BROTLI_TRANSFORM_OMIT_FIRST_8 = 19,
   BROTLI_TRANSFORM_OMIT_FIRST_9 = 20,
+  BROTLI_TRANSFORM_SHIFT_FIRST = 21,
+  BROTLI_TRANSFORM_SHIFT_ALL = 22,
   BROTLI_NUM_TRANSFORM_TYPES  /* Counts transforms, not a transform itself. */
 };
 
@@ -50,6 +52,9 @@
   uint32_t num_transforms;
   /* Each entry is a [prefix_id, transform, suffix_id] triplet. */
   const uint8_t* transforms;
+  /* Shift for BROTLI_TRANSFORM_SHIFT_FIRST and BROTLI_TRANSFORM_SHIFT_ALL,
+     must be NULL if and only if no such transforms are present. */
+  const uint8_t* params;
   /* Indices of transforms like ["", BROTLI_TRANSFORM_OMIT_LAST_#, ""].
      0-th element corresponds to ["", BROTLI_TRANSFORM_IDENTITY, ""].
      -1, if cut-off transform does not exist. */
diff --git a/third_party/brotli/common/version.h b/third_party/brotli/common/version.h
index 0d0d0c7..01b2998 100644
--- a/third_party/brotli/common/version.h
+++ b/third_party/brotli/common/version.h
@@ -14,13 +14,13 @@
    BrotliEncoderVersion methods. */
 
 /* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */
-#define BROTLI_VERSION 0x1000007
+#define BROTLI_VERSION 0x1000009
 
 /* This macro is used by build system to produce Libtool-friendly soname. See
    https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
  */
 
 /* ABI version, calculated as (CURRENT << 24) | (REVISION << 12) | AGE */
-#define BROTLI_ABI_VERSION 0x1007000
+#define BROTLI_ABI_VERSION 0x1009000
 
 #endif  /* BROTLI_COMMON_VERSION_H_ */
diff --git a/third_party/brotli/dec/bit_reader.c b/third_party/brotli/dec/bit_reader.c
index 722fd90..7f7b256a 100644
--- a/third_party/brotli/dec/bit_reader.c
+++ b/third_party/brotli/dec/bit_reader.c
@@ -15,6 +15,17 @@
 extern "C" {
 #endif
 
+const uint32_t kBrotliBitMask[33] = {   0x00000000,
+    0x00000001, 0x00000003, 0x00000007, 0x0000000F,
+    0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
+    0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
+    0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
+    0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
+    0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
+    0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
+    0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
+};
+
 void BrotliInitBitReader(BrotliBitReader* const br) {
   br->val_ = 0;
   br->bit_pos_ = sizeof(br->val_) << 3;
@@ -43,6 +54,23 @@
   return BROTLI_TRUE;
 }
 
+BROTLI_BOOL BrotliSafeReadBits32Slow(BrotliBitReader* const br,
+    uint32_t n_bits, uint32_t* val) {
+  uint32_t low_val;
+  uint32_t high_val;
+  BrotliBitReaderState memento;
+  BROTLI_DCHECK(n_bits <= 32);
+  BROTLI_DCHECK(n_bits > 24);
+  BrotliBitReaderSaveState(br, &memento);
+  if (!BrotliSafeReadBits(br, 16, &low_val) ||
+      !BrotliSafeReadBits(br, n_bits - 16, &high_val)) {
+    BrotliBitReaderRestoreState(br, &memento);
+    return BROTLI_FALSE;
+  }
+  *val = low_val | (high_val << 16);
+  return BROTLI_TRUE;
+}
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }  /* extern "C" */
 #endif
diff --git a/third_party/brotli/dec/bit_reader.h b/third_party/brotli/dec/bit_reader.h
index c06e914..22bc060 100644
--- a/third_party/brotli/dec/bit_reader.h
+++ b/third_party/brotli/dec/bit_reader.h
@@ -11,6 +11,7 @@
 
 #include <string.h>  /* memcpy */
 
+#include "../common/constants.h"
 #include "../common/platform.h"
 #include <brotli/types.h>
 
@@ -20,16 +21,7 @@
 
 #define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(brotli_reg_t) >> 1)
 
-static const uint32_t kBitMask[33] = {  0x00000000,
-    0x00000001, 0x00000003, 0x00000007, 0x0000000F,
-    0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
-    0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
-    0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
-    0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
-    0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
-    0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
-    0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
-};
+BROTLI_INTERNAL extern const uint32_t kBrotliBitMask[33];
 
 static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
   if (BROTLI_IS_CONSTANT(n) || BROTLI_HAS_UBFX) {
@@ -37,7 +29,7 @@
        "Unsigned Bit Field Extract" UBFX instruction on ARM. */
     return ~((0xFFFFFFFFu) << n);
   } else {
-    return kBitMask[n];
+    return kBrotliBitMask[n];
   }
 }
 
@@ -65,6 +57,12 @@
    reading. */
 BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br);
 
+/* Fallback for BrotliSafeReadBits32. Extracted as noninlined method to unburden
+   the main code-path. Never called for RFC brotli streams, required only for
+   "large-window" mode and other extensions. */
+BROTLI_INTERNAL BROTLI_NOINLINE BROTLI_BOOL BrotliSafeReadBits32Slow(
+    BrotliBitReader* const br, uint32_t n_bits, uint32_t* val);
+
 static BROTLI_INLINE void BrotliBitReaderSaveState(
     BrotliBitReader* const from, BrotliBitReaderState* to) {
   to->val_ = from->val_;
@@ -87,8 +85,11 @@
 }
 
 /* Returns amount of unread bytes the bit reader still has buffered from the
-   BrotliInput, including whole bytes in br->val_. */
+   BrotliInput, including whole bytes in br->val_. Result is capped with
+   maximal ring-buffer size (larger number won't be utilized anyway). */
 static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) {
+  static const size_t kCap = (size_t)1 << BROTLI_LARGE_MAX_WBITS;
+  if (br->avail_in > kCap) return kCap;
   return br->avail_in + (BrotliGetAvailableBits(br) >> 3);
 }
 
@@ -237,15 +238,17 @@
 static BROTLI_INLINE void BrotliTakeBits(
   BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
   *val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
-  BROTLI_LOG(("[BrotliReadBits]  %d %d %d val: %6x\n",
+  BROTLI_LOG(("[BrotliTakeBits]  %d %d %d val: %6x\n",
       (int)br->avail_in, (int)br->bit_pos_, (int)n_bits, (int)*val));
   BrotliDropBits(br, n_bits);
 }
 
 /* Reads the specified number of bits from |br| and advances the bit pos.
-   Assumes that there is enough input to perform BrotliFillBitWindow. */
-static BROTLI_INLINE uint32_t BrotliReadBits(
+   Assumes that there is enough input to perform BrotliFillBitWindow.
+   Up to 24 bits are allowed to be requested from this method. */
+static BROTLI_INLINE uint32_t BrotliReadBits24(
     BrotliBitReader* const br, uint32_t n_bits) {
+  BROTLI_DCHECK(n_bits <= 24);
   if (BROTLI_64_BITS || (n_bits <= 16)) {
     uint32_t val;
     BrotliFillBitWindow(br, n_bits);
@@ -262,10 +265,32 @@
   }
 }
 
+/* Same as BrotliReadBits24, but allows reading up to 32 bits. */
+static BROTLI_INLINE uint32_t BrotliReadBits32(
+    BrotliBitReader* const br, uint32_t n_bits) {
+  BROTLI_DCHECK(n_bits <= 32);
+  if (BROTLI_64_BITS || (n_bits <= 16)) {
+    uint32_t val;
+    BrotliFillBitWindow(br, n_bits);
+    BrotliTakeBits(br, n_bits, &val);
+    return val;
+  } else {
+    uint32_t low_val;
+    uint32_t high_val;
+    BrotliFillBitWindow(br, 16);
+    BrotliTakeBits(br, 16, &low_val);
+    BrotliFillBitWindow(br, 16);
+    BrotliTakeBits(br, n_bits - 16, &high_val);
+    return low_val | (high_val << 16);
+  }
+}
+
 /* Tries to read the specified amount of bits. Returns BROTLI_FALSE, if there
-   is not enough input. |n_bits| MUST be positive. */
+   is not enough input. |n_bits| MUST be positive.
+   Up to 24 bits are allowed to be requested from this method. */
 static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits(
     BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
+  BROTLI_DCHECK(n_bits <= 24);
   while (BrotliGetAvailableBits(br) < n_bits) {
     if (!BrotliPullByte(br)) {
       return BROTLI_FALSE;
@@ -275,6 +300,23 @@
   return BROTLI_TRUE;
 }
 
+/* Same as BrotliSafeReadBits, but allows reading up to 32 bits. */
+static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits32(
+    BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
+  BROTLI_DCHECK(n_bits <= 32);
+  if (BROTLI_64_BITS || (n_bits <= 24)) {
+    while (BrotliGetAvailableBits(br) < n_bits) {
+      if (!BrotliPullByte(br)) {
+        return BROTLI_FALSE;
+      }
+    }
+    BrotliTakeBits(br, n_bits, val);
+    return BROTLI_TRUE;
+  } else {
+    return BrotliSafeReadBits32Slow(br, n_bits, val);
+  }
+}
+
 /* Advances the bit reader position to the next byte boundary and verifies
    that any skipped bits are set to zero. */
 static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) {
diff --git a/third_party/brotli/dec/decode.c b/third_party/brotli/dec/decode.c
index 08bd76c..ae5a3d3 100644
--- a/third_party/brotli/dec/decode.c
+++ b/third_party/brotli/dec/decode.c
@@ -41,7 +41,8 @@
 
 /* We need the slack region for the following reasons:
     - doing up to two 16-byte copies for fast backward copying
-    - inserting transformed dictionary word (5 prefix + 24 base + 8 suffix) */
+    - inserting transformed dictionary word:
+        5 prefix + 24 base + 8 suffix */
 static const uint32_t kRingBufferWriteAheadSlack = 42;
 
 static const uint8_t kCodeLengthCodeOrder[BROTLI_CODE_LENGTH_CODES] = {
@@ -274,7 +275,8 @@
             s->loop_counter = i;
             return BROTLI_DECODER_NEEDS_MORE_INPUT;
           }
-          if (i + 1 == s->size_nibbles && s->size_nibbles > 4 && bits == 0) {
+          if (i + 1 == (int)s->size_nibbles && s->size_nibbles > 4 &&
+              bits == 0) {
             return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE);
           }
           s->meta_block_remaining_len |= (int)(bits << (i * 4));
@@ -323,7 +325,8 @@
             s->loop_counter = i;
             return BROTLI_DECODER_NEEDS_MORE_INPUT;
           }
-          if (i + 1 == s->size_nibbles && s->size_nibbles > 1 && bits == 0) {
+          if (i + 1 == (int)s->size_nibbles && s->size_nibbles > 1 &&
+              bits == 0) {
             return BROTLI_FAILURE(
                 BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE);
           }
@@ -470,32 +473,34 @@
    Totally 1..4 symbols are read, 1..11 bits each.
    The list of symbols MUST NOT contain duplicates. */
 static BrotliDecoderErrorCode ReadSimpleHuffmanSymbols(
-    uint32_t alphabet_size, uint32_t max_symbol, BrotliDecoderState* s) {
+    uint32_t alphabet_size_max, uint32_t alphabet_size_limit,
+    BrotliDecoderState* s) {
   /* max_bits == 1..11; symbol == 0..3; 1..44 bits will be read. */
   BrotliBitReader* br = &s->br;
-  uint32_t max_bits = Log2Floor(alphabet_size - 1);
-  uint32_t i = s->sub_loop_counter;
-  uint32_t num_symbols = s->symbol;
+  BrotliMetablockHeaderArena* h = &s->arena.header;
+  uint32_t max_bits = Log2Floor(alphabet_size_max - 1);
+  uint32_t i = h->sub_loop_counter;
+  uint32_t num_symbols = h->symbol;
   while (i <= num_symbols) {
     uint32_t v;
     if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, max_bits, &v))) {
-      s->sub_loop_counter = i;
-      s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_READ;
+      h->sub_loop_counter = i;
+      h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_READ;
       return BROTLI_DECODER_NEEDS_MORE_INPUT;
     }
-    if (v >= max_symbol) {
+    if (v >= alphabet_size_limit) {
       return
           BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET);
     }
-    s->symbols_lists_array[i] = (uint16_t)v;
-    BROTLI_LOG_UINT(s->symbols_lists_array[i]);
+    h->symbols_lists_array[i] = (uint16_t)v;
+    BROTLI_LOG_UINT(h->symbols_lists_array[i]);
     ++i;
   }
 
   for (i = 0; i < num_symbols; ++i) {
     uint32_t k = i + 1;
     for (; k <= num_symbols; ++k) {
-      if (s->symbols_lists_array[i] == s->symbols_lists_array[k]) {
+      if (h->symbols_lists_array[i] == h->symbols_lists_array[k]) {
         return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME);
       }
     }
@@ -588,27 +593,28 @@
 static BrotliDecoderErrorCode ReadSymbolCodeLengths(
     uint32_t alphabet_size, BrotliDecoderState* s) {
   BrotliBitReader* br = &s->br;
-  uint32_t symbol = s->symbol;
-  uint32_t repeat = s->repeat;
-  uint32_t space = s->space;
-  uint32_t prev_code_len = s->prev_code_len;
-  uint32_t repeat_code_len = s->repeat_code_len;
-  uint16_t* symbol_lists = s->symbol_lists;
-  uint16_t* code_length_histo = s->code_length_histo;
-  int* next_symbol = s->next_symbol;
+  BrotliMetablockHeaderArena* h = &s->arena.header;
+  uint32_t symbol = h->symbol;
+  uint32_t repeat = h->repeat;
+  uint32_t space = h->space;
+  uint32_t prev_code_len = h->prev_code_len;
+  uint32_t repeat_code_len = h->repeat_code_len;
+  uint16_t* symbol_lists = h->symbol_lists;
+  uint16_t* code_length_histo = h->code_length_histo;
+  int* next_symbol = h->next_symbol;
   if (!BrotliWarmupBitReader(br)) {
     return BROTLI_DECODER_NEEDS_MORE_INPUT;
   }
   while (symbol < alphabet_size && space > 0) {
-    const HuffmanCode* p = s->table;
+    const HuffmanCode* p = h->table;
     uint32_t code_len;
     BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(p);
     if (!BrotliCheckInputAmount(br, BROTLI_SHORT_FILL_BIT_WINDOW_READ)) {
-      s->symbol = symbol;
-      s->repeat = repeat;
-      s->prev_code_len = prev_code_len;
-      s->repeat_code_len = repeat_code_len;
-      s->space = space;
+      h->symbol = symbol;
+      h->repeat = repeat;
+      h->prev_code_len = prev_code_len;
+      h->repeat_code_len = repeat_code_len;
+      h->space = space;
       return BROTLI_DECODER_NEEDS_MORE_INPUT;
     }
     BrotliFillBitWindow16(br);
@@ -630,16 +636,17 @@
           symbol_lists, code_length_histo, next_symbol);
     }
   }
-  s->space = space;
+  h->space = space;
   return BROTLI_DECODER_SUCCESS;
 }
 
 static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
     uint32_t alphabet_size, BrotliDecoderState* s) {
   BrotliBitReader* br = &s->br;
+  BrotliMetablockHeaderArena* h = &s->arena.header;
   BROTLI_BOOL get_byte = BROTLI_FALSE;
-  while (s->symbol < alphabet_size && s->space > 0) {
-    const HuffmanCode* p = s->table;
+  while (h->symbol < alphabet_size && h->space > 0) {
+    const HuffmanCode* p = h->table;
     uint32_t code_len;
     uint32_t available_bits;
     uint32_t bits = 0;
@@ -659,9 +666,9 @@
     code_len = BROTLI_HC_FAST_LOAD_VALUE(p);  /* code_len == 0..17 */
     if (code_len < BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) {
       BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p));
-      ProcessSingleCodeLength(code_len, &s->symbol, &s->repeat, &s->space,
-          &s->prev_code_len, s->symbol_lists, s->code_length_histo,
-          s->next_symbol);
+      ProcessSingleCodeLength(code_len, &h->symbol, &h->repeat, &h->space,
+          &h->prev_code_len, h->symbol_lists, h->code_length_histo,
+          h->next_symbol);
     } else {  /* code_len == 16..17, extra_bits == 2..3 */
       uint32_t extra_bits = code_len - 14U;
       uint32_t repeat_delta = (bits >> BROTLI_HC_FAST_LOAD_BITS(p)) &
@@ -672,9 +679,9 @@
       }
       BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p) + extra_bits);
       ProcessRepeatedCodeLength(code_len, repeat_delta, alphabet_size,
-          &s->symbol, &s->repeat, &s->space, &s->prev_code_len,
-          &s->repeat_code_len, s->symbol_lists, s->code_length_histo,
-          s->next_symbol);
+          &h->symbol, &h->repeat, &h->space, &h->prev_code_len,
+          &h->repeat_code_len, h->symbol_lists, h->code_length_histo,
+          h->next_symbol);
     }
   }
   return BROTLI_DECODER_SUCCESS;
@@ -684,9 +691,10 @@
    Each code is 2..4 bits long. In total 30..72 bits are used. */
 static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) {
   BrotliBitReader* br = &s->br;
-  uint32_t num_codes = s->repeat;
-  unsigned space = s->space;
-  uint32_t i = s->sub_loop_counter;
+  BrotliMetablockHeaderArena* h = &s->arena.header;
+  uint32_t num_codes = h->repeat;
+  unsigned space = h->space;
+  uint32_t i = h->sub_loop_counter;
   for (; i < BROTLI_CODE_LENGTH_CODES; ++i) {
     const uint8_t code_len_idx = kCodeLengthCodeOrder[i];
     uint32_t ix;
@@ -699,21 +707,21 @@
         ix = 0;
       }
       if (kCodeLengthPrefixLength[ix] > available_bits) {
-        s->sub_loop_counter = i;
-        s->repeat = num_codes;
-        s->space = space;
-        s->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
+        h->sub_loop_counter = i;
+        h->repeat = num_codes;
+        h->space = space;
+        h->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
         return BROTLI_DECODER_NEEDS_MORE_INPUT;
       }
     }
     v = kCodeLengthPrefixValue[ix];
     BrotliDropBits(br, kCodeLengthPrefixLength[ix]);
-    s->code_length_code_lengths[code_len_idx] = (uint8_t)v;
-    BROTLI_LOG_ARRAY_INDEX(s->code_length_code_lengths, code_len_idx);
+    h->code_length_code_lengths[code_len_idx] = (uint8_t)v;
+    BROTLI_LOG_ARRAY_INDEX(h->code_length_code_lengths, code_len_idx);
     if (v != 0) {
       space = space - (32U >> v);
       ++num_codes;
-      ++s->code_length_histo[v];
+      ++h->code_length_histo[v];
       if (space - 1U >= 32U) {
         /* space is 0 or wrapped around. */
         break;
@@ -737,49 +745,48 @@
          encoded with predefined entropy code. 32 - 74 bits are used.
     B.2) Decoded table is used to decode code lengths of symbols in resulting
          Huffman table. In worst case 3520 bits are read. */
-static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size,
-                                              uint32_t max_symbol,
+static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size_max,
+                                              uint32_t alphabet_size_limit,
                                               HuffmanCode* table,
                                               uint32_t* opt_table_size,
                                               BrotliDecoderState* s) {
   BrotliBitReader* br = &s->br;
-  /* Unnecessary masking, but might be good for safety. */
-  alphabet_size &= 0x7FF;
+  BrotliMetablockHeaderArena* h = &s->arena.header;
   /* State machine. */
   for (;;) {
-    switch (s->substate_huffman) {
+    switch (h->substate_huffman) {
       case BROTLI_STATE_HUFFMAN_NONE:
-        if (!BrotliSafeReadBits(br, 2, &s->sub_loop_counter)) {
+        if (!BrotliSafeReadBits(br, 2, &h->sub_loop_counter)) {
           return BROTLI_DECODER_NEEDS_MORE_INPUT;
         }
-        BROTLI_LOG_UINT(s->sub_loop_counter);
+        BROTLI_LOG_UINT(h->sub_loop_counter);
         /* The value is used as follows:
            1 for simple code;
            0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */
-        if (s->sub_loop_counter != 1) {
-          s->space = 32;
-          s->repeat = 0;  /* num_codes */
-          memset(&s->code_length_histo[0], 0, sizeof(s->code_length_histo[0]) *
+        if (h->sub_loop_counter != 1) {
+          h->space = 32;
+          h->repeat = 0;  /* num_codes */
+          memset(&h->code_length_histo[0], 0, sizeof(h->code_length_histo[0]) *
               (BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH + 1));
-          memset(&s->code_length_code_lengths[0], 0,
-              sizeof(s->code_length_code_lengths));
-          s->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
+          memset(&h->code_length_code_lengths[0], 0,
+              sizeof(h->code_length_code_lengths));
+          h->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
           continue;
         }
       /* Fall through. */
 
       case BROTLI_STATE_HUFFMAN_SIMPLE_SIZE:
         /* Read symbols, codes & code lengths directly. */
-        if (!BrotliSafeReadBits(br, 2, &s->symbol)) {  /* num_symbols */
-          s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_SIZE;
+        if (!BrotliSafeReadBits(br, 2, &h->symbol)) {  /* num_symbols */
+          h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_SIZE;
           return BROTLI_DECODER_NEEDS_MORE_INPUT;
         }
-        s->sub_loop_counter = 0;
+        h->sub_loop_counter = 0;
       /* Fall through. */
 
       case BROTLI_STATE_HUFFMAN_SIMPLE_READ: {
         BrotliDecoderErrorCode result =
-            ReadSimpleHuffmanSymbols(alphabet_size, max_symbol, s);
+            ReadSimpleHuffmanSymbols(alphabet_size_max, alphabet_size_limit, s);
         if (result != BROTLI_DECODER_SUCCESS) {
           return result;
         }
@@ -788,21 +795,21 @@
 
       case BROTLI_STATE_HUFFMAN_SIMPLE_BUILD: {
         uint32_t table_size;
-        if (s->symbol == 3) {
+        if (h->symbol == 3) {
           uint32_t bits;
           if (!BrotliSafeReadBits(br, 1, &bits)) {
-            s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_BUILD;
+            h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_BUILD;
             return BROTLI_DECODER_NEEDS_MORE_INPUT;
           }
-          s->symbol += bits;
+          h->symbol += bits;
         }
-        BROTLI_LOG_UINT(s->symbol);
+        BROTLI_LOG_UINT(h->symbol);
         table_size = BrotliBuildSimpleHuffmanTable(
-            table, HUFFMAN_TABLE_BITS, s->symbols_lists_array, s->symbol);
+            table, HUFFMAN_TABLE_BITS, h->symbols_lists_array, h->symbol);
         if (opt_table_size) {
           *opt_table_size = table_size;
         }
-        s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
+        h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
         return BROTLI_DECODER_SUCCESS;
       }
 
@@ -813,44 +820,45 @@
         if (result != BROTLI_DECODER_SUCCESS) {
           return result;
         }
-        BrotliBuildCodeLengthsHuffmanTable(s->table,
-                                           s->code_length_code_lengths,
-                                           s->code_length_histo);
-        memset(&s->code_length_histo[0], 0, sizeof(s->code_length_histo));
+        BrotliBuildCodeLengthsHuffmanTable(h->table,
+                                           h->code_length_code_lengths,
+                                           h->code_length_histo);
+        memset(&h->code_length_histo[0], 0, sizeof(h->code_length_histo));
         for (i = 0; i <= BROTLI_HUFFMAN_MAX_CODE_LENGTH; ++i) {
-          s->next_symbol[i] = (int)i - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
-          s->symbol_lists[s->next_symbol[i]] = 0xFFFF;
+          h->next_symbol[i] = (int)i - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
+          h->symbol_lists[h->next_symbol[i]] = 0xFFFF;
         }
 
-        s->symbol = 0;
-        s->prev_code_len = BROTLI_INITIAL_REPEATED_CODE_LENGTH;
-        s->repeat = 0;
-        s->repeat_code_len = 0;
-        s->space = 32768;
-        s->substate_huffman = BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS;
+        h->symbol = 0;
+        h->prev_code_len = BROTLI_INITIAL_REPEATED_CODE_LENGTH;
+        h->repeat = 0;
+        h->repeat_code_len = 0;
+        h->space = 32768;
+        h->substate_huffman = BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS;
       }
       /* Fall through. */
 
       case BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS: {
         uint32_t table_size;
-        BrotliDecoderErrorCode result = ReadSymbolCodeLengths(max_symbol, s);
+        BrotliDecoderErrorCode result = ReadSymbolCodeLengths(
+            alphabet_size_limit, s);
         if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) {
-          result = SafeReadSymbolCodeLengths(max_symbol, s);
+          result = SafeReadSymbolCodeLengths(alphabet_size_limit, s);
         }
         if (result != BROTLI_DECODER_SUCCESS) {
           return result;
         }
 
-        if (s->space != 0) {
-          BROTLI_LOG(("[ReadHuffmanCode] space = %d\n", (int)s->space));
+        if (h->space != 0) {
+          BROTLI_LOG(("[ReadHuffmanCode] space = %d\n", (int)h->space));
           return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE);
         }
         table_size = BrotliBuildHuffmanTable(
-            table, HUFFMAN_TABLE_BITS, s->symbol_lists, s->code_length_histo);
+            table, HUFFMAN_TABLE_BITS, h->symbol_lists, h->code_length_histo);
         if (opt_table_size) {
           *opt_table_size = table_size;
         }
-        s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
+        h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
         return BROTLI_DECODER_SUCCESS;
       }
 
@@ -867,8 +875,8 @@
   uint32_t code;
   uint32_t nbits;
   code = ReadSymbol(table, br);
-  nbits = kBlockLengthPrefixCode[code].nbits;  /* nbits == 2..24 */
-  return kBlockLengthPrefixCode[code].offset + BrotliReadBits(br, nbits);
+  nbits = _kBrotliPrefixCodeRanges[code].nbits;  /* nbits == 2..24 */
+  return _kBrotliPrefixCodeRanges[code].offset + BrotliReadBits24(br, nbits);
 }
 
 /* WARNING: if state is not BROTLI_STATE_READ_BLOCK_LENGTH_NONE, then
@@ -886,13 +894,14 @@
   }
   {
     uint32_t bits;
-    uint32_t nbits = kBlockLengthPrefixCode[index].nbits;  /* nbits == 2..24 */
+    uint32_t nbits = _kBrotliPrefixCodeRanges[index].nbits;
+    uint32_t offset = _kBrotliPrefixCodeRanges[index].offset;
     if (!BrotliSafeReadBits(br, nbits, &bits)) {
       s->block_length_index = index;
       s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX;
       return BROTLI_FALSE;
     }
-    *result = kBlockLengthPrefixCode[index].offset + bits;
+    *result = offset + bits;
     s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
     return BROTLI_TRUE;
   }
@@ -952,22 +961,22 @@
 /* Decodes a series of Huffman table using ReadHuffmanCode function. */
 static BrotliDecoderErrorCode HuffmanTreeGroupDecode(
     HuffmanTreeGroup* group, BrotliDecoderState* s) {
-  if (s->substate_tree_group != BROTLI_STATE_TREE_GROUP_LOOP) {
-    s->next = group->codes;
-    s->htree_index = 0;
-    s->substate_tree_group = BROTLI_STATE_TREE_GROUP_LOOP;
+  BrotliMetablockHeaderArena* h = &s->arena.header;
+  if (h->substate_tree_group != BROTLI_STATE_TREE_GROUP_LOOP) {
+    h->next = group->codes;
+    h->htree_index = 0;
+    h->substate_tree_group = BROTLI_STATE_TREE_GROUP_LOOP;
   }
-  while (s->htree_index < group->num_htrees) {
+  while (h->htree_index < group->num_htrees) {
     uint32_t table_size;
-    BrotliDecoderErrorCode result =
-        ReadHuffmanCode(group->alphabet_size, group->max_symbol,
-                        s->next, &table_size, s);
+    BrotliDecoderErrorCode result = ReadHuffmanCode(group->alphabet_size_max,
+        group->alphabet_size_limit, h->next, &table_size, s);
     if (result != BROTLI_DECODER_SUCCESS) return result;
-    group->htrees[s->htree_index] = s->next;
-    s->next += table_size;
-    ++s->htree_index;
+    group->htrees[h->htree_index] = h->next;
+    h->next += table_size;
+    ++h->htree_index;
   }
-  s->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
+  h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
   return BROTLI_DECODER_SUCCESS;
 }
 
@@ -985,15 +994,16 @@
                                                BrotliDecoderState* s) {
   BrotliBitReader* br = &s->br;
   BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS;
+  BrotliMetablockHeaderArena* h = &s->arena.header;
 
-  switch ((int)s->substate_context_map) {
+  switch ((int)h->substate_context_map) {
     case BROTLI_STATE_CONTEXT_MAP_NONE:
       result = DecodeVarLenUint8(s, br, num_htrees);
       if (result != BROTLI_DECODER_SUCCESS) {
         return result;
       }
       (*num_htrees)++;
-      s->context_index = 0;
+      h->context_index = 0;
       BROTLI_LOG_UINT(context_map_size);
       BROTLI_LOG_UINT(*num_htrees);
       *context_map_arg =
@@ -1005,7 +1015,7 @@
         memset(*context_map_arg, 0, (size_t)context_map_size);
         return BROTLI_DECODER_SUCCESS;
       }
-      s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_READ_PREFIX;
+      h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_READ_PREFIX;
     /* Fall through. */
 
     case BROTLI_STATE_CONTEXT_MAP_READ_PREFIX: {
@@ -1016,38 +1026,38 @@
         return BROTLI_DECODER_NEEDS_MORE_INPUT;
       }
       if ((bits & 1) != 0) { /* Use RLE for zeros. */
-        s->max_run_length_prefix = (bits >> 1) + 1;
+        h->max_run_length_prefix = (bits >> 1) + 1;
         BrotliDropBits(br, 5);
       } else {
-        s->max_run_length_prefix = 0;
+        h->max_run_length_prefix = 0;
         BrotliDropBits(br, 1);
       }
-      BROTLI_LOG_UINT(s->max_run_length_prefix);
-      s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_HUFFMAN;
+      BROTLI_LOG_UINT(h->max_run_length_prefix);
+      h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_HUFFMAN;
     }
     /* Fall through. */
 
     case BROTLI_STATE_CONTEXT_MAP_HUFFMAN: {
-      uint32_t alphabet_size = *num_htrees + s->max_run_length_prefix;
+      uint32_t alphabet_size = *num_htrees + h->max_run_length_prefix;
       result = ReadHuffmanCode(alphabet_size, alphabet_size,
-                               s->context_map_table, NULL, s);
+                               h->context_map_table, NULL, s);
       if (result != BROTLI_DECODER_SUCCESS) return result;
-      s->code = 0xFFFF;
-      s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_DECODE;
+      h->code = 0xFFFF;
+      h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_DECODE;
     }
     /* Fall through. */
 
     case BROTLI_STATE_CONTEXT_MAP_DECODE: {
-      uint32_t context_index = s->context_index;
-      uint32_t max_run_length_prefix = s->max_run_length_prefix;
+      uint32_t context_index = h->context_index;
+      uint32_t max_run_length_prefix = h->max_run_length_prefix;
       uint8_t* context_map = *context_map_arg;
-      uint32_t code = s->code;
+      uint32_t code = h->code;
       BROTLI_BOOL skip_preamble = (code != 0xFFFF);
       while (context_index < context_map_size || skip_preamble) {
         if (!skip_preamble) {
-          if (!SafeReadSymbol(s->context_map_table, br, &code)) {
-            s->code = 0xFFFF;
-            s->context_index = context_index;
+          if (!SafeReadSymbol(h->context_map_table, br, &code)) {
+            h->code = 0xFFFF;
+            h->context_index = context_index;
             return BROTLI_DECODER_NEEDS_MORE_INPUT;
           }
           BROTLI_LOG_UINT(code);
@@ -1068,8 +1078,8 @@
         {
           uint32_t reps;
           if (!BrotliSafeReadBits(br, code, &reps)) {
-            s->code = code;
-            s->context_index = context_index;
+            h->code = code;
+            h->context_index = context_index;
             return BROTLI_DECODER_NEEDS_MORE_INPUT;
           }
           reps += 1U << code;
@@ -1089,13 +1099,13 @@
     case BROTLI_STATE_CONTEXT_MAP_TRANSFORM: {
       uint32_t bits;
       if (!BrotliSafeReadBits(br, 1, &bits)) {
-        s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_TRANSFORM;
+        h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_TRANSFORM;
         return BROTLI_DECODER_NEEDS_MORE_INPUT;
       }
       if (bits != 0) {
         InverseMoveToFrontTransform(*context_map_arg, context_map_size, s);
       }
-      s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
+      h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
       return BROTLI_DECODER_SUCCESS;
     }
 
@@ -1457,32 +1467,28 @@
 }
 
 static BROTLI_INLINE void TakeDistanceFromRingBuffer(BrotliDecoderState* s) {
-  if (s->distance_code == 0) {
-    --s->dist_rb_idx;
-    s->distance_code = s->dist_rb[s->dist_rb_idx & 3];
+  int offset = s->distance_code - 3;
+  if (s->distance_code <= 3) {
     /* Compensate double distance-ring-buffer roll for dictionary items. */
-    s->distance_context = 1;
+    s->distance_context = 1 >> s->distance_code;
+    s->distance_code = s->dist_rb[(s->dist_rb_idx - offset) & 3];
+    s->dist_rb_idx -= s->distance_context;
   } else {
-    int distance_code = s->distance_code << 1;
-    /* kDistanceShortCodeIndexOffset has 2-bit values from LSB:
-        3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 */
-    const uint32_t kDistanceShortCodeIndexOffset = 0xAAAFFF1B;
-    /* kDistanceShortCodeValueOffset has 2-bit values from LSB:
-       -0, 0,-0, 0,-1, 1,-2, 2,-3, 3,-1, 1,-2, 2,-3, 3 */
-    const uint32_t kDistanceShortCodeValueOffset = 0xFA5FA500;
-    int v = (s->dist_rb_idx +
-        (int)(kDistanceShortCodeIndexOffset >> distance_code)) & 0x3;
-    s->distance_code = s->dist_rb[v];
-    v = (int)(kDistanceShortCodeValueOffset >> distance_code) & 0x3;
-    if ((distance_code & 0x3) != 0) {
-      s->distance_code += v;
+    int index_delta = 3;
+    int delta;
+    int base = s->distance_code - 10;
+    if (s->distance_code < 10) {
+      base = s->distance_code - 4;
     } else {
-      s->distance_code -= v;
-      if (s->distance_code <= 0) {
-        /* A huge distance will cause a BROTLI_FAILURE() soon.
-           This is a little faster than failing here. */
-        s->distance_code = 0x7FFFFFFF;
-      }
+      index_delta = 2;
+    }
+    /* Unpack one of six 4-bit values. */
+    delta = ((0x605142 >> (4 * base)) & 0xF) - 3;
+    s->distance_code = s->dist_rb[(s->dist_rb_idx + index_delta) & 0x3] + delta;
+    if (s->distance_code <= 0) {
+      /* A huge distance will cause a BROTLI_FAILURE() soon.
+         This is a little faster than failing here. */
+      s->distance_code = 0x7FFFFFFF;
     }
   }
 }
@@ -1497,62 +1503,153 @@
   }
 }
 
+static BROTLI_INLINE BROTLI_BOOL SafeReadBits32(
+    BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
+  if (n_bits != 0) {
+    return BrotliSafeReadBits32(br, n_bits, val);
+  } else {
+    *val = 0;
+    return BROTLI_TRUE;
+  }
+}
+
+/*
+   RFC 7932 Section 4 with "..." shortenings and "[]" emendations.
+
+   Each distance ... is represented with a pair <distance code, extra bits>...
+   The distance code is encoded using a prefix code... The number of extra bits
+   can be 0..24... Two additional parameters: NPOSTFIX (0..3), and ...
+   NDIRECT (0..120) ... are encoded in the meta-block header...
+
+   The first 16 distance symbols ... reference past distances... ring buffer ...
+   Next NDIRECT distance symbols ... represent distances from 1 to NDIRECT...
+   [For] distance symbols 16 + NDIRECT and greater ... the number of extra bits
+   ... is given by the following formula:
+
+   [ xcode = dcode - NDIRECT - 16 ]
+   ndistbits = 1 + [ xcode ] >> (NPOSTFIX + 1)
+
+   ...
+*/
+
+/*
+   RFC 7932 Section 9.2 with "..." shortenings and "[]" emendations.
+
+   ... to get the actual value of the parameter NDIRECT, left-shift this
+   four-bit number by NPOSTFIX bits ...
+*/
+
+/* Remaining formulas from RFC 7932 Section 4 could be rewritten as following:
+
+     alphabet_size = 16 + NDIRECT + (max_distbits << (NPOSTFIX + 1))
+
+     half = ((xcode >> NPOSTFIX) & 1) << ndistbits
+     postfix = xcode & ((1 << NPOSTFIX) - 1)
+     range_start = 2 * (1 << ndistbits - 1 - 1)
+
+     distance = (range_start + half + extra) << NPOSTFIX + postfix + NDIRECT + 1
+
+   NB: ndistbits >= 1 -> range_start >= 0
+   NB: range_start has factor 2, as the range is covered by 2 "halves"
+   NB: extra -1 offset in range_start formula covers the absence of
+       ndistbits = 0 case
+   NB: when NPOSTFIX = 0, NDIRECT is not greater than 15
+
+   In other words, xcode has the following binary structure - XXXHPPP:
+    - XXX represent the number of extra distance bits
+    - H selects upper / lower range of distances
+    - PPP represent "postfix"
+
+  "Regular" distance encoding has NPOSTFIX = 0; omitting the postfix part
+  simplifies distance calculation.
+
+  Using NPOSTFIX > 0 allows cheaper encoding of regular structures, e.g. where
+  most of distances have the same reminder of division by 2/4/8. For example,
+  the table of int32_t values that come from different sources; if it is likely
+  that 3 highest bytes of values from the same source are the same, then
+  copy distance often looks like 4x + y.
+
+  Distance calculation could be rewritten to:
+
+    ndistbits = NDISTBITS(NDIRECT, NPOSTFIX)[dcode]
+    distance = OFFSET(NDIRECT, NPOSTFIX)[dcode] + extra << NPOSTFIX
+
+  NDISTBITS and OFFSET could be pre-calculated, as NDIRECT and NPOSTFIX could
+  change only once per meta-block.
+*/
+
+/* Calculates distance lookup table.
+   NB: it is possible to have all 64 tables precalculated. */
+static void CalculateDistanceLut(BrotliDecoderState* s) {
+  BrotliMetablockBodyArena* b = &s->arena.body;
+  uint32_t npostfix = s->distance_postfix_bits;
+  uint32_t ndirect = s->num_direct_distance_codes;
+  uint32_t alphabet_size_limit = s->distance_hgroup.alphabet_size_limit;
+  uint32_t postfix = 1u << npostfix;
+  uint32_t j;
+  uint32_t bits = 1;
+  uint32_t half = 0;
+
+  /* Skip short codes. */
+  uint32_t i = BROTLI_NUM_DISTANCE_SHORT_CODES;
+
+  /* Fill direct codes. */
+  for (j = 0; j < ndirect; ++j) {
+    b->dist_extra_bits[i] = 0;
+    b->dist_offset[i] = j + 1;
+    ++i;
+  }
+
+  /* Fill regular distance codes. */
+  while (i < alphabet_size_limit) {
+    uint32_t base = ndirect + ((((2 + half) << bits) - 4) << npostfix) + 1;
+    /* Always fill the complete group. */
+    for (j = 0; j < postfix; ++j) {
+      b->dist_extra_bits[i] = (uint8_t)bits;
+      b->dist_offset[i] = base + j;
+      ++i;
+    }
+    bits = bits + half;
+    half = half ^ 1;
+  }
+}
+
 /* Precondition: s->distance_code < 0. */
 static BROTLI_INLINE BROTLI_BOOL ReadDistanceInternal(
     int safe, BrotliDecoderState* s, BrotliBitReader* br) {
-  int distval;
+  BrotliMetablockBodyArena* b = &s->arena.body;
+  uint32_t code;
+  uint32_t bits;
   BrotliBitReaderState memento;
   HuffmanCode* distance_tree = s->distance_hgroup.htrees[s->dist_htree_index];
   if (!safe) {
-    s->distance_code = (int)ReadSymbol(distance_tree, br);
+    code = ReadSymbol(distance_tree, br);
   } else {
-    uint32_t code;
     BrotliBitReaderSaveState(br, &memento);
     if (!SafeReadSymbol(distance_tree, br, &code)) {
       return BROTLI_FALSE;
     }
-    s->distance_code = (int)code;
   }
+  --s->block_length[2];
   /* Convert the distance code to the actual distance by possibly
-     looking up past distances from the s->ringbuffer. */
+     looking up past distances from the s->dist_rb. */
   s->distance_context = 0;
-  if ((s->distance_code & ~0xF) == 0) {
+  if ((code & ~0xFu) == 0) {
+    s->distance_code = (int)code;
     TakeDistanceFromRingBuffer(s);
-    --s->block_length[2];
     return BROTLI_TRUE;
   }
-  distval = s->distance_code - (int)s->num_direct_distance_codes;
-  if (distval >= 0) {
-    uint32_t nbits;
-    int postfix;
-    int offset;
-    if (!safe && (s->distance_postfix_bits == 0)) {
-      nbits = ((uint32_t)distval >> 1) + 1;
-      offset = ((2 + (distval & 1)) << nbits) - 4;
-      s->distance_code = (int)s->num_direct_distance_codes + offset +
-                         (int)BrotliReadBits(br, nbits);
-    } else {
-      /* This branch also works well when s->distance_postfix_bits == 0. */
-      uint32_t bits;
-      postfix = distval & s->distance_postfix_mask;
-      distval >>= s->distance_postfix_bits;
-      nbits = ((uint32_t)distval >> 1) + 1;
-      if (safe) {
-        if (!SafeReadBits(br, nbits, &bits)) {
-          s->distance_code = -1;  /* Restore precondition. */
-          BrotliBitReaderRestoreState(br, &memento);
-          return BROTLI_FALSE;
-        }
-      } else {
-        bits = BrotliReadBits(br, nbits);
-      }
-      offset = ((2 + (distval & 1)) << nbits) - 4;
-      s->distance_code = (int)s->num_direct_distance_codes +
-          ((offset + (int)bits) << s->distance_postfix_bits) + postfix;
+  if (!safe) {
+    bits = BrotliReadBits32(br, b->dist_extra_bits[code]);
+  } else {
+    if (!SafeReadBits32(br, b->dist_extra_bits[code], &bits)) {
+      ++s->block_length[2];
+      BrotliBitReaderRestoreState(br, &memento);
+      return BROTLI_FALSE;
     }
   }
-  s->distance_code = s->distance_code - BROTLI_NUM_DISTANCE_SHORT_CODES + 1;
-  --s->block_length[2];
+  s->distance_code =
+      (int)(b->dist_offset[code] + (bits << s->distance_postfix_bits));
   return BROTLI_TRUE;
 }
 
@@ -1588,9 +1685,9 @@
   *insert_length = v.insert_len_offset;
   if (!safe) {
     if (BROTLI_PREDICT_FALSE(v.insert_len_extra_bits != 0)) {
-      insert_len_extra = BrotliReadBits(br, v.insert_len_extra_bits);
+      insert_len_extra = BrotliReadBits24(br, v.insert_len_extra_bits);
     }
-    copy_length = BrotliReadBits(br, v.copy_len_extra_bits);
+    copy_length = BrotliReadBits24(br, v.copy_len_extra_bits);
   } else {
     if (!SafeReadBits(br, v.insert_len_extra_bits, &insert_len_extra) ||
         !SafeReadBits(br, v.copy_len_extra_bits, &copy_length)) {
@@ -1935,21 +2032,6 @@
   return ProcessCommandsInternal(1, s);
 }
 
-/* Returns the maximum number of distance symbols which can only represent
-   distances not exceeding BROTLI_MAX_ALLOWED_DISTANCE. */
-static uint32_t BrotliMaxDistanceSymbol(uint32_t ndirect, uint32_t npostfix) {
-  static const uint32_t bound[BROTLI_MAX_NPOSTFIX + 1] = {0, 4, 12, 28};
-  static const uint32_t diff[BROTLI_MAX_NPOSTFIX + 1] = {73, 126, 228, 424};
-  uint32_t postfix = 1U << npostfix;
-  if (ndirect < bound[npostfix]) {
-    return ndirect + diff[npostfix] + postfix;
-  } else if (ndirect > bound[npostfix] + postfix) {
-    return ndirect + diff[npostfix];
-  } else {
-    return bound[npostfix] + diff[npostfix] + postfix;
-  }
-}
-
 BrotliDecoderResult BrotliDecoderDecompress(
     size_t encoded_size, const uint8_t* encoded_buffer, size_t* decoded_size,
     uint8_t* decoded_buffer) {
@@ -2167,33 +2249,23 @@
           s->state = BROTLI_STATE_UNCOMPRESSED;
           break;
         }
+        s->state = BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER;
+      /* Fall through. */
+
+      case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER: {
+        BrotliMetablockHeaderArena* h = &s->arena.header;
         s->loop_counter = 0;
+        /* Initialize compressed metablock header arena. */
+        h->sub_loop_counter = 0;
+        /* Make small negative indexes addressable. */
+        h->symbol_lists =
+            &h->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1];
+        h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
+        h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
+        h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
         s->state = BROTLI_STATE_HUFFMAN_CODE_0;
-        break;
-
-      case BROTLI_STATE_UNCOMPRESSED: {
-        result = CopyUncompressedBlockToOutput(
-            available_out, next_out, total_out, s);
-        if (result != BROTLI_DECODER_SUCCESS) {
-          break;
-        }
-        s->state = BROTLI_STATE_METABLOCK_DONE;
-        break;
       }
-
-      case BROTLI_STATE_METADATA:
-        for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) {
-          uint32_t bits;
-          /* Read one byte and ignore it. */
-          if (!BrotliSafeReadBits(br, 8, &bits)) {
-            result = BROTLI_DECODER_NEEDS_MORE_INPUT;
-            break;
-          }
-        }
-        if (result == BROTLI_DECODER_SUCCESS) {
-          s->state = BROTLI_STATE_METABLOCK_DONE;
-        }
-        break;
+      /* Fall through. */
 
       case BROTLI_STATE_HUFFMAN_CODE_0:
         if (s->loop_counter >= 3) {
@@ -2247,6 +2319,30 @@
         break;
       }
 
+      case BROTLI_STATE_UNCOMPRESSED: {
+        result = CopyUncompressedBlockToOutput(
+            available_out, next_out, total_out, s);
+        if (result != BROTLI_DECODER_SUCCESS) {
+          break;
+        }
+        s->state = BROTLI_STATE_METABLOCK_DONE;
+        break;
+      }
+
+      case BROTLI_STATE_METADATA:
+        for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) {
+          uint32_t bits;
+          /* Read one byte and ignore it. */
+          if (!BrotliSafeReadBits(br, 8, &bits)) {
+            result = BROTLI_DECODER_NEEDS_MORE_INPUT;
+            break;
+          }
+        }
+        if (result == BROTLI_DECODER_SUCCESS) {
+          s->state = BROTLI_STATE_METABLOCK_DONE;
+        }
+        break;
+
       case BROTLI_STATE_METABLOCK_HEADER_2: {
         uint32_t bits;
         if (!BrotliSafeReadBits(br, 6, &bits)) {
@@ -2255,11 +2351,9 @@
         }
         s->distance_postfix_bits = bits & BitMask(2);
         bits >>= 2;
-        s->num_direct_distance_codes = BROTLI_NUM_DISTANCE_SHORT_CODES +
-            (bits << s->distance_postfix_bits);
+        s->num_direct_distance_codes = bits << s->distance_postfix_bits;
         BROTLI_LOG_UINT(s->num_direct_distance_codes);
         BROTLI_LOG_UINT(s->distance_postfix_bits);
-        s->distance_postfix_mask = (int)BitMask(s->distance_postfix_bits);
         s->context_modes =
             (uint8_t*)BROTLI_DECODER_ALLOC(s, (size_t)s->num_block_types[0]);
         if (s->context_modes == 0) {
@@ -2291,17 +2385,19 @@
       /* Fall through. */
 
       case BROTLI_STATE_CONTEXT_MAP_2: {
-        uint32_t num_direct_codes =
-            s->num_direct_distance_codes - BROTLI_NUM_DISTANCE_SHORT_CODES;
-        uint32_t num_distance_codes = BROTLI_DISTANCE_ALPHABET_SIZE(
-            s->distance_postfix_bits, num_direct_codes,
-            (s->large_window ? BROTLI_LARGE_MAX_DISTANCE_BITS :
-                               BROTLI_MAX_DISTANCE_BITS));
-        uint32_t max_distance_symbol = (s->large_window ?
-            BrotliMaxDistanceSymbol(
-                num_direct_codes, s->distance_postfix_bits) :
-            num_distance_codes);
+        uint32_t npostfix = s->distance_postfix_bits;
+        uint32_t ndirect = s->num_direct_distance_codes;
+        uint32_t distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
+            npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
+        uint32_t distance_alphabet_size_limit = distance_alphabet_size_max;
         BROTLI_BOOL allocation_success = BROTLI_TRUE;
+        if (s->large_window) {
+          BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit(
+              BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect);
+          distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
+              npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
+          distance_alphabet_size_limit = limit.max_alphabet_size;
+        }
         result = DecodeContextMap(
             s->num_block_types[2] << BROTLI_DISTANCE_CONTEXT_BITS,
             &s->num_dist_htrees, &s->dist_context_map, s);
@@ -2315,8 +2411,8 @@
             s, &s->insert_copy_hgroup, BROTLI_NUM_COMMAND_SYMBOLS,
             BROTLI_NUM_COMMAND_SYMBOLS, s->num_block_types[1]);
         allocation_success &= BrotliDecoderHuffmanTreeGroupInit(
-            s, &s->distance_hgroup, num_distance_codes,
-            max_distance_symbol, s->num_dist_htrees);
+            s, &s->distance_hgroup, distance_alphabet_size_max,
+            distance_alphabet_size_limit, s->num_dist_htrees);
         if (!allocation_success) {
           return SaveErrorCode(s,
               BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS));
@@ -2338,18 +2434,24 @@
         result = HuffmanTreeGroupDecode(hgroup, s);
         if (result != BROTLI_DECODER_SUCCESS) break;
         s->loop_counter++;
-        if (s->loop_counter >= 3) {
-          PrepareLiteralDecoding(s);
-          s->dist_context_map_slice = s->dist_context_map;
-          s->htree_command = s->insert_copy_hgroup.htrees[0];
-          if (!BrotliEnsureRingBuffer(s)) {
-            result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2);
-            break;
-          }
-          s->state = BROTLI_STATE_COMMAND_BEGIN;
+        if (s->loop_counter < 3) {
+          break;
         }
-        break;
+        s->state = BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY;
       }
+      /* Fall through. */
+
+      case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY:
+        PrepareLiteralDecoding(s);
+        s->dist_context_map_slice = s->dist_context_map;
+        s->htree_command = s->insert_copy_hgroup.htrees[0];
+        if (!BrotliEnsureRingBuffer(s)) {
+          result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2);
+          break;
+        }
+        CalculateDistanceLut(s);
+        s->state = BROTLI_STATE_COMMAND_BEGIN;
+      /* Fall through. */
 
       case BROTLI_STATE_COMMAND_BEGIN:
       /* Fall through. */
diff --git a/third_party/brotli/dec/huffman.h b/third_party/brotli/dec/huffman.h
index b9f0716c..a8fbc453 100644
--- a/third_party/brotli/dec/huffman.h
+++ b/third_party/brotli/dec/huffman.h
@@ -18,12 +18,6 @@
 
 #define BROTLI_HUFFMAN_MAX_CODE_LENGTH 15
 
-/* Maximum possible Huffman table size for an alphabet size of (index * 32),
-   max code length 15 and root table bits 8. */
-static const uint16_t kMaxHuffmanTableSize[] = {
-  256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822,
-  854, 886, 920, 952, 984, 1016, 1048, 1080, 1112, 1144, 1176, 1208, 1240, 1272,
-  1304, 1336, 1368, 1400, 1432, 1464, 1496, 1528};
 /* BROTLI_NUM_BLOCK_LEN_SYMBOLS == 26 */
 #define BROTLI_HUFFMAN_MAX_SIZE_26 396
 /* BROTLI_MAX_BLOCK_TYPE_SYMBOLS == 258 */
@@ -82,7 +76,7 @@
 
 static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits,
     const uint16_t value) {
-  return ((value & 0xFFFF) << 16) | (bits & 0xFF);
+  return (HuffmanCode) ((value & 0xFFFF) << 16) | (bits & 0xFF);
 }
 
 #define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H) uint32_t __fastload_##H = (*H)
@@ -100,7 +94,7 @@
 /* Builds Huffman lookup table assuming code lengths are in symbol order.
    Returns size of resulting table. */
 BROTLI_INTERNAL uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
-    int root_bits, const uint16_t* const symbol_lists, uint16_t* count_arg);
+    int root_bits, const uint16_t* const symbol_lists, uint16_t* count);
 
 /* Builds a simple Huffman table. The |num_symbols| parameter is to be
    interpreted as follows: 0 means 1 symbol, 1 means 2 symbols,
@@ -110,13 +104,13 @@
     int root_bits, uint16_t* symbols, uint32_t num_symbols);
 
 /* Contains a collection of Huffman trees with the same alphabet size. */
-/* max_symbol is needed due to simple codes since log2(alphabet_size) could be
-   greater than log2(max_symbol). */
+/* alphabet_size_limit is needed due to simple codes, since
+   log2(alphabet_size_max) could be greater than log2(alphabet_size_limit). */
 typedef struct {
   HuffmanCode** htrees;
   HuffmanCode* codes;
-  uint16_t alphabet_size;
-  uint16_t max_symbol;
+  uint16_t alphabet_size_max;
+  uint16_t alphabet_size_limit;
   uint16_t num_htrees;
 } HuffmanTreeGroup;
 
diff --git a/third_party/brotli/dec/prefix.h b/third_party/brotli/dec/prefix.h
index 3ea062d..481a2c791 100644
--- a/third_party/brotli/dec/prefix.h
+++ b/third_party/brotli/dec/prefix.h
@@ -13,24 +13,6 @@
 #include "../common/constants.h"
 #include <brotli/types.h>
 
-/* Represents the range of values belonging to a prefix code:
-   [offset, offset + 2^nbits) */
-struct PrefixCodeRange {
-  uint16_t offset;
-  uint8_t nbits;
-};
-
-static const struct PrefixCodeRange
-    kBlockLengthPrefixCode[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
-  {   1,  2}, {    5,  2}, {  9,   2}, {  13,  2},
-  {  17,  3}, {   25,  3}, {  33,  3}, {  41,  3},
-  {  49,  4}, {   65,  4}, {  81,  4}, {  97,  4},
-  { 113,  5}, {  145,  5}, { 177,  5}, { 209,  5},
-  { 241,  6}, {  305,  6}, { 369,  7}, { 497,  8},
-  { 753,  9}, { 1265, 10}, {2289, 11}, {4337, 12},
-  {8433, 13}, {16625, 24}
-};
-
 typedef struct CmdLutElement {
   uint8_t insert_len_extra_bits;
   uint8_t copy_len_extra_bits;
diff --git a/third_party/brotli/dec/state.c b/third_party/brotli/dec/state.c
index e0b37c2d..f847836 100644
--- a/third_party/brotli/dec/state.c
+++ b/third_party/brotli/dec/state.c
@@ -33,10 +33,7 @@
   s->state = BROTLI_STATE_UNINITED;
   s->large_window = 0;
   s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
-  s->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
-  s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
   s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE;
-  s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
   s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE;
   s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
 
@@ -59,8 +56,6 @@
   s->context_map_slice = NULL;
   s->dist_context_map_slice = NULL;
 
-  s->sub_loop_counter = 0;
-
   s->literal_hgroup.codes = NULL;
   s->literal_hgroup.htrees = NULL;
   s->insert_copy_hgroup.codes = NULL;
@@ -84,9 +79,6 @@
   s->block_type_trees = NULL;
   s->block_len_trees = NULL;
 
-  /* Make small negative indexes addressable. */
-  s->symbol_lists = &s->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1];
-
   s->mtf_upper_bound = 63;
 
   s->dictionary = BrotliGetDictionary();
@@ -142,17 +134,20 @@
 }
 
 BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(BrotliDecoderState* s,
-    HuffmanTreeGroup* group, uint32_t alphabet_size, uint32_t max_symbol,
-    uint32_t ntrees) {
-  /* Pack two allocations into one */
-  const size_t max_table_size = kMaxHuffmanTableSize[(alphabet_size + 31) >> 5];
+    HuffmanTreeGroup* group, uint32_t alphabet_size_max,
+    uint32_t alphabet_size_limit, uint32_t ntrees) {
+  /* 376 = 256 (1-st level table) + 4 + 7 + 15 + 31 + 63 (2-nd level mix-tables)
+     This number is discovered "unlimited" "enough" calculator; it is actually
+     a wee bigger than required in several cases (especially for alphabets with
+     less than 16 symbols). */
+  const size_t max_table_size = alphabet_size_limit + 376;
   const size_t code_size = sizeof(HuffmanCode) * ntrees * max_table_size;
   const size_t htree_size = sizeof(HuffmanCode*) * ntrees;
   /* Pointer alignment is, hopefully, wider than sizeof(HuffmanCode). */
   HuffmanCode** p = (HuffmanCode**)BROTLI_DECODER_ALLOC(s,
       code_size + htree_size);
-  group->alphabet_size = (uint16_t)alphabet_size;
-  group->max_symbol = (uint16_t)max_symbol;
+  group->alphabet_size_max = (uint16_t)alphabet_size_max;
+  group->alphabet_size_limit = (uint16_t)alphabet_size_limit;
   group->num_htrees = (uint16_t)ntrees;
   group->htrees = p;
   group->codes = (HuffmanCode*)(&p[ntrees]);
diff --git a/third_party/brotli/dec/state.h b/third_party/brotli/dec/state.h
index d28b639..54dab69 100644
--- a/third_party/brotli/dec/state.h
+++ b/third_party/brotli/dec/state.h
@@ -21,6 +21,95 @@
 extern "C" {
 #endif
 
+/* Graphviz diagram that describes state transitions:
+
+digraph States {
+  graph [compound=true]
+  concentrate=true
+  node [shape="box"]
+
+  UNINITED -> {LARGE_WINDOW_BITS -> INITIALIZE}
+  subgraph cluster_metablock_workflow {
+    style="rounded"
+    label=< <B>METABLOCK CYCLE</B> >
+    METABLOCK_BEGIN -> METABLOCK_HEADER
+    METABLOCK_HEADER:sw -> METADATA
+    METABLOCK_HEADER:s -> UNCOMPRESSED
+    METABLOCK_HEADER:se -> METABLOCK_DONE:ne
+    METADATA:s -> METABLOCK_DONE:w
+    UNCOMPRESSED:s -> METABLOCK_DONE:n
+    METABLOCK_DONE:e -> METABLOCK_BEGIN:e [constraint="false"]
+  }
+  INITIALIZE -> METABLOCK_BEGIN
+  METABLOCK_DONE -> DONE
+
+  subgraph cluster_compressed_metablock {
+    style="rounded"
+    label=< <B>COMPRESSED METABLOCK</B> >
+
+    subgraph cluster_command {
+      style="rounded"
+      label=< <B>HOT LOOP</B> >
+
+      _METABLOCK_DONE_PORT_ [shape=point style=invis]
+
+      {
+        // Set different shape for nodes returning from "compressed metablock".
+        node [shape=invhouse]; CMD_INNER CMD_POST_DECODE_LITERALS;
+        CMD_POST_WRAP_COPY; CMD_INNER_WRITE; CMD_POST_WRITE_1;
+      }
+
+      CMD_BEGIN -> CMD_INNER -> CMD_POST_DECODE_LITERALS -> CMD_POST_WRAP_COPY
+
+      // IO ("write") nodes are not in the hot loop!
+      CMD_INNER_WRITE [style=dashed]
+      CMD_INNER -> CMD_INNER_WRITE
+      CMD_POST_WRITE_1 [style=dashed]
+      CMD_POST_DECODE_LITERALS -> CMD_POST_WRITE_1
+      CMD_POST_WRITE_2 [style=dashed]
+      CMD_POST_WRAP_COPY -> CMD_POST_WRITE_2
+
+      CMD_POST_WRITE_1 -> CMD_BEGIN:s [constraint="false"]
+      CMD_INNER_WRITE -> {CMD_INNER CMD_POST_DECODE_LITERALS}
+          [constraint="false"]
+      CMD_BEGIN:ne -> CMD_POST_DECODE_LITERALS [constraint="false"]
+      CMD_POST_WRAP_COPY -> CMD_BEGIN [constraint="false"]
+      CMD_POST_DECODE_LITERALS -> CMD_BEGIN:ne [constraint="false"]
+      CMD_POST_WRITE_2 -> CMD_POST_WRAP_COPY [constraint="false"]
+      {rank=same; CMD_BEGIN; CMD_INNER; CMD_POST_DECODE_LITERALS;
+          CMD_POST_WRAP_COPY}
+      {rank=same; CMD_INNER_WRITE; CMD_POST_WRITE_1; CMD_POST_WRITE_2}
+
+      {CMD_INNER CMD_POST_DECODE_LITERALS CMD_POST_WRAP_COPY} ->
+          _METABLOCK_DONE_PORT_ [style=invis]
+      {CMD_INNER_WRITE CMD_POST_WRITE_1} -> _METABLOCK_DONE_PORT_
+          [constraint="false" style=invis]
+    }
+
+    BEFORE_COMPRESSED_METABLOCK_HEADER:s -> HUFFMAN_CODE_0:n
+    HUFFMAN_CODE_0 -> HUFFMAN_CODE_1 -> HUFFMAN_CODE_2 -> HUFFMAN_CODE_3
+    HUFFMAN_CODE_0 -> METABLOCK_HEADER_2 -> CONTEXT_MODES -> CONTEXT_MAP_1
+    CONTEXT_MAP_1 -> CONTEXT_MAP_2 -> TREE_GROUP
+    TREE_GROUP -> BEFORE_COMPRESSED_METABLOCK_BODY:e
+    BEFORE_COMPRESSED_METABLOCK_BODY:s -> CMD_BEGIN:n
+
+    HUFFMAN_CODE_3:e -> HUFFMAN_CODE_0:ne [constraint="false"]
+    {rank=same; HUFFMAN_CODE_0; HUFFMAN_CODE_1; HUFFMAN_CODE_2; HUFFMAN_CODE_3}
+    {rank=same; METABLOCK_HEADER_2; CONTEXT_MODES; CONTEXT_MAP_1; CONTEXT_MAP_2;
+        TREE_GROUP}
+  }
+  METABLOCK_HEADER:e -> BEFORE_COMPRESSED_METABLOCK_HEADER:n
+
+  _METABLOCK_DONE_PORT_ -> METABLOCK_DONE:se
+      [constraint="false" ltail=cluster_command]
+
+  UNINITED [shape=Mdiamond];
+  DONE [shape=Msquare];
+}
+
+
+ */
+
 typedef enum {
   BROTLI_STATE_UNINITED,
   BROTLI_STATE_LARGE_WINDOW_BITS,
@@ -39,6 +128,7 @@
   BROTLI_STATE_METABLOCK_DONE,
   BROTLI_STATE_COMMAND_POST_WRITE_1,
   BROTLI_STATE_COMMAND_POST_WRITE_2,
+  BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER,
   BROTLI_STATE_HUFFMAN_CODE_0,
   BROTLI_STATE_HUFFMAN_CODE_1,
   BROTLI_STATE_HUFFMAN_CODE_2,
@@ -46,6 +136,7 @@
   BROTLI_STATE_CONTEXT_MAP_1,
   BROTLI_STATE_CONTEXT_MAP_2,
   BROTLI_STATE_TREE_GROUP,
+  BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY,
   BROTLI_STATE_DONE
 } BrotliRunningState;
 
@@ -98,6 +189,50 @@
   BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX
 } BrotliRunningReadBlockLengthState;
 
+typedef struct BrotliMetablockHeaderArena {
+  BrotliRunningTreeGroupState substate_tree_group;
+  BrotliRunningContextMapState substate_context_map;
+  BrotliRunningHuffmanState substate_huffman;
+
+  uint32_t sub_loop_counter;
+
+  uint32_t repeat_code_len;
+  uint32_t prev_code_len;
+
+  /* For ReadHuffmanCode. */
+  uint32_t symbol;
+  uint32_t repeat;
+  uint32_t space;
+
+  /* Huffman table for "histograms". */
+  HuffmanCode table[32];
+  /* List of heads of symbol chains. */
+  uint16_t* symbol_lists;
+  /* Storage from symbol_lists. */
+  uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
+                               BROTLI_NUM_COMMAND_SYMBOLS];
+  /* Tails of symbol chains. */
+  int next_symbol[32];
+  uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES];
+  /* Population counts for the code lengths. */
+  uint16_t code_length_histo[16];
+
+  /* For HuffmanTreeGroupDecode. */
+  int htree_index;
+  HuffmanCode* next;
+
+  /* For DecodeContextMap. */
+  uint32_t context_index;
+  uint32_t max_run_length_prefix;
+  uint32_t code;
+  HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272];
+} BrotliMetablockHeaderArena;
+
+typedef struct BrotliMetablockBodyArena {
+  uint8_t dist_extra_bits[544];
+  uint32_t dist_offset[544];
+} BrotliMetablockBodyArena;
+
 struct BrotliDecoderStateStruct {
   BrotliRunningState state;
 
@@ -110,7 +245,8 @@
   brotli_free_func free_func;
   void* memory_manager_opaque;
 
-  /* Temporary storage for remaining input. */
+  /* Temporary storage for remaining input. Brotli stream format is designed in
+     a way, that 64 bits are enough to make progress in decoding. */
   union {
     uint64_t u64;
     uint8_t u8[8];
@@ -125,7 +261,6 @@
   int dist_rb_idx;
   int dist_rb[4];
   int error_code;
-  uint32_t sub_loop_counter;
   uint8_t* ringbuffer;
   uint8_t* ringbuffer_end;
   HuffmanCode* htree_command;
@@ -153,13 +288,10 @@
   uint32_t block_type_rb[6];
   uint32_t distance_postfix_bits;
   uint32_t num_direct_distance_codes;
-  int distance_postfix_mask;
   uint32_t num_dist_htrees;
   uint8_t* dist_context_map;
   HuffmanCode* literal_htree;
   uint8_t dist_htree_index;
-  uint32_t repeat_code_len;
-  uint32_t prev_code_len;
 
   int copy_length;
   int distance_code;
@@ -168,33 +300,6 @@
   size_t rb_roundtrips;  /* how many times we went around the ring-buffer */
   size_t partial_pos_out;  /* how much output to the user in total */
 
-  /* For ReadHuffmanCode. */
-  uint32_t symbol;
-  uint32_t repeat;
-  uint32_t space;
-
-  HuffmanCode table[32];
-  /* List of heads of symbol chains. */
-  uint16_t* symbol_lists;
-  /* Storage from symbol_lists. */
-  uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
-                               BROTLI_NUM_COMMAND_SYMBOLS];
-  /* Tails of symbol chains. */
-  int next_symbol[32];
-  uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES];
-  /* Population counts for the code lengths. */
-  uint16_t code_length_histo[16];
-
-  /* For HuffmanTreeGroupDecode. */
-  int htree_index;
-  HuffmanCode* next;
-
-  /* For DecodeContextMap. */
-  uint32_t context_index;
-  uint32_t max_run_length_prefix;
-  uint32_t code;
-  HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272];
-
   /* For InverseMoveToFrontTransform. */
   uint32_t mtf_upper_bound;
   uint32_t mtf[64 + 1];
@@ -203,10 +308,7 @@
 
   /* States inside function calls. */
   BrotliRunningMetablockHeaderState substate_metablock_header;
-  BrotliRunningTreeGroupState substate_tree_group;
-  BrotliRunningContextMapState substate_context_map;
   BrotliRunningUncompressedState substate_uncompressed;
-  BrotliRunningHuffmanState substate_huffman;
   BrotliRunningDecodeUint8State substate_decode_uint8;
   BrotliRunningReadBlockLengthState substate_read_block_length;
 
@@ -229,6 +331,11 @@
   const BrotliTransforms* transforms;
 
   uint32_t trivial_literal_contexts[8];  /* 256 bits */
+
+  union {
+    BrotliMetablockHeaderArena header;
+    BrotliMetablockBodyArena body;
+  } arena;
 };
 
 typedef struct BrotliDecoderStateStruct BrotliDecoderStateInternal;
@@ -241,8 +348,8 @@
 BROTLI_INTERNAL void BrotliDecoderStateCleanupAfterMetablock(
     BrotliDecoderState* s);
 BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(
-    BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size,
-    uint32_t max_symbol, uint32_t ntrees);
+    BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size_max,
+    uint32_t alphabet_size_limit, uint32_t ntrees);
 
 #define BROTLI_DECODER_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L)
 
diff --git a/third_party/brotli/enc/backward_references.c b/third_party/brotli/enc/backward_references.c
index cd023d9b..a07a617 100644
--- a/third_party/brotli/enc/backward_references.c
+++ b/third_party/brotli/enc/backward_references.c
@@ -9,6 +9,7 @@
 #include "./backward_references.h"
 
 #include "../common/constants.h"
+#include "../common/context.h"
 #include "../common/dictionary.h"
 #include "../common/platform.h"
 #include <brotli/types.h>
@@ -119,17 +120,17 @@
 #undef CAT
 #undef EXPAND_CAT
 
-void BrotliCreateBackwardReferences(
-    size_t num_bytes, size_t position, const uint8_t* ringbuffer,
-    size_t ringbuffer_mask, const BrotliEncoderParams* params,
-    HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
+void BrotliCreateBackwardReferences(size_t num_bytes,
+    size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+    ContextLut literal_context_lut, const BrotliEncoderParams* params,
+    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
     Command* commands, size_t* num_commands, size_t* num_literals) {
   switch (params->hasher.type) {
 #define CASE_(N)                                                  \
     case N:                                                       \
-      CreateBackwardReferencesNH ## N(                            \
-          num_bytes, position, ringbuffer,                        \
-          ringbuffer_mask, params, hasher, dist_cache,            \
+      CreateBackwardReferencesNH ## N(num_bytes,                  \
+          position, ringbuffer, ringbuffer_mask,                  \
+          literal_context_lut, params, hasher, dist_cache,        \
           last_insert_len, commands, num_commands, num_literals); \
       return;
     FOR_GENERIC_HASHERS(CASE_)
diff --git a/third_party/brotli/enc/backward_references.h b/third_party/brotli/enc/backward_references.h
index 3a414664..9589cc15 100644
--- a/third_party/brotli/enc/backward_references.h
+++ b/third_party/brotli/enc/backward_references.h
@@ -10,6 +10,7 @@
 #define BROTLI_ENC_BACKWARD_REFERENCES_H_
 
 #include "../common/constants.h"
+#include "../common/context.h"
 #include "../common/dictionary.h"
 #include "../common/platform.h"
 #include <brotli/types.h>
@@ -25,10 +26,10 @@
    initially the total amount of commands output by previous
    CreateBackwardReferences calls, and must be incremented by the amount written
    by this call. */
-BROTLI_INTERNAL void BrotliCreateBackwardReferences(
-    size_t num_bytes, size_t position, const uint8_t* ringbuffer,
-    size_t ringbuffer_mask, const BrotliEncoderParams* params,
-    HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
+BROTLI_INTERNAL void BrotliCreateBackwardReferences(size_t num_bytes,
+    size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+    ContextLut literal_context_lut, const BrotliEncoderParams* params,
+    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
     Command* commands, size_t* num_commands, size_t* num_literals);
 
 #if defined(__cplusplus) || defined(c_plusplus)
diff --git a/third_party/brotli/enc/backward_references_hq.c b/third_party/brotli/enc/backward_references_hq.c
index 96b0e708..5651caeb 100644
--- a/third_party/brotli/enc/backward_references_hq.c
+++ b/third_party/brotli/enc/backward_references_hq.c
@@ -11,6 +11,7 @@
 #include <string.h>  /* memcpy, memset */
 
 #include "../common/constants.h"
+#include "../common/context.h"
 #include "../common/platform.h"
 #include <brotli/types.h>
 #include "./command.h"
@@ -26,6 +27,7 @@
 extern "C" {
 #endif
 
+/* BrotliCalculateDistanceCodeLimit(BROTLI_MAX_ALLOWED_DISTANCE, 3, 120). */
 #define BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE 544
 
 static const float kInfinity = 1.7e38f;  /* ~= 2 ^ 127 */
@@ -86,14 +88,10 @@
 static void InitZopfliCostModel(
     MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist,
     size_t num_bytes) {
-  uint32_t distance_histogram_size = dist->alphabet_size;
-  if (distance_histogram_size > BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE) {
-    distance_histogram_size = BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE;
-  }
   self->num_bytes_ = num_bytes;
   self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2);
-  self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size);
-  self->distance_histogram_size = distance_histogram_size;
+  self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size_limit);
+  self->distance_histogram_size = dist->alphabet_size_limit;
   if (BROTLI_IS_OOM(m)) return;
 }
 
@@ -408,9 +406,12 @@
     const int* starting_dist_cache, const size_t num_matches,
     const BackwardMatch* matches, const ZopfliCostModel* model,
     StartPosQueue* queue, ZopfliNode* nodes) {
+  const size_t stream_offset = params->stream_offset;
   const size_t cur_ix = block_start + pos;
   const size_t cur_ix_masked = cur_ix & ringbuffer_mask;
   const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit);
+  const size_t dictionary_start = BROTLI_MIN(size_t,
+      cur_ix + stream_offset, max_backward_limit);
   const size_t max_len = num_bytes - pos;
   const size_t max_zopfli_len = MaxZopfliLen(params);
   const size_t max_iters = MaxZopfliCandidates(params);
@@ -419,8 +420,8 @@
   size_t k;
   size_t gap = 0;
 
-  EvaluateNode(block_start, pos, max_backward_limit, gap, starting_dist_cache,
-      model, queue, nodes);
+  EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap,
+      starting_dist_cache, model, queue, nodes);
 
   {
     const PosData* posdata = StartPosQueueAt(queue, 0);
@@ -453,7 +454,7 @@
       if (cur_ix_masked + best_len > ringbuffer_mask) {
         break;
       }
-      if (BROTLI_PREDICT_FALSE(backward > max_distance + gap)) {
+      if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) {
         /* Word dictionary -> ignore. */
         continue;
       }
@@ -472,6 +473,8 @@
                                        &ringbuffer[cur_ix_masked],
                                        max_len);
       } else {
+        /* "Gray" area. It is addressable by decoder, but this encoder
+           instance does not have that data -> should not touch it. */
         continue;
       }
       {
@@ -506,7 +509,7 @@
         BackwardMatch match = matches[j];
         size_t dist = match.distance;
         BROTLI_BOOL is_dictionary_match =
-            TO_BROTLI_BOOL(dist > max_distance + gap);
+            TO_BROTLI_BOOL(dist > dictionary_start + gap);
         /* We already tried all possible last distance matches, so we can use
            normal distance code here. */
         size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
@@ -569,6 +572,7 @@
     const size_t block_start, const ZopfliNode* nodes, int* dist_cache,
     size_t* last_insert_len, const BrotliEncoderParams* params,
     Command* commands, size_t* num_literals) {
+  const size_t stream_offset = params->stream_offset;
   const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
   size_t pos = 0;
   uint32_t offset = nodes[0].u.next;
@@ -587,9 +591,10 @@
     {
       size_t distance = ZopfliNodeCopyDistance(next);
       size_t len_code = ZopfliNodeLengthCode(next);
-      size_t max_distance =
-          BROTLI_MIN(size_t, block_start + pos, max_backward_limit);
-      BROTLI_BOOL is_dictionary = TO_BROTLI_BOOL(distance > max_distance + gap);
+      size_t dictionary_start = BROTLI_MIN(size_t,
+          block_start + pos + stream_offset, max_backward_limit);
+      BROTLI_BOOL is_dictionary =
+          TO_BROTLI_BOOL(distance > dictionary_start + gap);
       size_t dist_code = ZopfliNodeDistanceCode(next);
       InitCommand(&commands[i], &params->dist, insert_length,
           copy_length, (int)len_code - (int)copy_length, dist_code);
@@ -613,6 +618,7 @@
     const BrotliEncoderParams* params, const size_t gap, const int* dist_cache,
     const ZopfliCostModel* model, const uint32_t* num_matches,
     const BackwardMatch* matches, ZopfliNode* nodes) {
+  const size_t stream_offset = params->stream_offset;
   const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
   const size_t max_zopfli_len = MaxZopfliLen(params);
   StartPosQueue queue;
@@ -637,7 +643,7 @@
       while (skip) {
         i++;
         if (i + 3 >= num_bytes) break;
-        EvaluateNode(position, i, max_backward_limit, gap,
+        EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
             dist_cache, model, &queue, nodes);
         cur_match_pos += num_matches[i];
         skip--;
@@ -650,8 +656,9 @@
 /* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
 size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
     size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
-    const BrotliEncoderParams* params,
-    const int* dist_cache, HasherHandle hasher, ZopfliNode* nodes) {
+    ContextLut literal_context_lut, const BrotliEncoderParams* params,
+    const int* dist_cache, Hasher* hasher, ZopfliNode* nodes) {
+  const size_t stream_offset = params->stream_offset;
   const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
   const size_t max_zopfli_len = MaxZopfliLen(params);
   ZopfliCostModel model;
@@ -662,6 +669,7 @@
   size_t i;
   size_t gap = 0;
   size_t lz_matches_offset = 0;
+  BROTLI_UNUSED(literal_context_lut);
   nodes[0].length = 0;
   nodes[0].u.cost = 0;
   InitZopfliCostModel(m, &model, &params->dist, num_bytes);
@@ -672,12 +680,14 @@
   for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
     const size_t pos = position + i;
     const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
+    const size_t dictionary_start = BROTLI_MIN(size_t,
+        pos + stream_offset, max_backward_limit);
     size_t skip;
     size_t num_matches;
-    num_matches = FindAllMatchesH10(hasher,
+    num_matches = FindAllMatchesH10(&hasher->privat._H10,
         &params->dictionary,
         ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance,
-        gap, params, &matches[lz_matches_offset]);
+        dictionary_start + gap, params, &matches[lz_matches_offset]);
     if (num_matches > 0 &&
         BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
       matches[0] = matches[num_matches - 1];
@@ -692,13 +702,14 @@
     }
     if (skip > 1) {
       /* Add the tail of the copy to the hasher. */
-      StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
+      StoreRangeH10(&hasher->privat._H10,
+          ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
           size_t, pos + skip, store_end));
       skip--;
       while (skip) {
         i++;
         if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
-        EvaluateNode(position, i, max_backward_limit, gap,
+        EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
             dist_cache, &model, &queue, nodes);
         skip--;
       }
@@ -710,15 +721,14 @@
 
 void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
     size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
-    const BrotliEncoderParams* params,
-    HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
+    ContextLut literal_context_lut, const BrotliEncoderParams* params,
+    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
     Command* commands, size_t* num_commands, size_t* num_literals) {
-  ZopfliNode* nodes;
-  nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
-  if (BROTLI_IS_OOM(m)) return;
+  ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
   BrotliInitZopfliNodes(nodes, num_bytes + 1);
   *num_commands += BrotliZopfliComputeShortestPath(m, num_bytes,
-      position, ringbuffer, ringbuffer_mask, params,
+      position, ringbuffer, ringbuffer_mask, literal_context_lut, params,
       dist_cache, hasher, nodes);
   if (BROTLI_IS_OOM(m)) return;
   BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
@@ -728,9 +738,10 @@
 
 void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
     size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
-    const BrotliEncoderParams* params,
-    HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
+    ContextLut literal_context_lut, const BrotliEncoderParams* params,
+    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
     Command* commands, size_t* num_commands, size_t* num_literals) {
+  const size_t stream_offset = params->stream_offset;
   const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
   uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes);
   size_t matches_size = 4 * num_bytes;
@@ -747,10 +758,16 @@
   BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
   size_t gap = 0;
   size_t shadow_matches = 0;
-  if (BROTLI_IS_OOM(m)) return;
+  BROTLI_UNUSED(literal_context_lut);
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(num_matches) ||
+      BROTLI_IS_NULL(matches)) {
+    return;
+  }
   for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) {
     const size_t pos = position + i;
     size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
+    size_t dictionary_start = BROTLI_MIN(size_t,
+        pos + stream_offset, max_backward_limit);
     size_t max_length = num_bytes - i;
     size_t num_found_matches;
     size_t cur_match_end;
@@ -759,10 +776,10 @@
     BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
         cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
     if (BROTLI_IS_OOM(m)) return;
-    num_found_matches = FindAllMatchesH10(hasher,
+    num_found_matches = FindAllMatchesH10(&hasher->privat._H10,
         &params->dictionary,
         ringbuffer, ringbuffer_mask, pos, max_length,
-        max_distance, gap, params,
+        max_distance, dictionary_start + gap, params,
         &matches[cur_match_pos + shadow_matches]);
     cur_match_end = cur_match_pos + num_found_matches;
     for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
@@ -777,7 +794,8 @@
         matches[cur_match_pos++] = matches[cur_match_end - 1];
         num_matches[i] = 1;
         /* Add the tail of the copy to the hasher. */
-        StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1,
+        StoreRangeH10(&hasher->privat._H10,
+                      ringbuffer, ringbuffer_mask, pos + 1,
                       BROTLI_MIN(size_t, pos + match_len, store_end));
         memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0]));
         i += skip;
@@ -791,7 +809,7 @@
   memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
   orig_num_commands = *num_commands;
   nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
   InitZopfliCostModel(m, &model, &params->dist, num_bytes);
   if (BROTLI_IS_OOM(m)) return;
   for (i = 0; i < 2; i++) {
diff --git a/third_party/brotli/enc/backward_references_hq.h b/third_party/brotli/enc/backward_references_hq.h
index 1e4275d..36b75f25 100644
--- a/third_party/brotli/enc/backward_references_hq.h
+++ b/third_party/brotli/enc/backward_references_hq.h
@@ -10,6 +10,7 @@
 #define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
 
 #include "../common/constants.h"
+#include "../common/context.h"
 #include "../common/dictionary.h"
 #include "../common/platform.h"
 #include <brotli/types.h>
@@ -23,15 +24,17 @@
 #endif
 
 BROTLI_INTERNAL void BrotliCreateZopfliBackwardReferences(MemoryManager* m,
-    size_t num_bytes, size_t position, const uint8_t* ringbuffer,
-    size_t ringbuffer_mask, const BrotliEncoderParams* params,
-    HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
+    size_t num_bytes,
+    size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+    ContextLut literal_context_lut, const BrotliEncoderParams* params,
+    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
     Command* commands, size_t* num_commands, size_t* num_literals);
 
 BROTLI_INTERNAL void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
-    size_t num_bytes, size_t position, const uint8_t* ringbuffer,
-    size_t ringbuffer_mask, const BrotliEncoderParams* params,
-    HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
+    size_t num_bytes,
+    size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+    ContextLut literal_context_lut, const BrotliEncoderParams* params,
+    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
     Command* commands, size_t* num_commands, size_t* num_literals);
 
 typedef struct ZopfliNode {
@@ -77,8 +80,8 @@
 BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(
     MemoryManager* m, size_t num_bytes,
     size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
-    const BrotliEncoderParams* params,
-    const int* dist_cache, HasherHandle hasher, ZopfliNode* nodes);
+    ContextLut literal_context_lut, const BrotliEncoderParams* params,
+    const int* dist_cache, Hasher* hasher, ZopfliNode* nodes);
 
 BROTLI_INTERNAL void BrotliZopfliCreateCommands(
     const size_t num_bytes, const size_t block_start, const ZopfliNode* nodes,
diff --git a/third_party/brotli/enc/backward_references_inc.h b/third_party/brotli/enc/backward_references_inc.h
index c18cdb00..766bf91f 100644
--- a/third_party/brotli/enc/backward_references_inc.h
+++ b/third_party/brotli/enc/backward_references_inc.h
@@ -10,11 +10,13 @@
 static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
     size_t num_bytes, size_t position,
     const uint8_t* ringbuffer, size_t ringbuffer_mask,
-    const BrotliEncoderParams* params,
-    HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
+    ContextLut literal_context_lut, const BrotliEncoderParams* params,
+    Hasher* hasher, int* dist_cache, size_t* last_insert_len,
     Command* commands, size_t* num_commands, size_t* num_literals) {
+  HASHER()* privat = &hasher->privat.FN(_);
   /* Set maximum distance, see section 9.1. of the spec. */
   const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
+  const size_t position_offset = params->stream_offset;
 
   const Command* const orig_commands = commands;
   size_t insert_length = *last_insert_len;
@@ -31,19 +33,23 @@
   /* Minimum score to accept a backward reference. */
   const score_t kMinScore = BROTLI_SCORE_BASE + 100;
 
-  FN(PrepareDistanceCache)(hasher, dist_cache);
+  BROTLI_UNUSED(literal_context_lut);
+
+  FN(PrepareDistanceCache)(privat, dist_cache);
 
   while (position + FN(HashTypeLength)() < pos_end) {
     size_t max_length = pos_end - position;
     size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
+    size_t dictionary_start = BROTLI_MIN(size_t,
+        position + position_offset, max_backward_limit);
     HasherSearchResult sr;
     sr.len = 0;
     sr.len_code_delta = 0;
     sr.distance = 0;
     sr.score = kMinScore;
-    FN(FindLongestMatch)(hasher, &params->dictionary,
+    FN(FindLongestMatch)(privat, &params->dictionary,
         ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
-        max_distance, gap, params->dist.max_distance, &sr);
+        max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
     if (sr.score > kMinScore) {
       /* Found a match. Let's look for something even better ahead. */
       int delayed_backward_references_in_row = 0;
@@ -57,10 +63,13 @@
         sr2.distance = 0;
         sr2.score = kMinScore;
         max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
-        FN(FindLongestMatch)(hasher,
+        dictionary_start = BROTLI_MIN(size_t,
+            position + 1 + position_offset, max_backward_limit);
+        FN(FindLongestMatch)(privat,
             &params->dictionary,
             ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
-            max_distance, gap, params->dist.max_distance, &sr2);
+            max_distance, dictionary_start + gap, params->dist.max_distance,
+            &sr2);
         if (sr2.score >= sr.score + cost_diff_lazy) {
           /* Ok, let's just write one byte for now and start a match from the
              next byte. */
@@ -76,18 +85,19 @@
       }
       apply_random_heuristics =
           position + 2 * sr.len + random_heuristics_window_size;
-      max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
+      dictionary_start = BROTLI_MIN(size_t,
+          position + position_offset, max_backward_limit);
       {
         /* The first 16 codes are special short-codes,
            and the minimum offset is 1. */
         size_t distance_code = ComputeDistanceCode(
-            sr.distance, max_distance + gap, dist_cache);
-        if ((sr.distance <= (max_distance + gap)) && distance_code > 0) {
+            sr.distance, dictionary_start + gap, dist_cache);
+        if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
           dist_cache[3] = dist_cache[2];
           dist_cache[2] = dist_cache[1];
           dist_cache[1] = dist_cache[0];
           dist_cache[0] = (int)sr.distance;
-          FN(PrepareDistanceCache)(hasher, dist_cache);
+          FN(PrepareDistanceCache)(privat, dist_cache);
         }
         InitCommand(commands++, &params->dist, insert_length,
             sr.len, sr.len_code_delta, distance_code);
@@ -105,7 +115,7 @@
           range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
               range_start, position + sr.len - (sr.distance << 2)));
         }
-        FN(StoreRange)(hasher, ringbuffer, ringbuffer_mask, range_start,
+        FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
                        range_end);
       }
       position += sr.len;
@@ -131,7 +141,7 @@
           size_t pos_jump =
               BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
           for (; position < pos_jump; position += 4) {
-            FN(Store)(hasher, ringbuffer, ringbuffer_mask, position);
+            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
             insert_length += 4;
           }
         } else {
@@ -140,7 +150,7 @@
           size_t pos_jump =
               BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
           for (; position < pos_jump; position += 2) {
-            FN(Store)(hasher, ringbuffer, ringbuffer_mask, position);
+            FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
             insert_length += 2;
           }
         }
diff --git a/third_party/brotli/enc/block_splitter.c b/third_party/brotli/enc/block_splitter.c
index d308eca..deb7c2e1 100644
--- a/third_party/brotli/enc/block_splitter.c
+++ b/third_party/brotli/enc/block_splitter.c
@@ -132,7 +132,7 @@
   {
     size_t literals_count = CountLiterals(cmds, num_commands);
     uint8_t* literals = BROTLI_ALLOC(m, uint8_t, literals_count);
-    if (BROTLI_IS_OOM(m)) return;
+    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literals)) return;
     /* Create a continuous array of literals. */
     CopyLiteralsToByteArray(cmds, num_commands, data, pos, mask, literals);
     /* Create the block split on the array of literals.
@@ -150,7 +150,7 @@
     /* Compute prefix codes for commands. */
     uint16_t* insert_and_copy_codes = BROTLI_ALLOC(m, uint16_t, num_commands);
     size_t i;
-    if (BROTLI_IS_OOM(m)) return;
+    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(insert_and_copy_codes)) return;
     for (i = 0; i < num_commands; ++i) {
       insert_and_copy_codes[i] = cmds[i].cmd_prefix_;
     }
@@ -170,7 +170,7 @@
     uint16_t* distance_prefixes = BROTLI_ALLOC(m, uint16_t, num_commands);
     size_t j = 0;
     size_t i;
-    if (BROTLI_IS_OOM(m)) return;
+    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_prefixes)) return;
     for (i = 0; i < num_commands; ++i) {
       const Command* cmd = &cmds[i];
       if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
diff --git a/third_party/brotli/enc/block_splitter_inc.h b/third_party/brotli/enc/block_splitter_inc.h
index 023712b..e612d6a 100644
--- a/third_party/brotli/enc/block_splitter_inc.h
+++ b/third_party/brotli/enc/block_splitter_inc.h
@@ -219,7 +219,12 @@
   uint32_t symbols[HISTOGRAMS_PER_BATCH] = { 0 };
   uint32_t remap[HISTOGRAMS_PER_BATCH] = { 0 };
 
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histogram_symbols) ||
+      BROTLI_IS_NULL(block_lengths) || BROTLI_IS_NULL(all_histograms) ||
+      BROTLI_IS_NULL(cluster_size) || BROTLI_IS_NULL(histograms) ||
+      BROTLI_IS_NULL(pairs)) {
+    return;
+  }
 
   memset(block_lengths, 0, num_blocks * sizeof(uint32_t));
 
@@ -278,11 +283,11 @@
   if (pairs_capacity < max_num_pairs + 1) {
     BROTLI_FREE(m, pairs);
     pairs = BROTLI_ALLOC(m, HistogramPair, max_num_pairs + 1);
-    if (BROTLI_IS_OOM(m)) return;
+    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(pairs)) return;
   }
 
   clusters = BROTLI_ALLOC(m, uint32_t, num_clusters);
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(clusters)) return;
   for (i = 0; i < num_clusters; ++i) {
     clusters[i] = (uint32_t)i;
   }
@@ -294,7 +299,7 @@
   BROTLI_FREE(m, cluster_size);
 
   new_index = BROTLI_ALLOC(m, uint32_t, num_clusters);
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return;
   for (i = 0; i < num_clusters; ++i) new_index[i] = kInvalidIndex;
   pos = 0;
   {
@@ -386,7 +391,7 @@
     return;
   }
   histograms = BROTLI_ALLOC(m, HistogramType, num_histograms);
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histograms)) return;
   /* Find good entropy codes. */
   FN(InitialEntropyCodes)(data, length,
                           sampling_stride_length,
@@ -405,7 +410,11 @@
     uint16_t* new_id = BROTLI_ALLOC(m, uint16_t, num_histograms);
     const size_t iters = params->quality < HQ_ZOPFLIFICATION_QUALITY ? 3 : 10;
     size_t i;
-    if (BROTLI_IS_OOM(m)) return;
+    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(block_ids) ||
+        BROTLI_IS_NULL(insert_cost) || BROTLI_IS_NULL(cost) ||
+        BROTLI_IS_NULL(switch_signal) || BROTLI_IS_NULL(new_id)) {
+      return;
+    }
     for (i = 0; i < iters; ++i) {
       num_blocks = FN(FindBlocks)(data, length,
                                   block_switch_cost,
diff --git a/third_party/brotli/enc/brotli_bit_stream.c b/third_party/brotli/enc/brotli_bit_stream.c
index aaf2dad..9348a97 100644
--- a/third_party/brotli/enc/brotli_bit_stream.c
+++ b/third_party/brotli/enc/brotli_bit_stream.c
@@ -34,33 +34,18 @@
   BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_LARGE_MAX_DISTANCE_BITS)
 /* MAX_SIMPLE_DISTANCE_ALPHABET_SIZE == 140 */
 
-/* Represents the range of values belonging to a prefix code:
-   [offset, offset + 2^nbits) */
-typedef struct PrefixCodeRange {
-  uint32_t offset;
-  uint32_t nbits;
-} PrefixCodeRange;
-
-static const PrefixCodeRange
-    kBlockLengthPrefixCode[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
-  { 1, 2}, { 5, 2}, { 9, 2}, {13, 2}, {17, 3}, { 25, 3}, { 33, 3},
-  {41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4}, {113, 5}, {145, 5},
-  {177, 5}, { 209,  5}, { 241,  6}, { 305,  6}, { 369,  7}, {  497,  8},
-  {753, 9}, {1265, 10}, {2289, 11}, {4337, 12}, {8433, 13}, {16625, 24}
-};
-
 static BROTLI_INLINE uint32_t BlockLengthPrefixCode(uint32_t len) {
   uint32_t code = (len >= 177) ? (len >= 753 ? 20 : 14) : (len >= 41 ? 7 : 0);
   while (code < (BROTLI_NUM_BLOCK_LEN_SYMBOLS - 1) &&
-      len >= kBlockLengthPrefixCode[code + 1].offset) ++code;
+      len >= _kBrotliPrefixCodeRanges[code + 1].offset) ++code;
   return code;
 }
 
 static BROTLI_INLINE void GetBlockLengthPrefixCode(uint32_t len, size_t* code,
     uint32_t* n_extra, uint32_t* extra) {
   *code = BlockLengthPrefixCode(len);
-  *n_extra = kBlockLengthPrefixCode[*code].nbits;
-  *extra = len - kBlockLengthPrefixCode[*code].offset;
+  *n_extra = _kBrotliPrefixCodeRanges[*code].nbits;
+  *extra = len - _kBrotliPrefixCodeRanges[*code].offset;
 }
 
 typedef struct BlockTypeCodeCalculator {
@@ -450,7 +435,7 @@
     const size_t max_tree_size = 2 * length + 1;
     HuffmanTree* tree = BROTLI_ALLOC(m, HuffmanTree, max_tree_size);
     uint32_t count_limit;
-    if (BROTLI_IS_OOM(m)) return;
+    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
     for (count_limit = 1; ; count_limit *= 2) {
       HuffmanTree* node = tree;
       size_t l;
@@ -714,7 +699,7 @@
   }
 
   rle_symbols = BROTLI_ALLOC(m, uint32_t, context_map_size);
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(rle_symbols)) return;
   MoveToFrontTransform(context_map, context_map_size, rle_symbols);
   RunLengthCodeZeros(context_map_size, rle_symbols,
                      &num_rle_symbols, &max_run_length_prefix);
@@ -956,23 +941,21 @@
 
   size_t pos = start_pos;
   size_t i;
-  uint32_t num_distance_symbols = params->dist.alphabet_size;
-  uint32_t num_effective_distance_symbols = num_distance_symbols;
+  uint32_t num_distance_symbols = params->dist.alphabet_size_max;
+  uint32_t num_effective_distance_symbols = params->dist.alphabet_size_limit;
   HuffmanTree* tree;
   ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
   BlockEncoder literal_enc;
   BlockEncoder command_enc;
   BlockEncoder distance_enc;
   const BrotliDistanceParams* dist = &params->dist;
-  if (params->large_window &&
-      num_effective_distance_symbols > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) {
-    num_effective_distance_symbols = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
-  }
+  BROTLI_DCHECK(
+      num_effective_distance_symbols <= BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS);
 
   StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
 
   tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
   InitBlockEncoder(&literal_enc, BROTLI_NUM_LITERAL_SYMBOLS,
       mb->literal_split.num_types, mb->literal_split.types,
       mb->literal_split.lengths, mb->literal_split.num_blocks);
@@ -1163,7 +1146,7 @@
   uint8_t dist_depth[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
   uint16_t dist_bits[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
   HuffmanTree* tree;
-  uint32_t num_distance_symbols = params->dist.alphabet_size;
+  uint32_t num_distance_symbols = params->dist.alphabet_size_max;
 
   StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
 
@@ -1177,7 +1160,7 @@
   BrotliWriteBits(13, 0, storage_ix, storage);
 
   tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
   BuildAndStoreHuffmanTree(lit_histo.data_, BROTLI_NUM_LITERAL_SYMBOLS,
                            BROTLI_NUM_LITERAL_SYMBOLS, tree,
                            lit_depth, lit_bits,
@@ -1206,7 +1189,7 @@
     BROTLI_BOOL is_last, const BrotliEncoderParams* params,
     const Command* commands, size_t n_commands,
     size_t* storage_ix, uint8_t* storage) {
-  uint32_t num_distance_symbols = params->dist.alphabet_size;
+  uint32_t num_distance_symbols = params->dist.alphabet_size_max;
   uint32_t distance_alphabet_bits =
       Log2FloorNonZero(num_distance_symbols - 1) + 1;
 
diff --git a/third_party/brotli/enc/cluster_inc.h b/third_party/brotli/enc/cluster_inc.h
index 22ecb3cc..3d4f40e 100644
--- a/third_party/brotli/enc/cluster_inc.h
+++ b/third_party/brotli/enc/cluster_inc.h
@@ -215,7 +215,7 @@
   uint32_t next_index;
   HistogramType* tmp;
   size_t i;
-  if (BROTLI_IS_OOM(m)) return 0;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return 0;
   for (i = 0; i < length; ++i) {
       new_index[i] = kInvalidIndex;
   }
@@ -229,7 +229,7 @@
   /* TODO: by using idea of "cycle-sort" we can avoid allocation of
      tmp and reduce the number of copying by the factor of 2. */
   tmp = BROTLI_ALLOC(m, HistogramType, next_index);
-  if (BROTLI_IS_OOM(m)) return 0;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return 0;
   next_index = 0;
   for (i = 0; i < length; ++i) {
     if (new_index[symbols[i]] == next_index) {
@@ -259,7 +259,10 @@
   HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity + 1);
   size_t i;
 
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(cluster_size) ||
+      BROTLI_IS_NULL(clusters) || BROTLI_IS_NULL(pairs)) {
+    return;
+  }
 
   for (i = 0; i < in_size; ++i) {
     cluster_size[i] = 1;
diff --git a/third_party/brotli/enc/command.c b/third_party/brotli/enc/command.c
new file mode 100644
index 0000000..5e6c2491
--- /dev/null
+++ b/third_party/brotli/enc/command.c
@@ -0,0 +1,28 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+   Distributed under MIT license.
+   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#include "./command.h"
+
+#include <brotli/types.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+const uint32_t kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES] = {
+    0,  1,  2,  3,  4,   5,   6,   8,   10,   14,   18,   26,
+    34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594};
+const uint32_t kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES] = {
+    0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24};
+const uint32_t kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES] = {
+    2,  3,  4,  5,  6,  7,   8,   9,   10,  12,  14,   18,
+    22, 30, 38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118};
+const uint32_t kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24};
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}  /* extern "C" */
+#endif
diff --git a/third_party/brotli/enc/command.h b/third_party/brotli/enc/command.h
index 1aac856..d84e373 100644
--- a/third_party/brotli/enc/command.h
+++ b/third_party/brotli/enc/command.h
@@ -20,14 +20,14 @@
 extern "C" {
 #endif
 
-static uint32_t kInsBase[] =   { 0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50,
-    66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594 };
-static uint32_t kInsExtra[] =  { 0, 0, 0, 0, 0, 0, 1, 1,  2,  2,  3,  3,  4,  4,
-    5,   5,   6,   7,   8,   9,   10,   12,   14,    24 };
-static uint32_t kCopyBase[] =  { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18, 22, 30,
-    38, 54,  70, 102, 134, 198, 326,   582, 1094,  2118 };
-static uint32_t kCopyExtra[] = { 0, 0, 0, 0, 0, 0, 0, 0,  1,  1,  2,  2,  3,  3,
-     4,  4,   5,   5,   6,   7,   8,     9,   10,    24 };
+BROTLI_INTERNAL extern const uint32_t
+    kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES];
+BROTLI_INTERNAL extern const uint32_t
+    kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES];
+BROTLI_INTERNAL extern const uint32_t
+    kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES];
+BROTLI_INTERNAL extern const uint32_t
+    kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES];
 
 static BROTLI_INLINE uint16_t GetInsertLengthCode(size_t insertlen) {
   if (insertlen < 6) {
@@ -89,19 +89,19 @@
 }
 
 static BROTLI_INLINE uint32_t GetInsertBase(uint16_t inscode) {
-  return kInsBase[inscode];
+  return kBrotliInsBase[inscode];
 }
 
 static BROTLI_INLINE uint32_t GetInsertExtra(uint16_t inscode) {
-  return kInsExtra[inscode];
+  return kBrotliInsExtra[inscode];
 }
 
 static BROTLI_INLINE uint32_t GetCopyBase(uint16_t copycode) {
-  return kCopyBase[copycode];
+  return kBrotliCopyBase[copycode];
 }
 
 static BROTLI_INLINE uint32_t GetCopyExtra(uint16_t copycode) {
-  return kCopyExtra[copycode];
+  return kBrotliCopyExtra[copycode];
 }
 
 typedef struct Command {
diff --git a/third_party/brotli/enc/compress_fragment_two_pass.c b/third_party/brotli/enc/compress_fragment_two_pass.c
index f8a5606..ca68b38 100644
--- a/third_party/brotli/enc/compress_fragment_two_pass.c
+++ b/third_party/brotli/enc/compress_fragment_two_pass.c
@@ -524,7 +524,7 @@
 static BROTLI_BOOL ShouldCompress(
     const uint8_t* input, size_t input_size, size_t num_literals) {
   double corpus_size = (double)input_size;
-  if (num_literals < MIN_RATIO * corpus_size) {
+  if ((double)num_literals < MIN_RATIO * corpus_size) {
     return BROTLI_TRUE;
   } else {
     uint32_t literal_histo[256] = { 0 };
diff --git a/third_party/brotli/enc/dictionary_hash.c b/third_party/brotli/enc/dictionary_hash.c
index 3677d7d..16d853fe5 100644
--- a/third_party/brotli/enc/dictionary_hash.c
+++ b/third_party/brotli/enc/dictionary_hash.c
@@ -13,1107 +13,1833 @@
 extern "C" {
 #endif
 
-BROTLI_INTERNAL const uint16_t kStaticDictionaryHash[32768] = {
-32072,0,0,0,0,0,0,0,0,21860,0,0,0,0,0,0,0,40486,0,0,0,0,0,45798,0,0,0,0,0,0,1292
-,0,0,0,0,4964,278,23717,0,19972,0,0,0,0,0,0,0,0,0,0,0,0,2126,16102,0,0,0,14437,0
-,0,0,0,0,0,0,26727,2253,0,0,17252,0,0,0,0,0,0,0,0,0,3622,0,0,0,0,22984,0,0,0,0,0
-,0,16647,0,34247,0,0,0,0,0,48486,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2511,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19532,0,0,24004,0,0,0,9828,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30853,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,31974,0,0,0,0,0,0,0,0,20650,2404,0,20773,1677,9031,0,6404,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51879,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6761,7206
-,0,0,21992,22983,0,0,3529,0,1864,0,0,0,0,0,0,11046,0,0,9641,0,0,0,6507,0,0,36934
-,21576,62375,0,0,0,0,0,0,0,0,0,8294,0,0,0,0,0,0,0,40807,0,0,0,39398,8136,0,0,0,0
-,0,0,0,8875,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7941,0,0,25609,0,0,0,936,
-3716,3213,15687,0,0,0,0,0,52519,0,17381,0,0,0,0,1320,5797,0,21029,0,0,6472,807,0
-,0,0,0,0,0,0,0,0,0,13545,0,0,0,3624,0,0,0,29674,30820,0,31237,0,6596,0,0,0,0,0,0
-,0,0,0,64070,0,0,0,0,0,0,0,0,0,0,0,22278,0,37446,0,0,0,0,7240,423,0,24612,21705,
-17636,0,0,0,0,0,0,1833,0,0,0,328,6021,0,0,0,19974,0,0,0,0,0,0,0,0,0,62119,4178,0
-,0,0,0,12100,8617,0,0,16900,0,36678,0,0,0,35366,0,51718,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,20998,0,62086,0,0,0,0,0,5542,0,0,0,0,0,0,0,0,0,0,0,14629,10952,25927,0,0,0
-,0,19849,0,0,0,0,0,0,0,30952,3046,14314,12998,0,0,0,15268,0,40582,30216,62118,0,
-0,0,20132,0,0,0,0,0,12005,0,0,0,52358,0,0,0,0,24778,0,44,33095,0,0,0,0,0,26372,0
-,0,0,0,0,3781,0,0,17928,9479,0,0,0,0,0,0,0,0,32297,28613,0,0,0,0,0,0,0,0,0,0,0,0
-,0,47174,11723,0,0,0,0,0,0,0,0,0,2536,55143,0,0,6410,0,0,0,0,0,0,0,0,56294,11914
-,0,529,0,30184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8261,0,0,28808,58854,22633,
-965,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64135,0,0,331,3684,0,1605,0,0,0,0,0,0,
-0,0,0,0,16650,37,0,23622,3144,15429,0,0,0,0,0,0,0,0,0,0,22443,69,0,0,0,0,0,0,0,0
-,17832,0,0,0,0,0,0,0,0,0,11113,0,0,0,0,18309,0,0,0,0,0,0,0,0,0,26630,0,0,25512,
-25895,0,0,0,0,0,0,0,0,0,0,0,16901,0,0,0,27558,0,0,9418,0,0,0,3508,0,0,0,0,0,0,0,
-0,37990,9289,8517,0,0,0,0,1578,1604,23944,0,0,14916,12781,0,0,0,0,0,0,0,12105,0,
-16617,0,0,0,0,0,0,0,0,0,0,0,0,21348,11240,28870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,5772,0,0,27812,0,0,0,0,0,0,0,8324,0,0,0,0,0,0,0,0,0,0,16748,1157,0,0,18794,
-16324,25898,935,8333,0,0,0,0,0,0,0,0,18246,0,18086,0,46854,0,0,0,0,0,0,339,0,0,
-25188,12780,12166,6409,0,0,0,0,16516,0,27012,28395,0,0,0,0,0,0,0,1420,0,0,0,9768
-,52967,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25163,324,0,0,0,0,0,0,0,0,0,64998,0,0,0,0,0,
-21893,0,0,0,0,0,47366,0,0,0,870,0,0,0,12646,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,26020,16360,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1809,0,0,0,6601,15878,0,0,0,0,0,
-29092,0,28516,0,0,0,0,0,0,0,0,0,21988,0,0,0,42950,0,0,0,0,0,0,0,0,0,0,5133,1318,
-0,0,0,0,0,0,0,0,0,0,0,54982,24904,0,0,0,0,0,0,0,0,0,0,51526,0,0,0,0,0,3685,0,0,0
-,0,10062,9412,0,0,0,31460,5708,6181,0,0,0,0,0,0,0,0,0,5575,0,0,0,0,0,0,0,0,0,0,
-27144,57478,0,0,0,0,0,0,7084,0,21993,53126,0,0,0,0,8397,0,0,5733,0,0,0,0,0,2116,
-0,24742,0,11271,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1133,0,4873,0,0,38310,0,0,0,0,0,
-0,0,0,0,0,0,0,17932,0,0,18053,0,0,0,25510,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17798,0,
-26214,0,0,0,0,0,0,0,0,23016,17415,20392,164,0,0,0,0,0,0,0,0,0,0,0,3239,0,46119,0
-,0,0,28580,0,0,0,0,0,0,0,0,0,7621,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41478,0,0,31016,
-55334,10056,1924,0,0,0,0,0,36614,0,36711,0,0,0,0,0,0,0,0,0,0,13994,59303,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,26501,0,5639,0,0,0,0,0,0,13897,1253,0,0,0,0,0,5095,0,0,0,
-28869,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8646,0,0,0,0,25641,17796,0,0,0,0,0,0,0,
-13316,620,6309,11819,0,0,0,0,0,0,0,0,0,904,1095,0,24229,0,0,28744,49703,0,23077,
-0,0,0,0,32392,0,0,0,0,35271,0,28740,5866,0,0,0,0,0,0,0,4361,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7917,8869,0,0,0,13924,0,0,0,0,
-0,41958,0,0,0,0,0,0,6766,13989,0,0,0,903,0,0,24010,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,64390,0,22468,0,25861,0,0,0,0,23656,5317,0,0,0,0,0,0,23017,5445,16009
-,0,0,0,0,0,0,0,0,48006,10473,0,0,14404,0,0,0,42183,0,0,0,51270,0,0,10602,24132,0
-,0,0,0,0,43782,0,0,17834,0,0,0,25576,27205,0,0,0,0,0,0,0,0,29066,0,0,0,0,0,626,
-1988,14700,0,0,0,0,0,0,0,0,0,0,0,0,57670,0,0,0,0,0,0,0,0,0,44710,0,0,0,0,3848,
-7623,0,0,0,0,0,0,0,0,0,0,0,42374,0,0,0,0,0,0,0,0,19272,6436,0,0,5256,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,19685,0,0,0,0,0,0,0,0,0,0,0,0,0,39783,0,0,0,0,30984,0,0,0,0,0,0
-,28230,0,0,0,29028,10538,3205,0,0,0,0,0,0,0,0,0,0,0,5636,840,295,0,0,8488,8198,0
-,0,0,0,0,0,0,0,0,20580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4074,19526,0,0,0,0,
-31144,64038,0,0,0,0,0,0,16716,0,0,0,0,0,0,0,0,0,0,0,17706,0,0,0,0,0,0,50630,0,
-50503,0,0,0,0,0,0,0,0,0,0,0,25446,0,0,0,13831,0,0,0,0,0,0,2696,4039,0,0,0,0,
-25288,0,12076,2054,0,48934,0,0,0,0,16969,59431,17259,35335,0,0,0,0,0,0,0,0,0,0,0
-,0,31275,0,0,0,1097,0,0,0,0,0,0,0,0,0,0,0,776,839,0,0,29386,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,5864,12134,0,0,0,0,0,0,0,25349,0,0,0,0,0,0,0,0,0,61447
-,0,0,0,0,0,0,0,0,0,24678,0,0,0,63335,0,28836,8142,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4494,0,0,0,0,0,14088,1188,0,16260,0,0,0,
-16421,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,276,0,0,17060,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24076,29445,0,33543,0,4901,0
-,0,12522,0,0,62471,0,0,0,0,0,0,0,0,0,0,4046,0,0,0,0,20486,0,15460,2217,51719,0,0
-,0,0,0,23495,0,0,0,0,0,0,15370,0,15849,0,15113,0,0,0,0,0,0,0,0,27972,7337,0,0,0,
-0,30342,0,0,0,0,0,0,0,0,32299,23940,0,17766,0,0,0,0,0,0,6184,0,20904,0,0,0,0,0,0
-,0,0,0,0,31492,0,0,0,5509,0,0,0,0,0,0,0,0,2669,50182,0,0,12299,0,0,0,0,0,0,0,
-5257,28167,0,0,0,0,0,0,0,0,0,0,0,11750,3890,0,0,26500,0,0,0,0,0,0,0,49318,0,0,0,
-0,0,0,0,10981,0,0,0,0,0,0,0,0,17961,1831,0,0,0,0,0,0,0,29638,0,0,0,0,26473,0,
-6216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,711,0,0,0,0,0,0,0,0,0,0,28683,39975
-,0,0,0,0,0,51654,0,0,0,27527,0,0,0,0,0,0,0,0,30859,3268,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28772,0,18212,0,0,0,0,25448,65446,0,0,0,0,
-0,0,3337,1670,0,0,0,0,0,19332,0,0,0,0,24936,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1043,0
-,0,0,0,15814,0,21670,0,0,0,0,0,0,0,16263,0,0,0,0,0,0,0,0,0,32454,0,30630,0,0,
-20170,9926,0,0,0,18247,0,0,14376,0,2056,17191,0,0,0,0,0,0,0,7812,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,22474,52806,1588,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10825,0,
-0,0,0,40934,0,0,0,0,0,0,0,28677,0,0,5714,0,0,0,0,0,0,0,0,0,0,0,0,0,25865,22246,0
-,0,0,0,17256,35751,0,0,0,0,0,0,0,0,8236,0,32108,0,0,0,43,14342,0,16517,0,0,30732
-,0,4012,133,0,40583,971,23942,0,0,27275,0,0,0,204,0,0,27140,7564,44327,27592,
-57958,0,0,0,0,22344,25701,0,0,0,0,0,0,0,19524,31755,0,0,28102,0,59111,0,0,0,0,0,
-0,0,12261,0,44934,0,0,0,0,31560,0,11114,0,0,0,0,0,0,0,0,0,0,0,18953,18311,0,
-45159,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2059,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-19399,0,0,0,0,0,0,0,0,0,0,0,0,0,58534,0,0,0,0,0,0,0,0,0,0,0,0,22411,23943,0,0,0,
-0,0,0,11690,0,0,4069,0,0,2668,6342,0,0,0,0,0,0,27658,1766,0,0,0,0,23240,56070,0,
-0,0,0,0,0,0,0,0,0,0,0,0,34119,0,24453,0,0,0,0,21867,0,17610,9894,0,0,27976,38790
-,0,0,0,43654,0,31559,12202,23142,0,0,0,50343,0,0,0,0,0,32806,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,49895,0,0,0,0,15786,4263,0,0,0,0,4746,3814,0,0,0,0,0,0,17192,
-453,17323,0,20328,4036,0,0,0,15844,0,0,0,0,27561,31940,32296,0,0,0,0,0,0,0,11499
-,11782,0,0,0,0,9738,50471,0,0,0,0,0,35430,0,0,0,0,0,29734,0,0,0,36551,0,0,0,0,
-9257,5606,0,13829,0,7015,0,0,0,0,0,25127,0,0,19051,0,0,0,0,0,0,0,0,0,0,0,0,0,
-2572,0,0,0,0,0,0,29797,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42342,0,0,0,0,9293,
-0,17896,56038,4077,0,0,0,29899,37351,0,30823,0,8326,0,0,0,18342,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18569,54054,0,0,0,0,0,0,0,0,0,37254,0,0,31433,
-61510,0,2022,0,0,0,0,0,25381,0,0,0,0,0,0,0,0,0,0,0,0,0,2149,25289,0,0,0,0,0,0,0,
-0,0,0,12516,14185,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8676,0,0,0,0,0
-,0,0,0,0,0,0,36486,0,0,0,0,10889,9607,0,28711,0,0,0,0,0,0,0,0,0,0,28490,0,0,0,0,
-26181,10283,1701,0,0,0,0,0,0,0,0,0,14980,0,7783,0,27846,0,0,0,56486,3892,0,0,0,
-5770,16583,0,26309,13422,20292,0,0,0,0,0,0,0,0,0,28742,0,0,0,0,14536,1158,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25801,0,0,0,0,0,0,0,0,0,0,0,0,42438,0,3332,0,0
-,0,0,0,0,0,0,0,8327,0,0,0,0,0,0,0,0,0,0,0,0,17353,1447,0,0,8427,48518,1359,0,0,0
-,0,0,14986,0,32168,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9230,2791,0,0,0,0,0,0,0,0,
-16073,31623,4269,0,0,0,0,0,0,4519,0,0,27912,58950,0,0,0,0,0,0,0,0,8361,19812,0,0
-,0,0,6056,7877,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21701,0,0,0,0,0,0,0,0,0,0,0
-,0,9128,1125,0,16548,0,0,0,0,0,0,0,0,0,0,17292,6854,21352,0,2380,0,0,4007,0,0,0,
-0,0,24357,4202,0,0,0,0,0,0,0,0,0,0,0,0,0,10664,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,42823,3022,0,0,0,0,0,0,0,0,0,0,0,0,14373,0,20677,3304,2759,20522,64903,0,
-0,0,38,0,0,0,0,0,0,0,0,0,0,0,27814,2802,8870,3758,1255,0,0,0,0,0,0,0,0,30027,
-9510,0,0,0,0,17864,14855,0,0,0,0,0,0,0,0,0,0,23404,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-51462,0,0,0,0,0,0,0,45734,0,0,23467,32327,0,0,10826,52999,0,0,0,33222,31336,
-64326,0,0,0,0,0,0,0,32166,0,0,3891,0,0,0,7017,645,0,0,0,0,0,0,27915,46087,0,0,0,
-21863,0,34246,0,0,16715,0,0,0,0,14052,21416,0,0,0,0,0,0,0,0,39846,0,0,0,0,0,
-38982,0,0,17512,7460,0,0,0,0,0,0,0,0,0,15428,0,0,0,0,0,0,0,28356,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,25445,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11879,0,0,0,0,0,0
-,0,0,0,0,0,0,0,19911,0,20007,0,0,0,10855,943,0,0,10821,0,0,0,0,4170,0,0,0,0,0,0,
-0,0,0,9836,0,0,0,0,0,0,0,0,0,0,65415,0,0,0,0,0,0,0,0,9865,24646,0,0,0,0,0,40519,
-0,0,0,0,0,0,0,0,0,12804,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22091,23655,0,0,0,0,0,0,
-0,31686,0,0,0,58599,0,0,0,0,0,0,0,0,0,0,0,0,0,19620,0,0,0,0,0,0,0,0,0,0,0,0,0,
-24421,0,28100,0,0,0,31268,0,3204,0,0,0,0,0,0,0,0,0,14822,0,0,0,0,19947,10182,0,0
-,9480,14821,4398,0,0,14532,0,0,0,48871,1873,0,0,0,0,0,0,0,589,1541,0,0,0,0,0,
-23333,0,0,0,14149,0,0,0,0,1296,14374,0,27300,0,0,0,0,0,0,7276,0,0,0,0,0,0,47718,
-0,0,0,0,0,0,0,0,0,0,5164,1765,0,14405,0,37574,1994,0,6636,0,0,0,0,0,0,0,0,27815,
-0,0,0,0,2568,6820,0,0,0,0,0,0,0,0,0,0,11336,26247,0,0,23912,0,0,0,30536,0,0,
-34342,0,17799,0,0,0,22149,0,6118,0,25732,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,26600,5190,0,0,1142,0,0,0,0,0,0,0,0,39527,0,0,0,0,0,39494,0,0,0,0,0,0,0
-,0,0,0,3085,0,0,0,0,0,0,0,4786,0,0,0,28873,6532,0,0,26664,0,9193,11719,0,0,0,0,0
-,0,31752,64646,0,0,0,0,0,0,0,0,0,0,0,11397,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25094,0
-,0,18153,20167,0,0,0,17254,0,0,878,0,0,0,0,0,0,0,0,0,0,24166,0,0,0,0,0,0,0,0,0,0
-,0,0,26059,0,0,0,0,0,0,0,0,0,0,0,0,0,31592,0,0,8167,24362,6212,0,34758,0,0,0,0,0
-,0,32520,0,0,44679,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17989,8681,29222,0,0,0,
-0,0,0,0,0,10251,4902,1452,15207,0,0,0,0,0,0,0,22822,0,10469,0,0,0,0,0,0,19337,
-17670,107,11494,0,0,0,0,27305,2565,0,0,0,0,0,0,0,64518,200,28389,0,0,0,0,31208,0
-,30762,0,0,0,0,0,29321,60518,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3209,3237,
-12490,22663,0,0,0,18789,31464,16391,0,0,0,0,0,0,0,0,0,0,0,20646,0,0,0,27238,0,0,
-0,0,0,15940,4488,6951,0,0,0,46342,0,0,0,0,0,0,0,0,0,28965,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,20584,3367,0,25350,0,0,0,0,0,0,0,0,0,0,0,0,1814,0,0,0,0,0,0,0,0,0,0,17125,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55943,0,0,0,0,0,24133,0,0,0,0,0,0,0,0,0,0,0,0,2929
-,0,0,50086,0,2918,25356,30052,115,11846,0,0,0,0,3056,0,0,0,0,17639,239,19815,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36806,0,0,0,0,0,0,0,0,0,0,0,0,0,21479,0,0,0,0,0,
-28420,11786,4772,0,0,3368,36295,0,31463,0,0,14665,996,0,20582,0,0,0,9988,0,23685
-,0,0,0,52551,0,0,0,0,0,0,0,7556,0,0,0,0,0,0,0,1895,2186,0,0,0,0,0,27755,25447,0,
-0,0,0,31052,63270,0,0,0,0,0,0,0,36742,0,24804,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,31048,0,0,0,0,0,0,0,0,0,21290,2276,0,0,0,0,26475,0,0,0,0,0,0,0,0,0
-,0,15332,0,0,0,0,0,0,0,0,3176,19431,0,0,0,0,0,0,0,62726,0,0,0,25380,0,0,27883,
-1316,0,0,7724,3015,0,0,0,0,6697,0,0,47910,0,0,0,0,0,0,0,0,0,3141,0,0,0,14820,0,0
-,0,0,9326,0,0,0,0,0,0,0,0,0,0,31493,0,0,0,0,0,6566,0,0,0,0,0,0,6569,1348,0,25638
-,0,0,0,0,0,20324,0,0,17067,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11876,0,41030,0,0,0,26405
-,0,0,0,0,0,0,0,0,0,11431,28137,14950,0,10151,0,0,0,0,0,0,0,29574,0,0,0,0,27176,
-57446,0,0,0,0,28650,57574,1387,0,0,0,0,0,0,0,0,0,0,58247,0,0,0,0,0,0,0,16805,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3526,0,15781,0,5572,13352,0,0,0,0,0,18665
-,23463,0,0,0,0,0,0,15405,6885,0,0,0,0,15272,0,0,0,0,0,0,0,0,9861,0,0,0,0,0,0,0,0
-,9512,4037,0,0,11563,49639,0,0,0,0,0,0,27880,57830,0,0,0,0,0,41831,0,21924,0,0,0
-,0,0,0,0,25509,0,27462,0,18085,0,0,0,0,0,0,0,0,0,0,0,0,13898,8068,26441,0,0,0,0,
-0,0,25316,0,0,0,0,16298,7397,5706,19239,0,0,0,0,0,0,0,0,1392,50919,0,0,0,0,0,
-53863,0,0,0,0,1451,0,0,0,0,0,0,0,0,0,0,35847,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,17801,15813,0,12740,0,0,0,32967,0,0,0,0,0,0,5389,0,0,0,0,0,0,0,0,0,0,31143,0,
-20548,0,0,0,0,0,0,0,0,0,51686,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-12109,19015,0,34983,0,21732,3600,0,0,0,0,47750,17288,43975,22857,47559,0,0,0,0,
-26408,48358,0,0,0,0,0,0,0,0,0,0,0,0,0,30470,0,0,23560,4581,0,22404,0,49286,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49831,0,0,0,27525,31691,7,0,0,25835,0,0,0,0,0,
-4201,16485,0,20676,0,0,0,0,3753,23303,16264,3878,0,0,0,0,0,0,11434,0,0,0,0,0,0,
-7589,0,0,0,0,0,0,0,0,0,57095,0,0,0,0,0,0,0,0,0,0,0,22820,11146,49158,0,23623,0,0
-,0,0,0,0,0,13893,0,0,0,0,0,0,11722,60071,1258,0,0,0,0,0,0,18564,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,27945,0,0,0,0,5479,0,20006,17608,3431,10988,30180,0,0,0,0,0,0,0,
-24581,14,0,0,0,0,0,0,25572,0,0,0,28612,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,53543,0
-,0,0,0,0,0,0,0,0,0,0,33670,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8710,0,14116,0,0,116,
-292,0,0,0,37831,0,43078,0,0,0,0,0,0,0,0,21832,0,0,32134,783,0,0,30982,0,0,0,68,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5932,0,0,0,18505,
-15175,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3630,16965,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,17797,0,0,0,0,0,0,520,42150,0,0,3122,0,0,0,22506,0,0,0,0,0,0,0,0,28550,0,
-0,0,50278,0,0,13641,5958,0,35238,0,0,0,0,0,0,0,0,29993,18724,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,20619,9319,0,0,0,0,23977,0,5193,0,0,12196,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,24390,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20105,677,0,0,0,0
-,0,0,0,0,29419,0,0,0,0,0,0,0,0,0,20266,0,0,0,0,10631,0,0,0,0,0,0,0,0,0,47655,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26628,12744,0,20648,0,0,0,432,0,0
-,0,0,0,0,0,0,0,0,646,0,25604,0,0,0,0,0,0,0,0,0,0,0,0,0,63782,0,0,0,0,24616,0,0,0
-,21291,0,0,0,0,0,0,0,0,0,0,45638,0,0,0,0,1931,0,0,0,20521,59975,0,20614,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,56231,0,0,0,0,0,29991,0,52871,0,20934,0,0,0,0,0,0,0,16871,
-0,0,0,0,0,0,0,0,0,0,0,0,0,7237,0,0,0,0,0,47558,0,0,0,0,0,0,0,0,0,0,0,10406,0,0,0
-,0,0,0,0,43046,0,0,2930,0,12936,0,0,0,0,0,0,0,0,0,0,0,0,31141,0,0,0,0,0,0,0,
-37639,0,17572,0,0,0,0,0,0,0,0,0,0,31240,0,0,0,0,0,688,0,0,0,0,0,1648,0,0,0,0,
-10055,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,146,0,0,0,0,0,0,0,0,0,6345,199,0,34982,0,0
-,0,0,0,0,0,0,0,0,0,0,0,56839,0,0,0,0,0,48902,0,13412,0,0,0,0,0,0,0,0,2441,4420,0
-,0,0,0,20428,933,0,0,0,0,0,0,0,45383,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,54726,0,0,0,0,0,0,0,0,0,0,0,0,17036,741,0,0,0,0,0,0,0,27589,0,0,30282
-,18950,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2248,0,0,0,0,0,0,0,0,0,25993,0,0,0,
-2443,0,0,31622,0,14150,0,0,0,28679,0,0,0,0,0,0,15464,0,0,0,0,54694,0,0,0,0,0,0,
-3827,0,0,0,3756,0,9897,0,0,0,0,0,19082,31239,0,0,0,0,0,0,0,0,0,0,0,24580,0,0,0,0
-,0,0,0,0,0,16580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27625,0,0,0,784,4647,32652,0,0,
-63494,0,0,0,0,0,0,0,21062,0,0,0,0,0,0,0,0,0,0,3404,58470,0,32325,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,18634,2789,0,0,0,0,0,0,0,8548,0,0,0,22501,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,15881,0,0,0,0,35879,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7978,17956,0,0,0,
-0,0,0,0,24324,0,0,4937,0,0,0,8168,0,13420,10340,0,0,0,0,0,11780,0,0,0,0,0,0,0,0,
-0,0,16712,0,0,0,0,0,0,0,17640,17991,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,2953,0,0,0,0,0,0,0,9100,16806,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30667,0,0,
-19013,0,0,0,0,0,0,205,15334,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1969,0,0,0,0,0,0,0,26248
-,52518,0,49798,0,0,0,0,0,0,0,9668,0,0,0,0,0,4742,0,0,21641,0,0,0,0,0,0,53574,0,0
-,0,0,0,0,5707,0,0,0,0,0,0,0,3018,12454,0,0,0,0,2920,262,0,0,0,0,0,0,0,0,0,0,3593
-,0,0,0,0,0,0,0,0,0,0,23910,0,0,0,0,0,0,0,55879,0,0,0,0,0,775,0,43270,5066,48967,
-0,0,22986,4165,8971,44838,0,0,0,0,0,62279,272,0,0,0,0,51430,0,0,0,0,0,0,28234,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13349,0,0,0,51111,20265,13861,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,585,7494,0,0,0,0,0,0,0,0,21768,62407,0,0,0,0,7979,166,0,
-0,0,0,0,0,0,0,0,38918,0,56742,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16296,5767,0,0,0,0,0,0
-,0,32068,0,0,0,0,0,0,0,0,0,0,0,0,0,29796,0,0,0,0,0,0,0,0,23916,30183,0,58791,0,0
-,0,0,0,0,0,20518,0,0,0,0,8969,0,0,0,183,0,0,0,0,0,2314,17445,0,0,0,0,0,0,0,0,0,
-23748,0,0,8139,4839,27914,0,0,0,0,0,0,0,0,0,0,0,0,29478,0,0,16552,26663,0,53767,
-0,0,13960,8039,18696,0,0,0,0,0,0,0,0,0,0,0,782,16005,0,0,0,0,0,0,0,0,6258,56806,
-16456,12455,0,0,0,0,0,0,0,23780,0,0,0,0,0,0,9355,0,0,0,7273,41063,24780,57766,0,
-0,0,0,0,0,0,0,0,0,3820,2597,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29225,61126,0,0,0,58439,
-15691,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37190,22408,967,0,0,0,
-23078,26858,0,0,0,19753,0,0,0,0,0,0,0,0,0,5416,13702,0,0,0,0,0,52742,20394,38567
-,0,0,0,51079,0,0,136,8516,0,0,0,0,0,0,0,0,0,0,0,27588,0,0,0,0,0,0,0,0,0,0,531,0,
-0,0,0,0,0,0,0,0,8936,5031,12520,19334,0,0,22827,30247,28074,31140,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,27497,18148,20104,59079,0,0,0,0,0,0,0,0,0,24389,0,0,6125,0,0,0,0,
-9541,0,0,24553,29095,0,0,0,0,0,0,0,25444,0,0,9643,0,0,63047,0,0,0,0,0,0,0,0,0,
-39558,0,0,0,0,0,0,20620,11815,499,0,5128,2278,0,0,0,0,0,46310,0,0,0,0,0,0,0,0,
-23530,40166,2440,0,0,0,0,0,0,0,0,0,0,15174,0,0,0,0,0,0,0,0,0,0,26922,0,0,0,0,0,0
-,0,0,0,0,26758,0,0,0,0,0,51911,0,0,23532,0,0,0,0,51238,25737,44486,12622,0,0,0,0
-,0,0,3078,0,9253,0,0,1128,22023,0,0,0,21350,0,16420,0,0,0,0,0,0,0,65094,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22532,0,48774,0,34503,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,9797,0,0,0,0,0,0,0,13797,0,38279,0,0,1738,0,489,46343,0,45382,0,0,0,0,0,0,
-0,0,0,29030,0,0,0,0,0,0,6220,56550,0,0,0,0,0,26885,0,28806,0,0,0,0,0,0,0,0,0,0,0
-,45958,0,0,0,0,20553,49927,0,0,0,0,0,0,3019,12358,0,0,0,0,0,0,0,0,0,0,26571,
-13319,0,0,653,23399,0,0,0,0,0,0,0,0,22316,0,0,21188,0,0,0,0,0,0,0,0,0,27556,0,0,
-0,0,0,0,0,27878,21483,27653,0,29701,237,0,10632,0,0,0,0,33766,0,0,0,0,0,0,31563,
-0,0,0,0,0,1416,2439,0,0,0,0,0,0,0,0,0,0,9611,0,0,0,0,0,0,0,5611,16581,26601,
-35462,0,0,0,26756,0,59271,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26984,57734,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,7882,0,0,0,19528,6469,0,0,1161,0,0,0,7688,20935,425,0,
-0,0,0,0,0,0,0,12519,0,12902,0,0,0,0,0,0,0,0,0,0,2411,0,11725,26086,0,0,20201,0,0
-,0,0,0,0,0,0,11045,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30471,0,0,0,0,0,0,0,0,0,0,0,
-21541,1141,21190,0,9188,0,0,0,0,0,0,0,0,0,0,0,0,0,0,184,1093,0,0,0,0,0,0,0,0,
-4842,0,13672,0,0,12230,0,0,0,10532,0,0,8937,0,0,0,0,0,0,0,0,0,0,28996,0,0,11720,
-26982,0,46182,0,43911,31754,0,1160,3940,0,20772,0,0,0,0,0,24549,0,32582,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,31845,0,0,0,0,0,0,0,2310,11788,0,0,43047,0,0,0,18853,0
-,0,0,0,0,0,0,0,0,63622,0,0,7048,17318,0,0,0,21957,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,1039,6279,0,0,0,0,0,0,0,0,0,0,0,0,0,12197,0,0,0,0,0,0,0,0,0,
-46470,0,0,24,19719,0,0,0,0,0,0,0,0,0,39335,0,0,0,0,0,0,0,0,0,0,21353,3846,0,0,0,
-0,0,0,0,36679,0,0,0,0,0,0,0,0,0,0,0,11268,0,0,0,0,0,9382,0,0,0,0,0,0,0,0,0,0,0,0
-,0,29926,0,33606,0,4708,2828,0,0,29543,0,0,0,0,0,29893,0,0,0,0,0,0,0,0,3663,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10920,7111,0,0,0,0,0,0,0,0,0,0
-,9384,0,0,0,0,0,0,0,0,0,0,0,0,20388,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37094,0,0,0,
-27110,0,0,0,0,0,0,21865,0,27753,30214,0,0,0,0,0,57895,0,0,0,0,0,0,0,0,0,0,12648,
-5446,0,0,0,0,0,0,0,0,0,0,19784,17124,0,52007,0,0,0,0,0,0,0,0,758,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,24900,0,0,0,0,0,1476,0,65031,0,0,1205,46663,0,30023,11625,
-1094,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10058,0,0,0,0,0,0,28455,0,0,0,0,0,0,0,0,0,0,0,
-14788,0,0,0,0,16808,0,0,742,0,0,0,0,0,0,0,0,0,0,0,21636,0,0,0,0,0,0,0,0,0,0,0,0,
-15944,23207,0,0,0,0,247,0,0,0,0,24743,0,0,0,5252,0,0,0,0,0,0,0,0,29961,18660,
-21099,46791,0,7045,0,0,0,0,25707,0,0,17412,3828,0,0,0,0,0,0,0,0,0,0,0,5803,5637,
-0,38151,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60103,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,853,0,0,0,0,0,0,30215,0,0,0,0,0,0,0,8741,0,0,0,0,0,27366,0,0,0,0,171,
-4070,0,0,0,0,0,0,0,0,24073,7366,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2184,5189,0,
-20932,1545,4996,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7684,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6313,0,0,0,0,0,0,0,30826,0,0,0,0,0,0,
-0,0,0,0,27463,0,0,0,0,0,0,0,0,0,0,21640,63303,0,0,3275,31111,0,0,0,0,0,0,0,11556
-,0,14756,0,0,0,15108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23914,28966,0,0,0,4965,0,0,0,0,
-0,0,0,0,0,0,10216,5223,0,0,0,0,0,0,0,0,0,27142,0,0,1173,20198,0,0,0,0,0,56614,0,
-0,0,0,0,4612,0,0,0,0,0,0,0,0,0,0,11822,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17769,7910,
-0,0,31880,0,0,6055,0,0,0,0,0,0,0,0,0,0,8970,0,0,0,0,0,0,0,0,0,0,0,16840,23879,0,
-0,11051,0,0,0,32552,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20842,13701,0,0,0,37191,7373,
-10471,17482,25348,0,0,0,38502,0,0,0,0,0,0,0,0,0,21509,6058,0,0,0,0,0,0,3173,0,0,
-0,9543,0,0,0,0,0,0,17768,12708,0,0,0,0,0,37030,0,0,0,0,0,0,0,0,0,0,12748,48743,0
-,11718,0,0,25194,0,0,0,9033,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5028,0,30118,0,0,0,0,0,
-42759,0,0,3720,0,0,0,0,0,0,25190,0,0,0,0,0,0,0,0,0,0,5450,5125,0,58086,0,0,0,0,0
-,27716,0,0,0,0,0,0,0,0,0,22052,0,0,0,0,26249,0,15947,3460,0,0,0,35814,0,0,0,7813
-,19500,32167,0,18597,0,0,0,0,0,28644,0,0,0,60743,0,0,0,0,0,29636,0,0,0,0,0,0,0,0
-,0,0,0,0,0,17220,15885,9414,9642,0,0,0,593,0,0,24228,0,0,0,0,0,40422,0,26244,0,
-23109,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64902,0,0,0,0,3979,60007,0,0,0,28199
-,0,0,0,43142,0,0,0,0,0,0,0,29158,0,30532,0,0,0,0,13256,0,0,0,0,16549,0,0,0,0,0,
-26116,0,0,0,0,0,0,0,0,22825,0,0,0,0,0,0,0,1065,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,18985,4805,0,0,0,0,0,17702,0,0,0,0,0,0,0,0,0,0,3468,0,0,0,0,13447,0,0,0
-,0,0,0,0,0,0,0,0,56871,0,0,1776,15780,0,0,2603,0,10280,31366,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,11592,3591,0,2372,0,0,0,0,0,0,0,20004,0,0,0,0,0,0,12072,518,0,0,1960,
-8999,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7178,32999,0,0,0,0,0,0,1641,0,0,0,0,0,0,0,6764,
-9893,490,4005,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25258,5541,0,14053,306,20743,0,0,
-9422,0,0,0,0,0,0,0,11977,260,0,35175,0,0,0,0,0,0,0,18405,0,0,0,16582,0,0,0,22470
-,0,0,0,0,0,0,2792,0,0,0,14026,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14858,3909,0,0,0
-,57671,0,0,0,0,0,0,15979,0,0,0,2794,15239,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26884,
-9070,0,0,0,0,51846,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19499,37127,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,19205,10350,11910,0,0,0,0,15083,23108,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,169,0,0,0,0,0,0,0,0,0,0,0,15274,41735,0,56774,0,0,2825,0,14025,
-389,0,0,0,0,0,0,0,0,21482,31910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20456,710,0,0,25032,
-21797,0,0,0,0,0,0,0,0,0,0,32427,21252,0,30150,0,43174,0,0,0,0,0,0,0,0,0,0,0,0,
-11403,0,0,1029,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6892,9252,0,63206,
-3496,14406,0,0,0,0,0,0,0,0,0,0,22568,0,0,21253,0,0,0,0,0,0,0,39623,0,0,10189,0,0
-,0,0,0,0,0,0,0,0,0,0,0,30729,59910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3305,0,0,0,0,0,0,
-0,0,0,7660,24871,0,838,0,0,0,0,0,0,0,0,0,0,0,0,12013,13252,0,551,0,0,0,43207,0,
-30567,0,0,0,0,0,0,0,0,28394,30724,0,0,0,0,0,0,0,0,0,0,22665,22725,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,29414,0,0,0,0,16074,8966,245,1445,0,0,0,0,24872,0,0,0,0,
-13124,0,35527,0,0,0,0,0,0,13259,10917,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-25191,0,0,0,13956,0,0,0,0,0,0,0,54631,19625,12070,3083,0,0,0,0,14436,0,0,0,0,0,0
-,0,0,0,0,0,0,0,21766,0,15463,29322,0,0,0,0,0,0,29990,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,23653,0,0,0,0,0,0,0,0,2643,0,0,21223,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,4114,0,0,0,0,0,0,0,0,34790,0,0,0,0,0,0,0,16103,0,0,0,0,0,0,297,3620,3338,
-10372,0,14727,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29924,22473,13895,
-15529,32455,30378,13540,0,28807,0,0,0,0,0,0,0,64582,18380,0,0,0,0,0,0,0,0,0,0,0,
-0,38598,0,0,0,0,0,0,0,0,1236,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32710,0,0,0,0,4590,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64935,0,0,0,0,0,0,0,0,0,0,0,0,16744,0,0,
-0,0,0,0,20005,0,0,13608,1191,0,0,0,62183,0,0,0,0,0,24484,0,0,0,0,0,0,0,0,0,0,
-17643,0,0,0,0,0,0,0,0,0,0,0,0,5380,0,0,32328,0,0,63814,0,0,0,2919,0,0,0,0,17034,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,60295,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,7690,486,0,0,0,39270,0,49094,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12555,0,0,0,0,0,0,0,0
-,0,0,0,0,20967,17993,12647,0,0,0,16036,32616,0,0,0,0,16294,8555,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35174,0,0,0,0,0,0,30346,0,0,0,0,0,0,0,
-14797,3652,0,0,8268,12934,0,54950,0,0,0,0,2632,33959,0,23175,0,0,0,0,0,36262,0,0
-,0,0,0,0,32684,26918,0,32676,0,0,0,0,0,0,0,0,0,0,15625,11943,1206,0,0,0,0,18052,
-0,0,0,0,0,16422,0,0,0,26404,0,0,28777,0,0,24902,0,0,408,45351,0,35719,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,3658,17446,0,165,0,0,0,0,0,0,0,6151,0,0,24424,0,0,0,0,0,0,0,
-24170,24293,0,0,0,0,0,0,0,0,0,11847,0,39591,0,0,0,0,0,0,9549,2788,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1010,0,0,0,0,0,0,26055,31724,0,24233,
-1828,0,0,0,0,0,0,0,0,0,17284,0,0,0,0,19464,0,0,0,0,0,0,0,0,32452,0,0,0,28871,0,0
-,0,0,17704,53383,0,0,0,0,0,0,0,0,0,17892,1938,0,0,0,0,0,16362,0,0,21605,0,0,5003
-,0,0,0,0,0,0,22693,0,22342,0,0,0,55846,0,0,0,0,0,0,0,0,0,22853,0,0,0,0,0,0,0,0,
-6600,263,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24836,0,0,0,0,0,0,0,0,0,
-40711,0,0,0,0,0,33894,0,0,0,0,0,0,13000,0,0,0,0,0,0,0,0,0,0,30308,0,0,0,0,0,0,
-5386,0,0,0,0,0,0,27844,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17740,0,0,0,0
-,25093,29064,0,0,0,0,0,0,0,12680,11462,0,0,0,0,0,0,0,0,84,7303,0,0,0,0,0,0,0,0,0
-,0,0,27044,457,0,22924,58246,19016,0,2606,45703,0,5157,0,25028,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,2065,0,0,0,0,0,31946,0,0,0,0,0,0,0,0,0,0,0,0,33382,0,
-47878,0,0,0,0,0,0,0,0,25004,0,0,0,0,0,0,0,26153,35654,0,58055,30668,0,0,0,0,
-25988,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4456,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,7560,20583,0,0,0,0,0,0,0,0,0,37510,0,0,0,0,0,0,0,0,0,42822,0,0,0,0,0,0,0,0,
-0,0,0,1733,0,0,0,8196,0,0,11241,0,30572,60326,0,15013,0,0,0,40646,0,23812,0,
-10022,0,0,0,0,0,0,0,0,12874,31015,0,0,0,0,0,0,1608,0,0,0,0,18308,0,0,0,0,27114,0
-,0,0,0,0,0,0,7944,1382,0,11813,0,0,0,0,0,0,0,0,0,0,0,0,0,24517,0,11621,0,0,0,0,0
-,0,0,0,0,0,0,21702,0,0,13100,8262,2644,7973,0,0,0,0,0,0,0,0,0,0,0,0,1033,12581,0
-,25221,0,0,0,40998,16301,62983,0,0,0,0,1263,9318,0,0,0,18854,0,0,1741,33895,0,0,
-0,0,0,0,26377,0,0,0,0,0,0,0,0,0,0,32165,0,51143,0,0,0,0,0,29412,0,0,0,0,0,0,0,0,
-1674,4230,0,0,0,0,0,10502,0,0,0,0,5545,0,0,0,0,0,2099,45158,0,0,0,0,0,0,0,0,0,0,
-14157,0,26955,0,0,0,0,0,0,0,0,0,17096,0,0,0,0,0,0,0,0,0,0,0,0,0,27050,6726,0,0,0
-,0,0,0,0,0,28554,0,0,7142,0,0,0,0,16936,0,0,0,25833,0,4399,6980,0,46214,0,0,0,0,
-0,10630,21164,0,0,0,0,0,0,0,2446,48551,0,0,0,0,0,0,0,0,0,0,0,13381,0,0,0,0,0,0,0
-,0,15400,12135,0,0,0,0,0,4774,586,0,0,0,0,0,0,0,0,23751,9736,4548,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25577,29607,6250,1637,0,0,0,0,
-22024,0,0,0,0,22308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37414,24044,0,0,0,14474,29735,
-0,7077,0,45990,0,0,0,0,30568,40039,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-6150,0,4228,0,0,0,0,0,27687,0,0,0,0,0,0,0,24548,21513,1350,0,0,0,33607,0,0,0,0,0
-,0,0,0,11784,1414,0,0,0,0,0,0,0,18244,940,0,0,0,0,0,0,7270,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,16709,0,0,0,0,0,0,0,48935,0,0,0,0,0,0,23660,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,53350,0,0,0,0,0,0,4236,16358,0,4422,6665,32644,0,0,744,18084,0,11014,0,0,0,0,0,
-29508,0,0,0,0,0,0,0,7686,0,0,13289,5478,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,12872,0,0,24134,1005,22916,0,31429,23400,0,0,0,0,0,0,0,28424,0,0,0,
-25706,27109,0,0,26345,0,0,0,0,0,0,25126,0,0,88,0,0,0,0,0,0,0,17032,0,0,21799,0,0
-,10060,0,12296,21892,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20777,14311,0,58182,
-32232,0,10282,0,2121,11527,0,0,0,12325,0,0,0,0,0,0,0,28804,2344,8133,0,0,0,0,
-21864,62695,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2771,0,0,
-23204,0,0,0,0,0,6278,0,0,0,0,0,26597,0,0,0,0,23144,0,0,0,0,0,31816,20070,0,0,0,0
-,0,0,0,0,0,0,24456,2118,0,0,0,0,6570,1156,0,0,0,0,0,0,0,30406,0,0,0,28388,3572,0
-,0,26599,12426,5286,0,0,0,0,0,4967,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24970,24167,0,0,0
-,0,28745,4678,0,0,0,0,0,0,0,1444,236,0,0,0,0,0,0,0,0,19428,0,0,0,0,0,0,2092,0,0,
-0,0,0,0,0,0,0,2827,0,0,0,0,0,19881,19204,0,11749,0,0,0,0,0,0,0,17958,0,17894,0,
-18726,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9190,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,21510,5033,0,0,0,0,22855,0,0,0,0,0,14598,0,29605,0,0,0,0,0,0,0,0,
-617,0,0,0,0,47142,0,0,0,0,0,0,0,0,0,0,3627,0,0,0,0,0,0,0,0,0,0,0,0,0,2225,14823,
-0,0,2637,6182,78,15078,0,0,0,0,20264,0,0,0,0,0,0,36743,4140,44551,17352,25703,0,
-0,0,0,0,0,0,0,0,0,0,0,14024,0,0,0,0,0,0,28004,0,0,0,0,0,7588,0,0,0,0,0,0,0,2087,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18028,0,0,0,300,14212,0,0,1386,40327,0,0,0,0
-,0,0,31082,0,0,22374,0,0,0,0,0,35718,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-26532,7756,0,0,18982,0,0,0,0,0,0,0,0,6440,1159,7180,0,0,0,0,0,0,45766,0,57798,0,
-16740,0,0,6802,60454,0,0,0,26470,0,0,0,0,0,65382,4362,7750,0,0,0,0,0,0,9096,4743
-,334,0,0,0,0,0,0,39974,0,0,0,25828,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3027,0,0,
-0,15816,0,0,0,0,0,0,0,0,48327,0,0,0,0,0,0,0,0,0,0,16168,41799,0,0,24458,8581,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12292,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,54503,0,0,0,0,5097,30852,18664,0,0,0,0,0,0,16484,0,0,27337,0,0,0,
-0,0,0,0,0,0,0,0,0,35942,0,0,0,0,0,0,0,4356,0,0,0,0,0,57030,0,0,1417,41191,0,0,0,
-0,0,23429,0,0,0,0,10024,21735,0,0,10126,0,0,0,0,19046,0,0,0,0,0,0,24105,4710,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4394,0,0,0,0,13253,0,56391,0,0,0,0,0,0,0,0,0,0,
-0,19174,0,0,0,0,0,0,0,0,0,55974,0,0,0,52070,0,15620,0,0,0,0,0,2660,0,0,0,0,21644
-,0,0,52455,0,0,0,0,0,0,0,0,0,8902,0,0,0,0,0,0,3116,0,464,34726,0,0,0,0,0,0,25003
-,12423,0,27172,1896,7335,0,0,0,0,0,35686,0,0,0,0,3472,0,0,0,0,22406,0,0,0,0,0,0,
-0,0,0,45254,0,0,0,0,0,0,0,0,0,0,0,0,0,21124,23594,33127,0,0,0,0,0,0,16684,22087,
-0,0,0,0,0,0,0,0,0,0,0,0,8714,0,0,0,0,0,0,0,0,0,0,55814,0,0,0,0,0,0,4109,23460,0,
-0,8874,0,0,0,0,0,0,0,0,0,147,0,0,0,0,0,0,0,0,0,0,0,0,0,29960,63398,1302,0,0,0,0,
-0,0,0,0,24806,0,0,0,0,0,0,0,0,0,9799,0,0,0,0,0,0,0,31333,0,0,0,0,0,19557,0,0,0,0
-,0,5701,0,0,0,63014,0,0,0,0,0,0,0,21254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12484,0,0,
-0,48326,0,0,0,0,0,0,0,0,0,0,0,15783,0,0,1202,0,0,0,0,23174,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,3086,49191,0,0,5387,15141,0,0,0,3365,0,0,0,0,20076,14021,
-0,0,0,0,0,0,0,0,0,0,376,40198,0,0,0,52039,0,24932,0,0,0,0,808,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,9860,0,0,0,0,0,23719,0,21476,0,0,0,0,20776,4807,0,0,3177,16678,0,0,110
-,10853,0,0,0,17382,0,0,0,0,0,0,0,0,0,43462,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,7500,4966,0,0,0,0,0,0,0,52102,0,24516,0,0,0,0,0,0,0,0,0,0,0,0,0,26535,0,0
-,0,46247,0,0,0,15557,0,0,0,0,76,52327,0,0,0,0,17866,0,0,0,0,0,0,0,0,0,0,46758,0,
-0,0,0,0,19173,0,0,0,0,0,0,0,0,0,44038,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2985,0
-,0,0,0,0,0,14310,0,0,2125,45831,0,0,0,0,0,0,9838,0,13227,19492,0,0,0,29764,0,0,0
-,0,686,30053,0,0,0,0,0,30789,139,20837,0,0,0,0,502,18533,0,0,0,0,0,19111,0,0,0,0
-,0,31396,0,0,0,17444,0,0,0,0,0,0,0,49862,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25610,550,0
-,0,561,0,29034,0,0,0,3528,0,0,0,1715,14661,18,63463,0,0,0,0,0,0,0,0,0,0,14186,0,
-0,0,0,0,0,0,0,0,0,0,29578,59014,0,39430,0,0,0,0,2250,16612,0,31780,0,0,0,0,0,0,
-462,16967,0,29029,0,0,0,0,0,23462,0,0,0,0,0,0,0,0,1768,0,6025,16998,1804,0,0,
-54182,0,0,0,0,0,0,0,0,14124,0,6154,29702,0,0,0,0,0,7716,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,48807,0,8292,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16389,5933,0,
-14857,51303,0,0,0,0,0,0,0,0,0,0,0,35623,9097,23047,0,0,23112,0,0,0,0,0,438,0,0,0
-,0,0,0,0,151,9254,1390,0,0,0,0,0,0,54215,0,0,0,0,6187,0,0,0,0,13095,0,0,0,0,0,0,
-0,0,0,0,0,0,9866,0,0,59622,0,0,0,0,0,0,0,0,0,25286,0,0,23848,32069,0,0,0,0,0,0,0
-,0,0,9255,2187,15270,437,0,0,0,0,0,0,0,0,0,0,19493,0,0,0,0,0,0,0,0,0,0,0,11748,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16902,0,0,0,0,0,0,0,0,0,22212,1865,17543,0,
-0,0,0,0,0,21996,0,0,0,0,55975,0,0,0,0,0,0,0,0,32138,21156,0,0,0,0,0,0,14249,0,0,
-0,2388,0,0,0,0,6823,0,0,0,0,0,0,0,0,0,0,0,0,0,26694,0,0,6059,53511,0,0,0,0,0,0,0
-,49542,6159,0,0,0,0,0,0,0,0,0,0,0,0,0,1036,24036,0,2501,0,0,0,0,0,0,17419,51271,
-3377,15142,0,0,0,0,0,0,5007,62374,0,56935,0,0,0,0,0,0,0,0,0,0,0,24422,0,0,0,0,0,
-0,0,0,942,0,0,0,0,0,0,0,0,0,0,28263,0,0,0,0,0,0,0,15622,0,19749,0,0,1611,0,22219
-,48583,25129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17476,0,0,0,0,0,0,0,0,0,0,
-721,0,0,0,0,32518,0,0,0,18469,0,0,0,0,0,0,5896,29927,3657,23046,0,0,3214,0,0,0,0
-,0,0,0,0,0,112,0,0,0,0,0,3048,455,0,31012,0,0,0,0,0,0,0,23270,0,32677,0,0,0,0,0,
-38086,0,0,0,0,0,0,0,0,0,0,0,0,0,4900,0,0,0,0,0,0,0,0,0,25541,0,18788,0,0,22248,
-1351,0,61734,4524,30629,0,14887,242,29063,0,0,14408,4741,0,0,0,37318,0,0,0,0,0,0
-,0,0,0,0,0,0,8106,0,32107,0,0,0,0,0,0,0,0,0,0,0,1481,0,0,28132,0,25798,0,59783,0
-,0,0,0,0,59078,0,0,0,23366,0,0,0,0,0,0,0,30887,0,0,0,0,16200,0,0,0,335,0,0,0,714
-,0,0,0,0,0,0,0,0,0,0,0,0,0,30730,9478,0,0,0,0,0,0,0,0,0,0,0,18790,0,0,0,0,663,0,
-0,0,1034,31431,0,0,0,0,0,0,0,0,0,0,30120,0,0,0,0,13925,0,0,0,0,0,0,2280,13414,0,
-0,0,0,0,0,22028,23687,3017,11047,0,0,21738,18630,0,0,0,0,0,0,0,30246,0,0,0,0,0,0
-,0,0,0,0,0,0,17257,0,21896,63783,0,0,0,21094,0,18662,0,25700,0,22533,0,0,0,0,0,
-6341,5800,11111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15399,
-12970,6501,0,0,3179,26438,0,0,0,0,0,0,0,15750,0,13062,0,0,0,0,0,0,0,0,0,0,142,0,
-0,0,0,21284,11177,4391,0,0,0,0,19595,40647,0,0,0,0,0,11877,0,0,0,26439,0,0,0,0,
-695,49126,27467,11972,0,0,0,0,0,0,9961,0,0,0,31722,62982,0,0,0,0,15817,52710,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24614,0,0,0,0,0,20550,0,0,5034,3942,0,0,0,
-45927,0,0,0,0,0,0,0,0,0,0,2548,0,0,0,0,0,0,45606,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,3405,12582,15563,54087,0,0,0,0,0,0,0,0,0,0,0,0,24202,5893,0,0,0,
-44230,0,0,0,5605,0,47782,0,32230,0,0,0,0,0,0,0,0,0,0,0,7014,0,0,0,0,16488,3175,0
-,27237,0,0,0,0,0,40902,0,0,0,0,0,0,0,32004,31434,0,24392,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,29130,58214,0,0,0,0,0,0,29002,0,0,0,0,0,0,0,0,0,0,55366,0,0,0,0,0,0,0
-,0,0,0,0,37926,0,0,0,0,0,0,0,0,1290,0,0,0,4713,0,0,0,0,0,0,0,0,0,0,0,0,0,20812,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1803,966,0,17700,0,0,654,19109,0,51655,0,0,0,0,0,
-10470,1584,0,0,0,0,0,0,0,2506,0,0,25159,4303,0,0,0,395,15879,0,0,0,0,0,0,0,0,0,0
-,1352,6535,0,19652,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4722,7909,0,0,0,0
-,30152,0,0,64742,0,0,0,0,0,0,2153,9125,0,0,279,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,41894,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,1328,17030,0,0,0,0,0,0,0,54151,0,0,0,0,1775,54535,0,0,0,0,31624,0,0,0,
-7150,0,0,0,0,0,0,0,1840,35943,0,0,0,0,0,56455,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-64486,0,0,0,51174,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4134
-,0,0,0,0,0,0,0,0,0,0,0,17092,0,0,0,0,0,0,0,0,0,0,0,0,12,16134,19883,39943,10281,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44711,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-14125,2407,0,0,0,0,0,0,0,0,0,0,26921,0,0,0,0,0,22188,0,20810,10053,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28170,0,15208,0,0
-,32517,5736,19271,3562,10534,0,0,0,59655,0,0,0,0,27084,60422,0,0,24969,0,0,0,
-2636,0,0,0,0,26277,0,0,0,0,0,0,0,0,0,0,0,30596,3594,0,0,0,8362,14565,0,0,0,0,0,0
-,10793,12326,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5906,59686,0,0,23081,517,0,15556,0,0,0,
-8486,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19877
-,0,0,0,0,0,0,0,0,7497,0,0,26085,0,0,23784,63591,6568,6310,0,0,0,0,0,0,0,0,0,
-10054,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7018,14470,18858,0,5641,10660,0,0,0,0,0,0,0,
-35526,1515,0,0,0,0,0,0,0,0,0,0,0,27656,0,0,9606,0,39590,0,0,0,0,0,0,0,0,0,0,0,
-53926,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232,4327,12649,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,20199,0,0,0,0,0,0,26730,0,0,0,19400,14695,0,31334,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19589,0,0,0,0,0,0,0,0,5064,11908,0,27333,0,
-0,0,0,0,0,0,47751,0,0,0,26662,0,0,0,0,0,0,0,55655,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,6245,0,0,0,0,0,0,0,0,23368,63911,0,0,0,0,0,0,0,0,1974,0,0,0,0,0,0,0,
-8520,24037,0,0,0,0,0,0,0,26279,0,0,0,22886,0,0,0,27782,0,30694,0,0,0,0,0,0,0,0,0
-,0,0,33703,0,0,0,30405,0,34598,0,51047,0,0,0,0,1908,0,0,0,0,0,0,0,0,0,0,1511,
-21897,0,0,0,0,0,0,51398,0,24870,0,32647,0,0,0,35015,0,0,0,0,0,0,0,11204,0,0,0,0,
-0,0,7758,57991,0,0,0,30949,0,0,22,15140,9162,0,0,0,0,0,0,25540,20136,7108,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16427,10789,9805,0,0,0,0,0,0,0,0,0,4680,0,0,52679,
-0,0,0,0,0,14884,0,0,0,16804,0,0,0,0,0,0,9578,5287,0,0,0,0,0,0,0,34054,0,0,0,0,0,
-19076,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7627,55719,0,39463,14446,58374,0,0,0,0,23465,
-15845,0,0,0,0,0,38534,0,0,0,17893,10922,0,7176,678,0,0,0,0,0,0,0,0,3113,46279,0,
-0,0,0,0,0,0,23334,0,0,18088,23268,0,62342,0,0,0,16613,0,0,0,0,0,0,0,0,0,38182,0,
-0,0,0,0,0,25292,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10344,71,6446,0,0,1893,0,0,
-1106,0,28680,30756,0,41126,0,0,1492,0,15341,0,0,0,0,17575,0,21220,0,0,0,0,0,
-25060,2088,21828,0,0,0,0,0,358,0,0,0,0,0,16708,0,0,0,1668,0,0,0,0,0,12260,0,0,0,
-0,0,0,0,0,4078,0,0,0,0,0,12713,6215,0,0,20329,0,0,0,0,0,0,0,0,0,0,31204,0,0,0,0,
-0,0,0,0,0,0,3732,0,1646,0,0,27460,0,34406,17128,14341,0,0,0,0,0,19527,0,0,0,0,0,
-0,0,0,0,0,6120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8551,21546,10212,3020,
-2951,0,17638,0,0,6985,44999,2218,8197,0,0,30472,63366,0,26660,0,0,0,0,0,0,0,0,0,
-0,0,0,1265,0,0,0,0,0,0,0,2610,0,0,0,11278,20295,0,0,0,0,0,19780,0,0,0,0,0,0,2353
-,10852,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5421,24292,0,0,0,0,0,0,0,0,0,0,0,0,0,34407,0,
-0,0,0,0,0,15432,20774,0,0,0,0,0,0,0,0,12360,10757,0,0,0,33126,0,0,0,0,0,0,0,0,0,
-0,0,29573,0,2343,0,0,0,0,0,63079,0,0,0,0,0,0,0,0,0,43015,0,16038,0,0,0,0,0,0,0,0
-,1480,25573,0,0,0,0,0,0,0,8839,0,0,0,0,0,0,0,24645,0,0,0,0,0,0,0,0,0,0,0,0,0,
-5063,0,0,0,0,0,45830,0,0,0,0,0,0,0,0,0,0,823,0,0,64039,0,0,0,0,0,0,0,0,0,0,0,0,0
-,15300,0,0,0,0,0,0,2924,46759,6760,19268,0,0,0,0,0,0,0,0,0,34182,0,0,3977,18149,
-0,0,0,32199,0,0,0,0,0,0,0,0,0,23524,25994,0,0,10343,0,0,0,9733,0,0,0,0,0,0,0,0,0
-,4740,0,0,0,0,0,0,0,0,0,16741,0,0,4626,23367,0,0,31400,0,0,3557,0,0,4234,0,0,0,0
-,0,0,28486,0,0,0,0,0,14213,0,57191,0,0,0,0,0,0,0,0,0,0,240,0,0,0,0,65318,29832,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29989,0,31846,0,0,8170,0,0,4421,27626,30884,0
-,0,20204,0,0,0,0,44614,534,20868,0,0,0,0,0,0,0,0,0,0,0,0,0,28710,0,10277,0,0,0,0
-,0,29511,0,19813,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27020,0,0,0,0,0,0,53094
-,0,35207,0,0,0,37542,0,61766,8584,8037,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12488
-,22757,0,0,0,0,0,0,0,0,0,0,0,0,0,23814,0,0,0,0,0,0,0,0,0,19973,0,0,0,63943,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36006,0,0,0,19012,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,8580,0,0,0,0,0,0,0,18021,0,0,0,0,0,0,0,0,80,1254,0,0,0,42630,0,0,0,0,0,
-0,0,16262,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2124,25479,0,0,0,0,16873,0,0,0,0,3142,
-0,0,18443,0,0,0,0,0,3917,0,8841,1190,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,20645,0,0,0,0,0,0,0,0,0,0,0,9284,0,0,24394,41351,0,0,0,42087,0,62566,0,0,0,0,
-0,0,0,0,0,0,6728,4199,0,0,0,0,25515,0,1231,0,374,15623,0,29956,0,14118,0,0,0,0,0
-,19047,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31718,0,0,0,0,0,0,0,0,0,0,0,20900,0,16743,0
-,0,0,28902,0,0,0,0,0,0,0,0,0,0,0,0,2578,0,0,0,0,0,0,0,0,0,13838,0,0,10052,0,0,0,
-0,7432,43783,17097,0,0,0,0,0,873,0,0,0,398,0,0,0,0,0,0,0,0,0,8459,23559,0,53030,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35750,0,4071,0,0,0,38662,0,41414,0,0,0,0,11656,0,0
-,0,0,0,4011,42695,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25353,0,0,0,0,0,0,0,27177,22372,0,
-0,0,0,0,30980,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,46278,3976,12711
-,0,0,0,0,0,0,0,0,0,0,0,20517,0,0,0,0,0,0,0,0,0,0,0,0,4072,11078,0,0,16553,2405,0
-,0,0,0,0,0,0,0,2670,0,0,0,0,0,0,32998,0,0,0,0,0,0,0,47046,0,30533,0,0,11050,9734
-,13129,0,0,0,0,23494,0,0,0,0,0,58310,0,0,0,57543,0,0,0,0,0,0,0,0,0,0,0,0,0,454,0
-,0,0,0,0,0,5163,59687,2220,0,0,0,0,0,0,29510,0,0,0,0,0,0,0,0,0,0,0,17316,0,20069
-,0,0,0,0,0,0,0,0,0,5319,0,0,0,0,0,0,0,0,0,27174,0,0,0,0,0,0,0,22949,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,19208,0,0,0,0,0,0,20933,0,0,6026,8742,0,0,0,17380,0,13127,2797,0
-,0,30116,0,0,5963,8004,0,57126,0,0,0,0,0,42854,14792,30759,0,24964,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,16933,0,0,0,0,0,0,15176,40839,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-788,30341,0,0,0,0,21036,24102,0,0,0,0,30123,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-22597,31531,26789,0,59559,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9352,29863,0,0,0,0,0,0,0,0
-,0,24551,0,0,0,0,0,0,0,20516,0,0,0,39462,3665,0,28265,0,8778,64262,0,57414,9132,
-0,0,18276,0,0,0,0,0,0,0,0,0,0,26344,30725,524,19751,0,13796,0,0,0,0,0,0,0,0,0,0,
-18155,0,12841,0,74,24998,13579,1061,0,64199,0,0,8776,0,0,60231,0,25412,0,0,0,
-59143,0,0,0,0,0,0,14344,1510,0,0,0,38374,0,0,0,0,0,0,0,0,13353,0,0,0,0,0,0,0,0,0
-,0,9446,0,0,0,0,0,0,0,32613,0,0,0,0,0,0,0,0,0,0,0,0,0,19844,0,0,0,0,14859,0,0,0,
-0,6662,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14154,0,29770,0,0,0,0,0,
-16520,2182,0,0,0,0,0,36102,3340,0,0,0,0,0,0,0,0,25189,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,15720,0,0,0,0,0,0,22758,0,0,304,0,3243,14117,0,0,0,0,0,0,0,0,0,0,5130,
-12679,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21733,10441,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,36103,0,0,0,0,0,23590,0,57479,0,0,0,0,0,0,0,0,0,0,0,0,10824,
-18372,0,0,0,0,0,35078,15722,12967,0,0,0,0,0,34599,0,0,0,0,0,0,0,0,0,0,0,0,0,
-53639,0,38630,0,0,0,0,0,0,31017,11333,0,0,0,0,19144,0,9513,0,0,0,0,0,0,0,0,56711
-,24042,0,1197,0,0,58502,0,0,0,0,0,0,0,0,0,8230,6121,18628,0,0,0,0,0,0,25290,0,0,
-0,0,0,1514,0,0,0,0,0,0,0,14378,9798,32363,0,0,0,0,0,9577,0,0,0,0,0,0,26788,0,0,0
-,0,0,0,330,10533,0,0,0,0,0,42246,0,0,0,0,0,0,5074,21028,0,38119,0,0,0,0,0,0,248,
-0,31176,62054,0,53287,0,0,0,0,271,0,0,0,0,0,0,0,0,0,0,0,0,0,9224,2117,0,0,0,0,
-15818,5607,0,52582,0,0,0,0,0,0,0,0,18248,24005,23018,0,0,0,0,0,0,0,0,0,0,0,0,0,
-427,0,0,39910,0,0,7080,11399,0,0,0,0,0,0,0,0,0,0,22220,57894,0,0,0,0,0,0,0,13156
-,0,1413,1007,0,0,0,0,21415,0,21543,0,0,0,0,0,0,0,0,0,41702,22538,9573,0,0,0,8806
-,0,0,6920,56359,0,0,0,0,0,0,0,0,0,0,0,42215,0,0,13708,0,0,0,0,0,0,0,0,0,0,16453,
-0,0,0,0,0,0,1582,1764,3282,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11653,0,0,0,0,12139,0,
-29482,31076,1673,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40262,0,0,0,33862,0
-,0,0,0,0,20996,0,0,0,0,0,4615,0,0,0,0,0,0,0,0,0,0,0,43943,333,19367,0,0,0,0,0,0,
-0,26821,0,32389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4936,11687,0,0,0,0,0,0,0,0,0,10885,0
-,0,0,0,0,25926,0,0,0,0,0,0,15851,0,0,0,0,0,0,0,0,0,8360,0,17130,7942,0,11460,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,18150,14248,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-22310,0,0,0,42758,0,0,0,0,0,0,0,0,29354,5574,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,31109,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11236,0,0,0,0,0,0,0,0
-,0,0,0,0,0,9156,0,0,1801,14023,0,0,0,0,0,62406,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-23620,0,0,0,0,0,0,0,0,0,0,31018,65510,0,0,0,0,0,0,0,26182,0,0,0,0,0,0,0,27717,0,
-0,0,0,0,0,0,46950,0,0,0,0,0,0,0,0,0,0,0,0,0,31108,0,11366,0,0,0,3717,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8552,6054,3339,0,0,0,0,51622,0,
-0,0,0,0,0,0,3718,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28358,0,2756,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,1462,0,0,27622,0,0,0,0,0,0,0,62502,14410,56743,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,12206,0,0,0,0,0,0,0,0,0,0,0,0,36550,0,38054,0,0,0,
-21221,0,0,0,0,0,0,0,27077,0,0,16906,0,12587,12101,0,0,0,0,0,0,10414,28775,21769,
-60167,0,56646,0,0,0,0,0,20740,0,0,0,0,0,0,5931,5351,0,65478,0,0,0,0,0,0,7977,
-52647,0,4868,0,0,0,55463,0,0,0,0,0,32197,0,0,0,0,0,13445,0,0,0,26631,0,0,0,0,0,
-11237,0,0,0,0,209,1285,0,0,1928,0,0,0,0,43334,23849,23172,0,0,0,0,0,0,0,0,24712,
-62439,8811,3463,20457,0,0,0,0,0,0,0,0,0,16008,56263,0,0,0,0,0,0,0,0,0,0,0,60358,
-22761,6565,0,0,30888,27686,0,0,0,17093,0,0,0,0,22121,0,0,0,7593,14182,0,28103,0,
-0,0,0,0,45126,0,0,0,0,0,0,0,0,0,0,0,0,0,31844,0,0,0,0,0,0,0,0,0,0,0,0,0,18500,0,
-0,0,0,28202,0,0,0,0,0,0,0,0,26308,0,29541,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-29572,0,0,0,21285,0,0,0,0,0,60839,0,0,0,0,0,30407,15949,2981,0,0,0,46439,0,0,0,0
-,0,23911,26505,25222,12811,5895,0,6343,0,0,0,0,0,0,0,0,0,0,0,31815,0,0,0,0,0,0,0
-,0,19688,10245,0,0,0,31301,26985,28964,0,0,0,0,0,0,0,0,27208,31172,0,0,0,0,216,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16292,0,0,0,0,0,8743,0,0,0,0,0,0,0,0,
-0,0,0,0,0,6438,0,0,0,33319,0,0,0,33286,0,0,0,0,0,0,0,0,0,22181,7499,24774,0,
-10756,0,44775,724,0,25768,25669,24873,5349,25257,0,0,54566,0,0,0,0,0,0,0,0,0,0,0
-,327,439,357,0,0,6536,8452,0,0,1802,0,0,61350,0,15045,0,0,0,0,0,0,0,0,0,0,0,
-38343,0,0,0,0,0,0,0,0,0,0,32491,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-22885,0,0,32073,0,0,0,9546,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27748,0,0,23176,0,0,0
-,0,0,0,0,0,0,0,0,0,24583,0,0,0,0,0,34118,0,0,0,0,2158,0,5586,30340,0,0,0,0,0,0,0
-,0,0,0,0,0,0,24452,0,0,0,0,2409,4390,0,24196,0,0,0,0,0,0,32264,26948,20587,0,0,0
-,2155,0,0,0,0,0,0,0,0,0,0,0,4328,26276,0,0,0,0,0,0,0,0,23564,0,12458,11367,0,0,
-25162,0,0,0,0,0,0,65414,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32966,0,0,0,
-34662,0,0,0,0,0,39238,0,0,0,0,11400,10214,266,12452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,15173,0,0,0,13668,0,13222,0,23364,0,0,0,0,0,11941,0,0,0,0,0,0,0,0,0,
-25575,0,0,0,57383,0,0,0,10308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,2865,9287,75,0,0,0,0,0,0,0,0,0,0,21508,22380,59526,0,0,0,23589,0,0,0,51590
-,0,0,0,0,0,0,0,0,0,0,0,4645,3980,28295,0,0,0,0,0,12388,0,0,0,0,0,0,0,0,0,0,0,
-21734,0,17607,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41767,0,0,0,0,0,0,0,18436,0,0,0,0,0,
-0,0,21958,0,19430,0,0,1204,0,0,0,0,0,0,0,0,0,3240,55239,0,0,0,0,0,30660,0,0,0,
-28901,0,0,0,0,4716,0,0,0,0,0,0,0,0,0,0,0,11754,0,0,0,0,22086,0,22564,8749,0,0,
-28391,0,0,0,0,0,0,0,0,0,0,0,2886,0,0,0,0,0,0,0,29062,0,0,0,0,0,0,0,40358,0,0,
-15916,39526,0,13735,0,0,0,0,28938,0,407,4006,0,0,0,26916,0,0,0,0,0,27526,30280,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24586,0,24649,5126,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8684,0,0,0,0,0,0,0,23019,0,22377,18599,0
-,0,0,0,0,0,0,0,0,0,27593,9735,0,20196,0,0,0,0,28168,48423,0,0,0,0,0,31399,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,13892,0,0,0,0,0,17606,0,0,15242,29767,26378,17701,0,0,
-14472,0,4840,0,0,0,0,0,0,24708,0,9349,4330,0,0,0,0,0,0,0,16137,0,0,34854,0,0,0,0
-,0,0,0,0,0,0,0,25063,0,0,0,0,0,0,6603,12583,0,0,0,0,0,0,0,0,7433,29188,0,0,0,0,0
-,31270,0,0,22920,3143,0,0,0,0,0,23461,0,0,0,0,0,0,0,0,618,0,0,0,0,21381,0,11524,
-0,0,0,0,0,0,21004,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,312,23239,0,0,0,0,0,0,0,0,0,0,0,
-0,2313,0,0,40614,0,0,14825,0,0,0,0,0,0,46535,0,41190,7853,0,31656,0,0,0,0,0,0,0,
-0,0,3433,5255,0,0,0,0,0,0,0,33958,0,0,0,0,72,15493,0,0,0,0,0,0,0,36070,0,0,0,0,0
-,0,0,14724,0,0,0,0,0,29828,0,0,0,0,0,0,0,18822,20008,0,0,0,0,2438,2952,0,0,0,0,0
-,0,0,0,0,0,0,0,0,3342,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24420,0,19908,0,0,0,8101,0,
-17479,0,0,3530,0,8202,29319,0,0,1132,6789,0,0,23881,0,0,0,4810,0,0,46918,0,0,0,
-41574,0,0,0,0,0,0,0,0,0,48582,0,0,0,0,0,0,0,0,0,0,0,0,0,39334,0,0,0,26117,0,0,0,
-0,0,0,5100,0,0,0,0,0,23496,27813,4045,54918,0,0,0,0,0,0,6473,7428,0,0,0,0,6792,0
-,0,0,0,0,3560,32103,0,0,0,0,0,0,0,0,0,0,0,54790,0,0,6926,0,0,0,0,16518,0,0,0,0,0
-,20806,0,0,0,0,1841,3174,0,0,0,0,9612,18374,0,0,0,0,32744,0,0,9671,0,59879,0,
-23300,8073,0,0,14758,0,0,0,10342,0,0,0,0,0,0,24808,14759,0,0,0,0,0,0,5515,0,0,
-14852,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2354,23271,0,32740,0,0,0,0,0,0,0,0
-,0,0,18472,0,0,0,0,0,0,0,0,33190,0,0,0,0,0,0,0,0,8972,21669,0,0,0,0,0,0,0,0,0,0,
-0,25574,0,0,0,0,5096,0,14283,55367,0,0,0,0,0,0,0,0,0,12644,0,0,0,0,4651,0,0,0,0,
-0,0,0,661,0,0,13638,19466,0,0,0,0,0,31273,0,8010,0,0,0,0,0,3211,0,0,0,0,63430,0,
-0,0,0,0,15237,0,0,0,0,0,0,19018,2437,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14312,0
-,0,0,0,16836,0,0,471,35975,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,6023,0,0,0,0,0,0,0,0,11593,9639,0,0,0,55783,0,5700,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27908,0,26598,0,0,6667,6470,0,0,0,0,0,0,0,
-62534,0,0,0,0,16522,27911,0,0,10025,7172,0,0,779,0,360,17477,0,0,0,61991,7752,
-7717,1494,0,0,0,26569,40742,0,0,0,0,0,0,0,26406,10474,32196,0,0,0,0,0,50567,
-16521,11716,0,0,0,0,0,55558,0,0,0,0,0,0,0,0,0,0,0,61926,0,26436,0,0,0,0,4459,
-10598,0,0,0,0,0,0,0,0,0,0,0,9223,0,29318,0,0,0,0,0,60423,0,0,0,0,0,0,0,47078,0,
-50246,0,12612,0,0,0,0,0,0,0,61799,0,55015,0,21060,7309,0,0,0,0,0,11976,0,0,0,0,
-23527,0,0,0,0,0,0,10347,15942,0,34023,0,0,0,0,4969,0,0,0,0,0,0,0,0,28997,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36454,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-3466,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19716,
-28872,0,0,0,0,0,22152,0,0,0,0,0,0,26342,0,0,0,9764,0,0,0,0,0,0,0,21798,0,0,0,0,
-13,6853,32136,0,0,0,0,0,0,0,750,0,0,54502,0,0,0,0,0,0,0,0,0,46183,0,0,625,22854,
-0,0,0,0,2061,23588,0,0,11049,56262,0,0,18538,1509,0,0,17258,4453,0,0,0,0,12429,0
-,0,0,0,8102,0,0,0,0,0,0,8074,0,23852,0,0,0,0,0,0,0,0,0,0,0,16136,3428,0,27876,0,
-0,0,7332,0,0,0,0,0,28900,0,0,2284,0,0,17573,201,1508,0,0,0,0,0,0,0,0,0,31365,
-27688,22565,0,0,0,5159,0,0,0,0,4584,42599,0,0,0,44422,1068,23173,0,0,0,613,0,0,0
-,12645,0,0,0,0,0,27076,6732,0,0,0,3913,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,22244,29992,15911,0,0,0,0,0,22982,0,0,0,0,0,0,0,50598,0,0
-,0,0,0,0,5161,1574,0,0,0,0,0,0,0,0,0,19108,0,0,0,35014,0,0,0,25956,29067,0,0,0,0
-,0,0,0,0,0,0,47079,0,0,0,0,0,0,0,0,0,0,1356,61927,0,0,0,64455,2122,64231,0,0,
-18763,0,0,0,0,0,0,0,0,0,907,34471,0,0,0,39078,0,0,1995,0,0,0,0,0,0,0,0,0,0,56518
-,0,0,0,0,0,0,0,0,0,0,0,0,822,0,15978,44423,0,0,3112,325,0,0,0,0,0,15397,0,0,0,0,
-0,0,0,0,0,0,1193,4294,4968,15559,0,46150,0,0,0,0,0,18917,0,0,0,0,0,0,9928,37543,
-0,0,0,0,13097,36999,0,0,0,15430,0,0,8424,29639,0,0,0,0,0,0,0,0,0,0,0,0,0,25734,0
-,0,0,0,0,0,0,0,0,0,0,0,0,40487,0,13284,0,11141,0,0,0,32388,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5298,57702,0,0,0,0,0,0,0,13060,0,0,0,0,0,0,
-8233,42278,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36422,0,0,0,7972,0,0,0,
-18437,0,0,0,0,7406,0,0,0,9225,0,0,0,0,0,0,0,0,0,13865,47591,18220,53703,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2796,0,0,0,0,0,24940,17223,0,0,0
-,13221,0,0,0,0,0,0,0,0,0,0,15848,0,0,0,0,0,6122,1735,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,16968,18151,0,0,0,0,0,47494,0,0,0,0,0,0,26089,19494,0,0,0,0,0,15494,0,0
-,0,0,0,0,0,0,0,0,28809,0,0,0,0,42727,0,55174,0,0,0,0,0,0,0,0,0,0,0,20485,0,0,0,0
-,0,0,0,0,0,0,0,58598,0,0,0,0,0,0,0,0,0,0,0,0,0,15172,0,0,0,0,0,0,0,0,0,35302,0,
-48135,20972,33094,0,0,0,0,0,9765,0,0,0,0,0,0,0,0,0,39559,0,0,13736,6950,0,0,0,0,
-23658,8903,0,0,0,0,0,0,0,22662,0,0,0,0,0,58886,7468,0,0,0,0,0,0,0,0,64550,0,0,0,
-0,0,47622,0,0,0,50886,0,0,0,0,0,57606,912,0,0,0,0,0,0,0,0,0,1449,0,1169,0,718,
-46151,12104,0,0,0,0,0,0,48230,0,0,0,0,0,0,0,0,0,0,1259,0,0,33734,23208,62567,0,
-65158,0,0,0,0,0,0,0,0,0,0,28684,59878,0,0,0,0,0,0,0,0,0,0,25769,0,0,0,0,65479,0,
-0,0,0,555,22789,0,19748,1769,10246,8680,0,0,0,0,0,0,0,0,0,14250,0,5899,3303,0,0,
-0,0,0,0,0,0,21097,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21638,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,10795,0,0,0,16204,0,0,0,0,0,26986,2469,0,14660,0,0,0,0,0,45447,
-12234,3494,4555,10566,0,0,0,0,0,0,0,0,0,0,0,0,2801,0,0,0,15755,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,39654,0,0,0,0,0,0,6763,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-33574,0,10279,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63527,0,0,3912,0,0,7492,0,0,0,35142,
-0,0,0,0,0,0,17576,8103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16713,4198,0,0,4782,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,16228,0,0,0,0,25961,20166,0,0,0,10980,0,0,0,0,0,14340,
-18922,14567,0,44199,0,0,0,0,0,0,0,18406,0,0,0,0,0,37606,0,0,0,0,0,0,0,0,0,20902,
-0,0,0,56358,0,38342,0,0,0,0,9514,36071,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21700,0,0,
-5266,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1134,0,1453,0,0,0,0,0,3882,0,0,0,
-0,0,0,0,0,4004,0,0,0,51910,0,0,0,0,0,23076,4648,0,0,0,31051,25351,0,0,0,22884,0,
-0,0,0,0,63975,0,0,2376,16997,0,0,2096,0,0,0,3373,7046,0,0,0,0,0,0,0,30726,0,0,0,
-0,20,0,13707,614,0,0,12840,3079,0,0,0,0,0,51046,3729,0,32680,0,0,0,0,0,24008,
-62759,0,0,4745,0,0,0,0,0,0,0,0,0,0,0,0,0,2414,0,0,44262,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,24937,0,0,0,0,0,0,0,0,19140,0,13575,0,0,0,0,0,0,0,39110,0,0,0,28036,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,4261,0,0,0,0,5992,0,264,0,0,0,0,0,0,0,13739,0,21928,0,
-0,0,0,0,0,0,0,0,0,0,4232,15110,0,0,0,0,0,0,0,0,0,30022,0,0,27977,0,0,0,0,0,24776
-,0,0,0,0,0,2962,0,0,0,0,0,0,26564,22441,0,0,0,0,0,13640,11205,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,19305,1894,0,0,0,0,0,0,0,0,0,0,9389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14119,
-5224,135,0,0,0,0,0,0,0,0,0,25796,0,0,0,0,0,0,7470,0,0,0,0,63815,0,55654,0,0,
-12584,0,1524,33223,0,0,0,9895,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11624,
-0,0,0,5614,0,0,0,0,0,0,0,21320,0,0,53607,0,51206,0,0,0,25863,0,0,0,0,0,0,0,0,0,0
-,0,8964,1740,0,0,0,0,0,0,0,0,13476,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7975,0,
-0,3306,8134,0,8389,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25766,0,0,0,0,0,0,0,0,0,
-52166,0,0,0,0,0,0,0,0,0,0,0,0,0,21477,31112,31652,0,0,0,0,0,0,0,28452,0,0,0,
-44231,0,0,0,0,0,0,0,24805,0,0,0,0,0,0,0,0,0,0,12428,6471,0,0,0,0,525,17926,0,0,0
-,26919,0,0,18120,0,0,0,30024,0,0,0,0,0,0,0,0,0,0,29189,0,0,0,43559,0,0,0,0,0,0,
-19787,7557,0,59334,0,0,10184,6085,0,44039,0,0,0,0,0,0,0,11175,0,0,0,0,30440,
-63110,0,0,0,0,0,0,11017,0,0,0,0,0,0,0,0,27204,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,29126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,622,0,5226,2727,0,15588,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4650,0,2675,0,0,32420,0,0,0,61511,0,0,
-5419,17829,2123,0,0,0,0,0,0,0,0,0,0,0,0,0,0,38183,2640,0,11274,14533,1842,0,0,
-42663,12681,3430,0,11845,0,0,0,0,0,0,0,0,0,6533,0,0,0,0,0,54598,0,0,0,0,0,0,0,0,
-0,0,0,0,12616,38535,0,0,0,0,0,32229,0,0,0,54279,0,48614,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,31401,0,0,0,0,34310,0,0,0,22788,0,52134,0,0,0,0,0,0,0,23302,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,40678,0,0,0,51463,535,0,0,0,0,15525,0,0,0,0,0,0,4904,869,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63718,0,0,0,0,0,0,0,0,1678,0,692,0,0,0,
-0,0,0,0,0,0,26216,0,0,0,0,0,29355,0,0,0,0,25095,0,0,0,0,4335,0,0,0,0,0,14538,0,0
-,0,0,0,0,0,0,0,27273,55014,0,0,0,0,0,27271,0,0,0,0,0,30468,0,0,0,0,18186,0,0,0,0
-,0,14345,0,0,0,2152,0,0,0,0,0,0,0,0,0,0,0,0,0,0,58438,21034,0,23339,21318,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,21412,0,0,0,0,0,0,0,12869,0,0,4875,0,0,0,0,29191,0,0,0,0
-,0,0,1640,10247,0,14244,0,0,0,0,9867,0,0,0,0,0,12363,0,0,7653,0,0,4168,2663,0,
-4580,0,11143,0,0,0,0,0,0,0,30662,0,0,0,0,0,6724,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,13764,0,0,0,0,0,0,0,0,0,0,0,0,234,6821,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,25639,0,0,0,0,0,0,0,0,0,29958,0,3461,0,0,0,0,0,0,0,0,0,28324,
-18795,7013,12746,11655,0,37287,0,0,10953,7718,9705,0,0,0,0,0,0,0,0,0,0,46534,0,0
-,0,0,0,0,0,0,0,0,8137,17988,0,25156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41415,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15784,6918,0,0,0,0,7019,10919,0,0,0,
-0,0,0,0,0,0,0,4171,55495,4940,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22440,19333,0,0,
-28136,0,6249,21317,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,53414,0,0,0,57318,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39303,0,0,0,0,0,19940,0,0,0,0,0,0,0,25543,0,0,0
-,0,0,0,0,0,0,0,0,0,2698,3911,0,0,0,26790,0,0,0,0,0,0,32424,0,0,18470,0,0,0,14726
-,29834,0,0,0,0,0,0,0,0,0,0,0,1000,4197,0,0,0,19366,0,0,0,39878,0,0,0,0,2185,8901
-,5288,9829,25000,0,0,0,0,0,0,1062,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35622,0,
-0,23048,62503,6506,0,0,0,0,0,0,0,13609,10438,0,0,0,0,0,0,0,0,0,0,7723,42119,0,0,
-0,0,0,13317,0,0,0,41606,0,27111,0,0,21194,11461,0,0,0,0,26856,58342,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,20940,48710,0,0,0,0,0,0,5227,0,0,0,0,0,10061,31300,0,0,0,19236,0
-,0,0,0,0,30277,13896,0,0,0,12876,13159,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,428,
-46951,13134,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15462,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,21668,0,0,0,0,0,0,0,0,0,0,0,0,2249,0,0,0,0,44967,0,0,0,0
-,0,0,3465,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24868,0,0,0,0,0,23909,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,2190,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16164,0,
-10437,0,0,5263,20102,20938,0,0,0,1192,1030,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,21385,4870,0,0,0,0,0,0,0,0,0,0,0,18596,0,0,0,0,1422,4038,2858,0,0,0,0,0,0,0,0
-,48998,0,0,0,0,0,0,0,0,6508,37350,0,0,0,0,0,0,0,0,17001,39431,0,0,0,0,0,30182,0,
-21445,7403,28164,0,51750,0,0,0,62631,0,0,0,0,0,0,0,31206,0,0,0,0,0,0,0,0,0,0,0,
-7751,0,0,0,0,0,0,0,0,0,13477,0,0,456,26693,0,0,0,0,0,0,0,0,0,0,0,0,14890,0,0,0,0
-,0,26697,22022,13225,27364,0,0,0,18884,0,0,0,0,0,0,0,0,3659,0,0,0,0,0,0,0,0,0,0,
-0,1448,5413,0,0,0,0,0,0,0,0,0,0,0,6340,0,0,18091,18725,0,0,0,0,0,0,0,0,0,0,0,0,0
-,22118,0,0,0,18981,0,0,0,0,0,0,0,0,0,29223,3724,0,0,0,0,43526,0,0,0,25668,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21545,9862,0,22692,32201,60646,0,7300,0,0,
-0,58887,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19460,0,0,0,0,0,0,0,0,0,50342,0,
-65255,4360,17286,0,0,0,0,0,0,0,28708,0,0,30025,60102,0,0,0,0,0,0,0,0,0,47014,0,
-31973,0,9572,0,0,0,0,0,0,0,18501,0,0,0,0,0,14597,0,0,0,53735,5228,22183,0,0,0,0,
-0,0,1554,24164,0,0,0,0,0,0,0,0,0,0,0,0,10827,0,0,0,0,34918,0,0,0,0,22252,0,0,
-46855,0,0,0,0,0,31207,0,0,10733,0,0,63334,0,0,0,0,8616,50119,20169,12678,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,58087,20298,5,0,0,30920,0,0,0,0,0,0,0,296,13190,0
-,30663,0,0,18536,12228,0,6788,0,0,0,0,30890,21796,0,0,526,0,0,0,0,0,0,0,0,0,0,0,
-0,20965,0,0,0,0,2161,0,0,0,0,0,0,24038,0,0,0,0,13544,7398,0,0,32522,9605,0,0,0,0
-,3208,7590,0,0,0,43846,0,0,0,38663,0,0,0,0,0,39014,4142,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,6373,0,0,13676,0,0,0,0,30374,21288,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22791,0,0,0,0,0,37958,0,0,0,0,0,0,0,0,0,0,9452,
-9990,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4841,0,0,0,0,18820,152,0,0,0,0,0,13260,3334,0,0
-,24234,8422,0,17957,0,0,0,10244,0,0,0,0,0,0,0,0,0,0,0,7204,0,0,0,0,1201,26151,0,
-31173,0,0,0,0,0,0,0,0,0,0,0,0,0,64838,4203,7525,521,0,18888,37031,0,0,0,0,0,0,0,
-0,7082,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4490,12487,0,0,0,0,0,0,0,36615,0,0,
-0,14854,0,0,0,0,0,0,0,0,0,0,0,0,6539,13029,9704,38983,0,0,0,0,168,10405,0,0,0,0,
-394,25607,0,57063,0,0,0,0,0,0,0,0,0,0,16141,19878,0,0,0,0,0,0,0,0,0,29446,0,
-12036,0,0,0,0,0,6982,18572,0,24584,14535,0,0,0,0,0,0,0,0,0,0,16,0,21642,0,0,0,0,
-0,0,5254,0,0,0,0,0,0,0,0,1622,0,0,0,0,0,0,0,0,0,0,0,0,0,3853,9126,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,7241,10982,0,0,0,0,0,0,0,0,0,0,0,0,0,0,950,0,0,57990,0,0,277,0
-,0,0,694,36007,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42470,0,0,0,0,18409,
-51142,0,0,0,0,0,0,0,0,0,28646,0,0,0,30693,0,0,0,0,0,56295,5544,0,0,0,0,8518,8366
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45670,0,0,
-9608,33062,0,0,0,0,0,0,0,0,0,0,0,18694,0,0,0,0,1672,23493,0,0,6955,7655,0,36134,
-0,0,0,0,0,0,0,0,23432,647,0,0,0,0,0,0,0,0,0,0,0,13382,0,0,0,19621,0,0,0,0,0,0,0,
-0,0,20228,0,0,2728,31495,0,0,0,0,29096,22213,235,35495,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,5348,0,0,0,0,8968,1989,0,0,1066,0,0,11492,5965,31367,0,0,0,0,0,0,0,0,0,0,0,
-18727,0,0,0,6757,0,0,10765,4646,0,36166,0,27943,0,0,26888,8420,0,0,0,0,0,0,0,0,0
-,29316,0,0,0,0,0,0,0,0,0,0,4975,0,0,0,14762,3111,0,0,0,0,0,43399,0,0,0,0,0,0,0,
-18980,0,0,0,0,0,44550,0,0,0,0,4051,0,0,0,0,37734,0,0,0,0,0,5188,0,0,0,0,0,24486,
-0,5989,0,41159,0,0,0,0,0,0,0,0,0,20326,0,0,747,6884,0,0,0,41798,0,0,3117,22919,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21032,0,0,0,0,0,0,0,0,9574,0,0,0,0,0,0,
-4302,0,0,0,0,0,0,0,0,0,0,0,21068,34630,0,0,0,0,0,64071,0,0,0,0,0,0,26667,7943,0,
-0,0,0,0,52934,0,0,17002,0,0,0,0,0,0,20294,0,0,0,0,0,0,0,0,0,27301,18347,7974,0,0
-,0,0,0,0,0,0,16874,0,0,0,0,45414,0,0,0,0,0,0,648,1575,0,0,0,31749,0,0,0,23301,0,
-0,0,0,0,0,0,0,0,0,0,0,15912,50535,0,0,0,0,1993,8582,0,0,0,0,0,0,0,38438,0,0,0,0,
-0,0,0,0,0,0,0,0,15850,6183,0,0,0,0,3402,0,0,27494,0,0,749,0,0,0,0,0,0,0,26025,
-29606,0,0,7144,19622,30504,0,0,0,0,0,0,0,0,21316,0,0,0,0,0,0,0,0,0,21444,0,0,
-1289,6919,0,0,0,0,0,0,8299,0,0,0,14090,35655,0,0,0,0,0,0,0,0,2377,15206,0,0,6028
-,4452,0,25508,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50310,0,0,0,0,1269,0,0,0,0,0,0,0,0,0
-,0,0,0,51014,0,0,0,0,0,0,0,9286,0,7429,0,0,28393,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,16680,452,0,0,0,0,0,23718,0,0,0,31750,0,0,0,0,0,0,0,0,3568,0,0,13604,0,0,
-0,0,0,25255,0,0,0,50982,0,56582,0,0,7467,0,0,0,0,30181,0,0,0,0,0,0,0,30564,7208,
-7845,0,0,0,0,0,0,7726,0,0,0,0,62182,0,0,0,41094,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,22695,0,0,0,0,0,0,17736,0,0,0,0,0,0,0,0,50054,0,0,0,14180,0,0,0,0,
-0,0,8974,0,0,0,0,0,0,0,0,23332,0,0,0,11140,0,0,0,0,0,0,0,24262,27145,9540,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,26537,45510,6062,3879,0,0,20233,25991,0,0,17803,0,0,0,0,0,
-13962,5508,16971,27013,7437,31494,0,0,0,0,0,0,0,0,0,0,4714,0,0,0,0,0,0,0,0,17189
-,0,0,0,0,0,27492,0,0,26953,0,0,0,0,0,0,0,0,0,0,41319,0,0,0,0,0,0,0,0,0,0,0,47430
-,19596,12549,0,0,0,8390,1006,0,0,0,0,0,0,0,0,0,0,24100,17577,4,0,0,0,0,0,22277,0
-,0,0,0,0,0,0,26692,0,0,0,0,0,24676,0,0,0,0,0,0,0,0,0,0,0,0,0,29477,0,0,0,21573,0
-,0,0,0,0,0,0,0,0,0,9864,14214,0,0,0,0,0,0,25771,5766,0,0,8909,8679,0,0,6861,
-16166,0,38887,0,0,0,0,0,0,12392,8678,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-52646,1354,2950,0,14692,0,0,10572,49830,0,0,0,0,0,0,0,0,3626,582,0,0,0,55750,0,0
-,0,30885,0,0,0,0,0,0,0,0,0,0,0,0,0,5830,0,0,2090,0,0,0,0,0,0,0,0,0,0,0,0,31142,0
-,0,0,0,0,10503,0,0,18825,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-57158,0,0,30792,63526,0,0,0,9863,16267,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,18824,0,0,0,0,0,0,19653,25388,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9292,0,0,0,0,0,0,0,0,0,0,36358,0,0,0,0,0,0,0,0,
-0,0,25480,23015,0,0,10440,6725,0,0,0,22436,24265,15109,0,0,0,62311,8906,34534,0,
-0,0,0,0,0,15913,1319,0,0,20296,1477,30760,0,25928,16772,0,0,1069,0,0,0,0,0,0,0,0
-,0,0,0,0,17029,0,31909,0,0,0,0,0,0,0,0,0,0,0,41638,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,41542,0,21478,0,0,0,9796,0,0,0,0,0,0,0,0,0,0,22187,58343,0,0,0,24295,0,
-0,0,0,0,61831,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2833,5829,0,0,0,62855,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,16676,0,0,0,0,0,0,13577,27431,0,0,0,0,21480,10501,0,16932,
-0,0,0,0,0,22918,0,48294,2574,2150,0,0,0,0,1897,4518,0,0,0,0,0,0,25064,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47942,0,0,0,0,10990,13767,
-25705,37863,21672,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43430,1712,0,0,0,0,
-18886,0,0,0,0,0,0,0,0,0,0,0,0,0,10535,0,0,0,0,0,0,0,15012,0,0,0,0,0,0,0,0,0,0,
-14734,0,0,55782,0,0,30824,10886,0,0,0,0,0,51302,0,0,8012,0,0,0,0,0,20680,6981,0,
-57415,11,0,0,18277,0,14564,0,0,0,32390,0,0,0,0,0,0,0,0,0,0,0,0,19113,5158,0,
-11172,0,16774,0,0,0,0,0,0,0,0,0,0,0,0,10315,13830,0,0,0,0,0,0,10410,7141,0,0,0,0
-,0,18116,0,0,0,44615,15403,13958,0,1540,14632,19525,24201,19781,0,0,0,24165,0,
-38951,0,0,0,0,0,6308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17416,15749,3438,13255,0,0,0,0,
-0,0,0,0,0,0,0,32228,0,0,0,0,176,0,0,50566,0,0,0,0,0,0,0,0,0,0,0,0,0,21540,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,58982,0,0,0,0,0,0,0,0,0,5284,0,0,0,0,0,0,25897,28326,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15945,0,0,0,9804,293,0,0,0,0,0,0,0,13988,23082,4677
-,0,0,0,0,0,0,0,0,0,0,0,5670,0,0,0,0,0,0,0,44070,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,6405,0,30692,0,0,0,61702,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,45926,0,15398,0,0,0,0,0,0,4554,2692,0,0,0,0,0,32485,0,0,0,10084,0,0,0,0,0,0,
-24297,0,0,0,0,0,0,0,0,22790,0,0,0,55110,0,0,0,0,0,0,0,0,0,0,0,0,7112,0,31530,
-45255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40743,17226,22599,0,
-0,0,0,0,0,0,0,3695,0,0,0,0,0,0,0,0,0,0,56999,0,0,0,0,0,13799,3114,21287,1353,
-7591,0,0,0,8455,0,0,6824,0,0,0,0,0,0,0,14569,0,0,0,29000,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,19979,0,18376,0,0,0,0,0,0,0,0,0,0,0,0,11332,0,0,0,49863,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,2191,7527,23148,58022,0,0,0,30631,0,26565,0,0,0,0,0,0,0,0,0,0,0,0,754
-,0,0,15877,0,0,0,0,0,0,0,17510,7657,2821,0,0,0,0,0,0,0,0,0,41927,0,0,0,0,0,0,0,0
-,2569,34439,0,0,3790,0,0,0,15339,8775,0,0,0,0,0,0,0,0,0,0,0,15908,0,0,21419,8359
-,0,0,0,0,424,0,0,0,0,0,0,25318,8008,20551,0,0,0,45735,30058,30372,0,0,0,0,0,0,0,
-0,0,0,0,0,0,26180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31432,10567,0,0,0,0,
-17450,0,0,0,0,0,0,30310,0,38022,0,0,0,0,0,28932,0,0,0,0,0,43910,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,22180,12075,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22247,0,0,22826,
-12359,0,0,0,0,4105,50407,0,0,0,0,0,0,13581,28583,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,28936,0,0,0,0,0,17673,10310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,905,57862,
-1580,0,0,0,0,58630,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13479,0,0,
-14153,13286,0,0,9259,0,0,0,0,0,6606,3524,0,0,0,0,0,6567,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,631,49255,0,0,0,0,0,42886,0,38215,0,0,0,0,0,0,0,0,17580,
-0,0,0,0,0,0,0,0,55046,0,0,0,0,0,0,0,0,0,10213,0,0,0,0,3604,37767,0,0,0,0,0,0,0,0
-,0,0,0,30950,0,0,0,0,0,0,0,0,0,62087,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23528,0
-,0,0,0,0,0,0,0,0,28715,4229,0,0,0,0,0,0,0,0,0,0,1226,26820,0,0,0,12133,6984,261,
-21130,32548,0,0,0,0,0,0,3565,12390,20713,28071,0,0,1706,25287,0,0,0,0,0,0,0,0,
-14670,0,0,0,0,0,0,30534,0,0,0,12615,0,43750,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28228,
-0,0,0,0,0,0,0,45095,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1224,3975,10954,6375,0,0,0,0
-,0,0,0,0,0,0,23180,20100,0,0,0,0,25736,8519,0,0,0,0,0,6663,0,2534,0,0,0,0,0,0,0,
-0,23720,0,0,0,0,0,0,0,0,0,0,19398,0,47814,26281,49702,0,0,4332,12965,0,0,5704,
-3206,0,0,0,0,0,0,0,0,0,0,0,0,0,15396,0,0,0,44102,0,0,0,0,0,0,0,0,0,0,0,0,0,25317
-,1064,39271,27433,0,14952,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14308,0,0,0,0,0,0,2763
-,4100,0,0,0,0,0,0,18792,0,0,0,22154,32583,0,6244,0,0,0,0,0,0,0,49478,0,0,0,0,0,0
-,0,0,0,0,0,21894,0,0,11048,0,0,0,0,0,0,11685,0,53862,0,0,15114,0,13870,0,0,0,0,0
-,0,0,919,0,0,0,31916,0,22570,101,0,0,0,0,0,0,0,0,0,7333,0,0,0,0,3272,0,0,0,0,
-27718,32712,0,0,0,0,0,0,0,0,0,1782,0,3688,0,0,0,0,29862,0,0,0,0,0,0,0,22469,0,0,
-0,0,0,0,0,55302,850,15492,0,0,0,5927,19786,13350,0,25702,0,0,0,0,0,0,0,0,0,0,0,
-40390,0,0,0,0,0,0,0,0,0,0,0,0,0,20260,0,0,0,0,0,0,0,0,0,0,0,0,0,15335,8394,0,0,0
-,0,0,0,26566,0,0,0,0,843,2245,0,0,0,0,0,0,0,0,6959,0,20488,1638,0,0,11533,50759,
-0,0,0,0,0,20871,0,0,0,0,0,24519,0,0,0,0,9544,23591,0,0,0,0,0,0,0,0,0,0,20969,
-7109,29001,0,0,32422,31720,64294,0,0,0,0,16106,0,0,0,6930,4933,0,0,0,22917,0,
-27015,0,0,0,0,19880,8070,0,0,0,0,23945,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-3310,0,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18439,0,0,0,20742,0,0,0,10597,0,0,0,0,0,0,
-0,0,0,0,0,0,20236,0,0,0,16584,3429,0,0,0,0,0,0,0,0,27241,0,0,0,0,16132,0,0,0,0,0
-,0,0,0,0,0,0,0,244,28261,0,0,0,0,0,0,0,29509,0,0,0,0,0,0,0,0,2921,31781,0,0,0,0,
-0,0,6408,4196,344,0,0,0,0,0,0,0,0,0,0,0,0,0,11689,45863,0,0,0,0,906,3301,0,0,
-25544,32421,0,0,0,0,0,0,0,0,1260,61607,0,27302,0,0,8682,16614,0,0,0,0,10830,0,0,
-9604,15049,13413,0,0,0,0,0,0,26761,0,0,0,0,0,0,61990,0,0,0,0,0,12580,0,0,11432,0
-,0,0,0,0,22507,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12389,0,0,0,0,0,0,
-2408,22661,14507,43239,0,9700,0,0,24714,0,0,0,0,0,0,0,0,23972,0,0,0,0,0,0,0,0,0,
-0,0,0,0,34086,0,0,22955,7238,0,0,0,0,0,28485,13806,20038,0,0,0,0,22602,0,0,0,
-1645,22340,0,0,0,0,0,0,0,0,0,0,0,26502,0,0,554,0,0,0,0,61735,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,2694,0,0,0,0,0,0,0,0,0,0,0,0,0,0,883,27879,15948,0,3242,57382,0,0
-,0,0,0,0,13930,0,0,0,0,0,30922,0,4137,52615,0,0,0,0,0,0,0,0,0,0,0,0,0,31911,
-16072,0,0,0,0,0,0,0,0,0,0,0,0,26340,0,61671,0,0,0,0,3145,56199,0,0,0,0,0,0,0,0,0
-,0,0,0,280,0,5131,33479,0,15751,0,0,0,0,0,0,4136,1446,0,0,0,0,0,0,11304,17863,0,
-0,0,0,0,25125,0,0,0,36646,6057,0,0,0,855,11301,0,0,0,0,0,64774,0,0,0,19397,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,1040,27367,0,0,0,0,0,0,0,0,0,0,0,0,0,64358,0,0,178,
-132,0,0,14763,24455,0,0,0,46374,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,46246,0,0,0,37382,
-0,0,0,7462,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8166,0,0,6921,0,0,0,9163,0,0,0,119,
-0,0,0,23146,17156,0,0,0,0,0,9127,0,0,0,17927,0,0,0,0,0,22084,0,0,0,0,0,39879,0,0
-,2035,0,1067,0,0,0,0,0,16652,59591,0,0,0,0,0,0,0,0,0,0,0,0,20171,0,0,0,0,17733,0
-,0,0,0,0,32037,0,0,0,0,0,14277,0,0,0,0,0,0,0,42022,0,0,26793,20358,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,8907,0,0,0,0,0,0,0,0,27780,0,0,0,0,32330,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,39399,0,9732,0,16199,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,854,0,2984,45063,25418,26980,22539,0,9133,3653,15528,28743,4649,0,616,
-65127,0,0,0,61863,0,0,0,0,0,0,0,55303,0,0,0,0,0,0,0,0,23880,0,0,0,0,0,0,0,31848,
-62854,0,0,0,0,0,0,0,0,0,0,0,49606,0,27974,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,32580,0,0,0,26052,4043,0,0,40454,0,0,26056,30565,0,0,0,0,0,0,0,31398,0,0,0,0
-,0,0,0,0,29288,1797,0,0,3220,0,0,0,0,0,0,0,0,0,20427,0,0,0,0,23621,0,0,0,0,0,0,0
-,0,0,24261,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35591,0,0,6862,0,0,0,4265,0,6285,
-5383,0,0,0,0,0,36870,0,39847,0,0,17224,5414,27882,58118,0,0,13224,4262,0,0,0,
-31302,0,0,1388,2982,11881,0,0,0,0,0,0,16837,809,0,24140,10724,0,0,0,0,5835,0,0,0
-,0,0,0,0,0,0,0,0,1256,19237,0,0,0,0,0,0,0,5796,11848,0,0,52870,11464,0,0,0,0,0,0
-,0,0,0,5645,9158,0,25223,0,0,0,0,0,39142,24968,8135,32104,28678,0,0,0,46311,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23820,0,0,0,0,0,4050,0,1323,25220,0,0,0,20133,0,
-0,0,0,0,0,0,0,0,0,0,9381,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,13444,1198,60806,0,0,0,0,17356,50247,30632,0,0,0,0,0,0,0,11944,
-999,0,0,0,0,4010,10404,0,0,0,0,0,0,10346,0,0,49510,0,0,0,0,0,0,0,0,0,0,0,0,0,
-38919,0,0,0,0,0,0,6351,60966,20137,487,0,0,0,0,0,0,655,2406,17387,43303,0,0,0,
-17063,0,0,213,0,0,0,0,0,0,17221,0,0,0,0,0,0,0,0,0,0,0,10820,0,0,0,0,369,6,0,0,
-9098,21093,0,31653,0,0,0,0,0,0,0,0,0,27143,0,0,16234,0,0,0,0,0,0,0,0,6020,31723,
-28293,0,0,0,0,1936,30695,0,0,0,0,0,52902,0,0,29512,10791,0,20420,0,0,16010,0,0,0
-,0,0,0,0,0,0,0,0,5324,0,0,0,0,0,0,0,0,0,0,0,0,13383,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,24328,0,0,0,0,0,0,40870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,24648,0,0,0,0,0,0,0,7786,2852,0,0,0,0,0,0,0,0,0,44678,0,17925,0,0,105,53062,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18762,0,0,40679,0,0,0,16165,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,20390,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62310,1322,
-14247,0,0,0,0,0,0,0,0,1832,6052,0,0,11882,0,0,0,0,17668,0,28262,0,29542,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28007,0,0,0,57223,
-1585,0,0,0,0,0,0,0,0,0,0,0,21162,0,0,62247,0,0,0,0,0,25414,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,36326,0,0,0,23845,0,0,0,0,0,0,0,2693,0,0,0,0,0,0,0,
-13125,0,31236,0,0,0,0,0,22502,0,0,0,0,0,0,5994,10309,0,0,0,7269,0,0,0,0,17929,0,
-1011,44647,0,0,0,0,0,14919,0,0,0,0,20586,5350,0,0,0,45702,0,13189,0,0,0,0,0,0,0,
-0,0,35782,17992,0,0,0,0,0,8203,0,0,0,0,0,0,56678,0,0,0,0,0,38087,4233,0,2127,0,0
-,0,0,0,0,0,0,0,0,10148,0,0,0,2021,0,0,0,0,0,0,0,47206,0,0,0,0,0,0,0,9220,0,0,0,0
-,19465,0,0,0,0,0,0,0,0,39206,0,38055,0,0,0,0,0,0,0,46982,0,0,0,0,0,22054,3850,0,
-0,0,0,0,0,0,55,0,10542,0,0,0,0,7239,0,0,0,0,0,59367,0,0,14761,0,0,0,0,43079,0,0,
-0,0,0,2726,0,0,9582,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37478,0,
-0,0,31364,0,0,0,0,0,0,0,0,20393,8933,0,0,0,0,0,9380,0,0,0,0,16905,549,0,0,0,0,
-182,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1558,0,0,0,0,0,0,0,19242,0
-,0,0,0,0,0,24933,0,6276,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42310,23595,
-24068,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13191,6158,2567,0,0,268,47047,0,0,0,0,0,0,0,
-0,0,27940,0,0,0,0,0,26726,0,0,0,0,8200,1222,31562,0,0,0,0,0,0,0,0,0,2922,8231,
-8904,29157,0,0,0,0,0,0,0,0,23976,4836,0,0,0,0,0,0,0,0,0,0,0,0,31658,0,0,31685,0,
-0,2889,6213,0,0,0,0,0,13605,0,0,0,0,0,24772,0,0,0,0,0,0,0,0,0,0,20684,26468,
-24075,0,0,0,21193,0,715,679,0,0,0,0,0,0,3050,7654,0,0,0,13798,0,0,0,0,15,27973,0
-,0,8491,2086,0,0,0,43206,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60391,0,0,0,0,0,0
-,0,25892,0,22276,0,34374,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20165,0,0,25672,0
-,0,0,1811,24839,0,31044,0,0,25513,0,0,0,0,0,12810,0,0,62438,0,0,1325,0,364,3782,
-0,0,0,0,0,0,0,0,8042,19687,0,0,0,33415,0,0,0,0,0,0,0,0,0,0,0,7205,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,11844,0,0,0,0,3341,1543,6698,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,29766,0,0,0,0,0,0,0,0,0,0,0,41158,0,24294,0,3844,12329,
-0,0,0,13738,0,0,0,0,0,0,0,0,26245,0,0,0,0,0,0,6378,0,343,4838,0,0,0,24358,11688,
-0,0,0,0,0,0,0,0,0,1489,34759,0,0,0,0,363,51974,1878,11013,0,0,32265,59782,0,0,0,
-28421,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22756,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14089,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,29257,61222,0,30661,0,28327,0,0,0,0,0,0,0,0,0,0,0,0,0,
-27108,8843,0,9673,2084,0,0,0,16327,0,48455,0,0,0,0,0,0,4876,9316,0,0,0,0,0,0,0,0
-,0,0,0,0,9035,18852,0,0,0,0,0,0,0,0,0,0,0,0,0,4164,0,0,14827,1349,0,0,0,0,0,
-11909,0,0,0,0,0,0,0,0,0,21765,0,0,0,0,0,0,0,0,31272,63910,0,0,0,25924,0,0,0,0,0,
-0,0,0,0,44487,0,0,0,20612,0,0,27754,31428,0,0,0,0,0,0,0,17287,0,3943,0,0,0,63302
-,0,0,0,0,25256,19942,0,55142,0,39046,0,0,0,0,0,0,0,15367,0,0,0,0,0,0,0,0,0,0,0,
-28422,0,0,0,0,0,0,0,0,0,0,0,0,9576,63847,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,25226,5734,0,0,0,0,0,0,13801,4997,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,43942,1270,2566,6284,0,0,16230,0,0,0,20678,0,0,0,0,0,38855,0,0,0,0,
-29643,0,0,0,41,3655,0,0,0,0,0,14276,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,15686,0,0,0,15718,0,50694,0,0,16232,8007,0,0,0,5060,
-329,11591,51,0,0,0,0,0,0,0,0,0,13065,7302,27530,15366,0,24934,0,0,0,17828,0,0,
-4552,6311,0,0,0,0,0,0,0,0,0,0,0,47686,368,12103,10122,33830,0,0,599,18534,9579,
-49479,0,5668,0,0,0,0,0,0,0,0,0,13157,0,0,0,0,23274,14055,0,0,0,0,0,48903,0,0,0,0
-,0,0,1871,0,15434,0,0,0,16174,62470,0,0,0,0,0,0,0,0,0,0,0,7749,0,0,0,0,0,0,0,
-30501,0,0,0,0,25675,0,0,0,0,0,0,0,0,0,0,9285,0,0,25323,1669,0,0,0,0,0,0,0,0,0,0,
-0,3588,0,0,0,0,0,32902,0,0,4426,0,0,0,0,57959,0,0,0,0,0,0,29898,58278,0,0,0,0,
-11880,1220,0,0,0,41479,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23141,0,0,0,0,0,0,0,0,0,0,0
-,0,0,42566,0,0,0,0,0,0,0,40167,9484,3493,0,0,0,0,0,21126,0,0,0,0,8649,18918,0,0,
-0,0,0,0,0,34886,2601,0,0,0,0,12518,0,0,0,0,7976,10311,0,0,0,0,0,0,0,45190,0,0,0,
-0,0,0,0,0,0,0,16842,20229,0,0,0,0,0,0,7528,4614,0,0,0,0,0,30086,0,0,0,1671,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,9896,6277,0,0,0,0,0,61191,0,41287,0,21956,0,0,20010,0,0,0
-,0,0,0,0,0,0,0,0,13195,0,0,0,0,1381,0,0,0,0,365,30951,24268,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,7044,0,0,0,0,0,0,0,0,0,0,27944,359,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,28487,0,0,77,0,0,0,0,0,0,0,0,56775,12586,8421,0,0,0,0,0,0,26185,14599,0,0,
-8040,5702,12585,3109,0,0,0,0,0,21574,5388,0,0,0,0,0,0,0,5106,52454,0,0,0,0,0,0,0
-,0,1907,29895,0,6116,0,0,0,0,11081,5285,0,28069,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4104
-,0,0,0,0,0,0,41511,0,0,0,0,0,0,5262,0,0,0,503,4231,7720,34343,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7304,10374,1718,0,0,29127,0,0,0,0,0,0,0,0,23497,
-22567,6952,2340,0,0,0,0,0,0,0,0,20360,12453,0,45094,0,0,0,0,0,28582,0,0,0,0,680,
-0,0,0,0,0,0,0,0,0,0,0,0,0,23084,0,0,0,30696,0,0,0,0,45862,0,0,0,0,0,0,0,0,0,0,0,
-0,5580,6053,0,0,0,0,0,0,0,0,0,0,712,70,0,0,26091,11335,0,0,0,0,13612,0,13160,
-1926,435,51559,0,0,0,0,0,0,0,0,0,0,0,0,0,47302,19083,0,0,12742,0,1607,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,6155,37095,0,0,0,0,0,18948,7146,0,0,0,0,0,0,0,7848,
-2055,0,0,0,0,8910,0,19336,0,0,48070,8490,0,0,0,0,0,0,0,9932,56423,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,4133,0,0,0,0,0,0,0,0,0,43398,0,0,0,0,0,0,0,0,16173,0,0,0,0,0
-,0,0,32011,0,0,30918,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26854,0,0,0,0,0,0,0,0,0,0,0,0
-,0,20389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18889,0,0,0,0,8965,0,0,0,44358,0,0,0,8997,0
-,34055,0,0,0,0,0,29350,0,0,501,17767,0,0,32457,60262,0,0,0,30886,0,0,3757,1063,0
-,0,0,25637,0,0,0,0,0,28068,0,26374,0,0,0,0,0,0,0,0,0,0,0,11684,0,0,0,0,0,0,24779
-,229,0,13766,0,0,7402,11525,0,0,0,0,0,0,0,0,26313,23686,0,0,29736,47527,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27268,0,0,0,0,553,0,0,0,0,0,0,32038,0,0,0,0,1135,
-26596,0,0,12300,14631,0,0,0,43238,0,871,0,0,31496,0,8457,17669,0,12836,0,0,0,
-22726,0,38758,0,0,375,6564,0,0,0,0,0,0,0,0,0,0,0,0,170,18535,0,22948,0,0,32360,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,25764,0,0,0,0,0,0,0,0,0,0,0,15652,0,0,0,32774,0,0,0,0
-,0,0,0,0,0,28551,0,0,0,0,0,0,0,0,0,0,0,0,15145,0,0,0,21100,27654,0,0,0,0,0,0,
-4874,26215,0,1639,0,0,0,0,0,0,0,0,0,0,4169,0,0,0,0,0,7336,0,0,0,0,21572,0,0,0,0,
-0,0,0,0,0,24644,1675,2533,0,0,0,53318,0,13094,0,0,0,0,0,0,0,6246,0,22020,0,0,0,0
-,0,0,0,0,0,0,0,28453,5576,5124,0,0,0,0,0,0,0,0,0,0,0,0,0,27910,0,29382,18216,
-8583,0,0,0,39174,0,43558,0,0,0,0,0,0,0,0,0,11973,0,0,0,0,0,23397,0,0,0,0,6091,0,
-0,0,0,0,0,0,6474,16197,14217,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,26728,0,567,48839,0,0,0,0,0,15271,0,0,31818,43974,2450,0,0,0,0,0,0,0,
-11368,9191,0,44454,0,0,0,0,0,0,14568,12293,0,0,0,8453,0,0,0,0,0,0,0,0,0,0,0,0,
-32040,0,0,0,0,0,0,0,0,0,0,0,0,902,0,0,0,27236,5612,11495,0,0,0,0,0,0,0,0,9194,
-23684,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27430,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-26217,44870,0,0,0,0,0,0,5581,7173,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-52775,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20968,18340,0,0,0,0,0,0,0,0,4107,11239
-,0,0,0,0,0,0,0,0,0,0,0,29381,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21990,0,0,0,0
-,0,0,0,0,0,48806,0,0,0,32292,0,0,0,0,0,0,0,10884,0,0,0,0,0,0,0,0,0,0,27562,0,
-5643,0,0,0,0,0,0,0,0,0,3089,31525,0,19684,0,0,0,0,0,0,0,61415,0,0,0,0,0,36198,0,
-0,0,0,0,0,0,7908,0,0,0,0,872,743,0,0,0,0,0,0,0,0,1229,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,32484,0,0,0,0,0,34822,0,0,0,0,0,50726,0,0,0,0,7274,0,0,0,15304,
-11526,0,0,0,3047,0,0,0,0,0,0,22376,0,0,0,846,0,0,0,0,35815,0,0,0,23652,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,23721,2148,0,0,0,0,0,0,14856,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,1358,0,3082,0,0,0,848,10949,0,0,0,0,0,0,6504,0,0,14372,0,0,0,0,0,0
-,0,0,0,0,8201,9958,0,0,0,0,0,0,24266,0,0,0,0,0,0,0,0,26469,0,0,0,0,18604,2053,0,
-33511,0,0,0,0,0,9222,0,0,0,0,0,44006,0,0,0,0,0,0,0,0,0,0,0,41895,0,0,0,0,0,0,0,0
-,12044,390,0,0,0,0,0,4935,0,48646,0,56102,3052,16070,0,0,0,0,0,0,0,8612,9320,
-38311,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,500,0,0,0,0,42918,0,
-32550,0,0,0,0,0,0,0,0,27434,57926,17064,0,0,46502,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,26760,6756,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,624,0,5000,0,0,0,0,32293,0,
-0,0,0,0,0,0,0,0,0,0,0,0,26246,0,0,0,0,0,0,0,0,23,7301,0,0,0,36199,0,40838,0,0,0,
-0,0,0,0,0,0,0,0,0,27178,57350,0,0,12457,9317,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16810,0,0,0,14510,0,0,0,0,21319,0,0,0,13508,17,
-11365,0,0,0,0,5291,0,8329,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27685,0,0,0,0,0,0,0,
-52006,0,0,0,7493,0,44263,0,0,0,0,0,0,0,0,9800,0,0,0,25676,61478,0,0,0,0,0,0,5773
-,0,0,0,0,41991,26057,0,0,0,0,0,0,0,0,0,0,22629,0,0,0,47783,362,1959,23468,0,0,0,
-10921,0,0,0,3150,0,0,0,0,0,0,0,0,0,0,0,32456,0,0,0,0,0,0,0,4559,3270,0,0,983,0,0
-,26343,0,33446,0,0,0,61767,0,48390,0,0,0,0,0,0,0,2790,0,39782,7849,0,0,0,0,0,0,0
-,1544,2183,0,0,0,0,0,0,0,0,4040,2471,20009,30020,0,0,11242,0,0,0,5578,53382,0,
-22631,0,0,0,0,0,0,0,0,0,0,0,12901,0,0,0,0,0,0,0,0,0,0,0,0,215,0,0,9030,0,0,0,0,0
-,0,265,1412,0,0,11626,3687,0,0,0,0,0,0,0,0,0,0,0,0,17449,24359,0,0,26729,40134,0
-,0,0,0,29768,61958,0,0,0,0,0,0,0,0,20908,0,0,0,0,0,11016,0,0,47462,21547,5926,0,
-0,14728,2983,24104,15301,0,0,0,0,0,32645,0,0,0,0,0,0,0,3300,0,0,0,15972,0,0,0,0,
-0,0,6634,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3076,0,30983,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,106,0,0,0,0,12775,0,0,0,0,7177,18022,0,0,0,0,0,22534,0,0,0,0,0,0,0,0,0,0,0,
-49894,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27560,0,0,0,0,30278,10668,23877,0,
-0,0,0,0,0,0,29124,0,0,0,0,0,0,0,0,0,0,0,0,0,20870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,44582,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48454,0,0,0,0,6442,0,16330,22951,0,0
-,16904,0,0,0,0,644,0,0,0,40038,0,0,0,37222,0,0,0,9830,0,0,0,0,0,34919,0,0,0,0,0,
-0,0,0,0,0,0,13733,0,0,0,28196,0,0,0,0,0,19876,0,0,0,0,0,0,0,23558,0,11142,0,
-27781,0,0,0,0,13864,0,0,0,24682,47847,0,0,0,0,6890,0,0,0,0,0,3981,0,0,0,0,0,0,0,
-0,0,0,0,1772,0,0,0,0,0,0,0,3603,1991,0,27396,8652,0,18312,0,0,0,0,30054,0,0,0,0,
-0,0,0,11270,0,0,0,0,0,0,0,0,0,20708,0,0,0,0,338,0,0,0,0,0,0,0,7050,0,0,0,0,0,0,0
-,0,0,0,0,0,0,14862,0,0,3492,0,0,0,55878,0,0,0,16486,0,0,0,18119,0,0,0,0,0,0,2154
-,1284,0,0,23113,31751,0,0,29547,0,0,0,0,0,0,36647,0,0,0,0,0,0,0,0,0,0,0,18183,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,7913,0,0,0,0,20644,0,0,10508,0,0,0,0,0,0,0,0,0,0,0,0,
-43622,0,0,0,0,0,40966,0,0,0,0,0,0,0,0,0,0,246,901,11529,5191,0,0,0,0,0,0,0,0,0,0
-,0,24454,0,0,26665,27590,0,27397,0,0,0,0,0,0,23562,2949,0,0,30344,62214,0,47334,
-2026,18885,0,0,0,48678,0,0,0,22694,0,0,1972,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,15465,0,0,0,0,38822,0,0,0,0,945,32708,0,54791,0,14918,0,0,0,0,0,0,
-0,0,0,0,0,0,0,23396,0,0,0,0,0,0,5486,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7722,0,0,
-0,0,0,0,0,0,0,0,0,30856,64166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35206,0,0,0,30535,0,
-0,0,0,0,0,0,0,0,62663,0,0,1096,17574,31820,0,0,14375,4402,27207,0,0,21448,4676,0
-,0,0,0,16585,5094,0,0,0,0,0,0,0,0,4845,0,0,32870,0,0,0,0,0,0,0,0,0,0,31466,0,0,0
-,0,31783,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4522,16039,0,0,0,0,0,0,0,0,
-0,14469,0,0,0,0,0,0,0,0,0,0,7464,4773,0,0,0,0,0,0,0,0,18636,0,0,0,25640,0,0,0,0,
-0,0,2244,0,0,11818,0,1168,0,0,0,0,0,0,0,6540,23079,13770,7719,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,58150,528,
-34502,32682,0,0,12997,0,0,0,0,0,2214,0,0,0,0,0,58567,0,0,0,26375,0,0,0,0,0,0,0,0
-,0,26437,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,32005,22952,59047,0,13543,0,0,0,0,0,0,0,0,16328,0,0,33542,0,0,0,19782,0,0,0,
-16644,0,0,0,0,31688,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10276,0,0,0,
-0,0,0,0,36327,0,0,29480,0,0,0,777,12709,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27398,0,0,
-0,4455,9037,31397,0,9221,0,0,0,60487,20840,1796,0,0,0,0,0,0,0,0,8364,0,0,0,0,0,0
-,0,0,0,0,0,19752,44902,0,38566,0,0,18027,0,0,0,0,0,0,0,0,10662,0,0,0,0,0,11812,0
-,0,0,0,0,0,0,0,0,19910,0,0,0,45030,0,0,0,0,0,0,0,0,0,0,0,0,19978,5127,0,11620,0,
+BROTLI_INTERNAL const uint16_t kStaticDictionaryHashWords[32768] = {
+1002,0,0,0,0,0,0,0,0,683,0,0,0,0,0,0,0,1265,0,0,0,0,0,1431,0,0,0,0,0,0,40,0,0,0,
+0,155,8,741,0,624,0,0,0,0,0,0,0,0,0,0,0,0,66,503,0,0,0,451,0,0,0,0,0,0,0,835,70,
+0,0,539,0,0,0,0,0,0,0,0,0,113,0,0,0,0,718,0,0,0,0,0,0,520,0,1070,0,0,0,0,0,1515,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,610,0,0,750,0,0,0,307,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,964,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,999,0,0,0,0,0,0,0,0,
+645,75,0,649,52,282,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1621,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,211,225,0,0,687,718,0,0,110,0,58,0,0,0,0,0,0,345,0,0,301,0,0,
+0,203,0,0,1154,674,1949,0,0,0,0,0,0,0,0,0,259,0,0,0,0,0,0,0,1275,0,0,0,1231,254,
+0,0,0,0,0,0,0,277,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,0,0,800,0,0,0,29,
+116,100,490,0,0,0,0,0,1641,0,543,0,0,0,0,41,181,0,657,0,0,202,25,0,0,0,0,0,0,0,
+0,0,0,423,0,0,0,113,0,0,0,927,963,0,976,0,206,0,0,0,0,0,0,0,0,0,2002,0,0,0,0,0,
+0,0,0,0,0,0,696,0,1170,0,0,0,0,226,13,0,769,678,551,0,0,0,0,0,0,57,0,0,0,10,188,
+0,0,0,624,0,0,0,0,0,0,0,0,0,1941,130,0,0,0,0,378,269,0,0,528,0,1146,0,0,0,1105,
+0,1616,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,656,0,1940,0,0,0,0,0,173,0,0,0,0,0,0,0,0,0,
+0,0,457,342,810,0,0,0,0,620,0,0,0,0,0,0,0,967,95,447,406,0,0,0,477,0,1268,944,
+1941,0,0,0,629,0,0,0,0,0,375,0,0,0,1636,0,0,0,0,774,0,1,1034,0,0,0,0,0,824,0,0,
+0,0,0,118,0,0,560,296,0,0,0,0,0,0,0,0,1009,894,0,0,0,0,0,0,0,0,0,0,0,0,0,1474,
+366,0,0,0,0,0,0,0,0,0,79,1723,0,0,200,0,0,0,0,0,0,0,0,1759,372,0,16,0,943,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,258,0,0,900,1839,707,30,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,2004,0,0,10,115,0,50,0,0,0,0,0,0,0,0,0,0,520,1,0,738,98,482,0,0,0,0,
+0,0,0,0,0,0,701,2,0,0,0,0,0,0,0,0,557,0,0,0,0,0,0,0,0,0,347,0,0,0,0,572,0,0,0,0,
+0,0,0,0,0,832,0,0,797,809,0,0,0,0,0,0,0,0,0,0,0,528,0,0,0,861,0,0,294,0,0,0,109,
+0,0,0,0,0,0,0,0,1187,290,266,0,0,0,0,49,50,748,0,0,466,399,0,0,0,0,0,0,0,378,0,
+519,0,0,0,0,0,0,0,0,0,0,0,0,667,351,902,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,180,
+0,0,869,0,0,0,0,0,0,0,260,0,0,0,0,0,0,0,0,0,0,523,36,0,0,587,510,809,29,260,0,0,
+0,0,0,0,0,0,570,0,565,0,1464,0,0,0,0,0,0,10,0,0,787,399,380,200,0,0,0,0,516,0,
+844,887,0,0,0,0,0,0,0,44,0,0,0,305,1655,0,0,0,0,0,0,0,0,0,0,0,0,0,0,786,10,0,0,
+0,0,0,0,0,0,0,2031,0,0,0,0,0,684,0,0,0,0,0,1480,0,0,0,27,0,0,0,395,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,813,511,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,0,0,0,206,
+496,0,0,0,0,0,909,0,891,0,0,0,0,0,0,0,0,0,687,0,0,0,1342,0,0,0,0,0,0,0,0,0,0,
+160,41,0,0,0,0,0,0,0,0,0,0,0,1718,778,0,0,0,0,0,0,0,0,0,0,1610,0,0,0,0,0,115,0,
+0,0,0,314,294,0,0,0,983,178,193,0,0,0,0,0,0,0,0,0,174,0,0,0,0,0,0,0,0,0,0,848,
+1796,0,0,0,0,0,0,221,0,687,1660,0,0,0,0,262,0,0,179,0,0,0,0,0,66,0,773,0,352,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35,0,152,0,0,1197,0,0,0,0,0,0,0,0,0,0,0,0,560,0,0,
+564,0,0,0,797,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,556,0,819,0,0,0,0,0,0,0,0,719,544,
+637,5,0,0,0,0,0,0,0,0,0,0,0,101,0,1441,0,0,0,893,0,0,0,0,0,0,0,0,0,238,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1296,0,0,969,1729,314,60,0,0,0,0,0,1144,0,1147,0,0,0,0,0,
+0,0,0,0,0,437,1853,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,828,0,176,0,0,0,0,0,0,434,39,0,
+0,0,0,0,159,0,0,0,902,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,270,0,0,0,0,801,556,0,0,
+0,0,0,0,0,416,19,197,369,0,0,0,0,0,0,0,0,0,28,34,0,757,0,0,898,1553,0,721,0,0,0,
+0,1012,0,0,0,0,1102,0,898,183,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,247,277,0,0,0,435,0,0,0,0,0,1311,0,0,0,0,
+0,0,211,437,0,0,0,28,0,0,750,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2012,0,702,
+0,808,0,0,0,0,739,166,0,0,0,0,0,0,719,170,500,0,0,0,0,0,0,0,0,1500,327,0,0,450,
+0,0,0,1318,0,0,0,1602,0,0,331,754,0,0,0,0,0,1368,0,0,557,0,0,0,799,850,0,0,0,0,
+0,0,0,0,908,0,0,0,0,0,19,62,459,0,0,0,0,0,0,0,0,0,0,0,0,1802,0,0,0,0,0,0,0,0,0,
+1397,0,0,0,0,120,238,0,0,0,0,0,0,0,0,0,0,0,1324,0,0,0,0,0,0,0,0,602,201,0,0,164,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,615,0,0,0,0,0,0,0,0,0,0,0,0,0,1243,0,0,0,0,968,0,0,
+0,0,0,0,882,0,0,0,907,329,100,0,0,0,0,0,0,0,0,0,0,0,176,26,9,0,0,265,256,0,0,0,
+0,0,0,0,0,0,643,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,610,0,0,0,0,973,2001,0,
+0,0,0,0,0,522,0,0,0,0,0,0,0,0,0,0,0,553,0,0,0,0,0,0,1582,0,1578,0,0,0,0,0,0,0,0,
+0,0,0,795,0,0,0,432,0,0,0,0,0,0,84,126,0,0,0,0,790,0,377,64,0,1529,0,0,0,0,530,
+1857,539,1104,0,0,0,0,0,0,0,0,0,0,0,0,977,0,0,0,34,0,0,0,0,0,0,0,0,0,0,0,24,26,
+0,0,918,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,183,379,0,0,0,0,0,0,0,792,
+0,0,0,0,0,0,0,0,0,1920,0,0,0,0,0,0,0,0,0,771,0,0,0,1979,0,901,254,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,140,0,0,0,0,0,440,37,0,
+508,0,0,0,513,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,533,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,752,920,0,1048,0,153,0,
+0,391,0,0,1952,0,0,0,0,0,0,0,0,0,0,126,0,0,0,0,640,0,483,69,1616,0,0,0,0,0,734,
+0,0,0,0,0,0,480,0,495,0,472,0,0,0,0,0,0,0,0,874,229,0,0,0,0,948,0,0,0,0,0,0,0,0,
+1009,748,0,555,0,0,0,0,0,0,193,0,653,0,0,0,0,0,0,0,0,0,0,984,0,0,0,172,0,0,0,0,
+0,0,0,0,83,1568,0,0,384,0,0,0,0,0,0,0,164,880,0,0,0,0,0,0,0,0,0,0,0,367,121,0,0,
+828,0,0,0,0,0,0,0,1541,0,0,0,0,0,0,0,343,0,0,0,0,0,0,0,0,561,57,0,0,0,0,0,0,0,
+926,0,0,0,0,827,0,194,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,0,0,0,0,0,0,0,
+0,0,0,896,1249,0,0,0,0,0,1614,0,0,0,860,0,0,0,0,0,0,0,0,964,102,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,899,0,569,0,0,0,0,795,2045,0,0,0,
+0,0,0,104,52,0,0,0,0,0,604,0,0,0,0,779,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,
+494,0,677,0,0,0,0,0,0,0,508,0,0,0,0,0,0,0,0,0,1014,0,957,0,0,630,310,0,0,0,570,
+0,0,449,0,64,537,0,0,0,0,0,0,0,244,0,0,0,0,0,0,0,0,0,0,0,0,0,0,702,1650,49,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,338,0,0,0,0,1279,0,0,0,0,0,0,0,896,0,0,
+178,0,0,0,0,0,0,0,0,0,0,0,0,0,808,695,0,0,0,0,539,1117,0,0,0,0,0,0,0,0,257,0,
+1003,0,0,0,1,448,0,516,0,0,960,0,125,4,0,1268,30,748,0,0,852,0,0,0,6,0,0,848,
+236,1385,862,1811,0,0,0,0,698,803,0,0,0,0,0,0,0,610,992,0,0,878,0,1847,0,0,0,0,
+0,0,0,383,0,1404,0,0,0,0,986,0,347,0,0,0,0,0,0,0,0,0,0,0,592,572,0,1411,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,606,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1829,0,0,0,0,0,0,0,0,0,0,0,0,700,748,0,0,0,0,0,0,365,0,0,127,0,0,
+83,198,0,0,0,0,0,0,864,55,0,0,0,0,726,1752,0,0,0,0,0,0,0,0,0,0,0,0,0,1066,0,764,
+0,0,0,0,683,0,550,309,0,0,874,1212,0,0,0,1364,0,986,381,723,0,0,0,1573,0,0,0,0,
+0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1559,0,0,0,0,493,133,0,0,0,0,148,
+119,0,0,0,0,0,0,537,14,541,0,635,126,0,0,0,495,0,0,0,0,861,998,1009,0,0,0,0,0,0,
+0,359,368,0,0,0,0,304,1577,0,0,0,0,0,1107,0,0,0,0,0,929,0,0,0,1142,0,0,0,0,289,
+175,0,432,0,219,0,0,0,0,0,785,0,0,595,0,0,0,0,0,0,0,0,0,0,0,0,0,80,0,0,0,0,0,0,
+931,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1323,0,0,0,0,290,0,559,1751,127,0,0,0,
+934,1167,0,963,0,260,0,0,0,573,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+580,1689,0,0,0,0,0,0,0,0,0,1164,0,0,982,1922,0,63,0,0,0,0,0,793,0,0,0,0,0,0,0,0,
+0,0,0,0,0,67,790,0,0,0,0,0,0,0,0,0,0,391,443,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,271,0,0,0,0,0,0,0,0,0,0,0,1140,0,0,0,0,340,300,0,897,0,0,0,0,0,0,
+0,0,0,0,890,0,0,0,0,818,321,53,0,0,0,0,0,0,0,0,0,468,0,243,0,870,0,0,0,1765,121,
+0,0,0,180,518,0,822,419,634,0,0,0,0,0,0,0,0,0,898,0,0,0,0,454,36,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,806,0,0,0,0,0,0,0,0,0,0,0,0,1326,0,104,0,0,0,0,0,0,0,
+0,0,260,0,0,0,0,0,0,0,0,0,0,0,0,542,45,0,0,263,1516,42,0,0,0,0,0,468,0,1005,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,288,87,0,0,0,0,0,0,0,0,502,988,133,0,0,0,0,0,0,
+141,0,0,872,1842,0,0,0,0,0,0,0,0,261,619,0,0,0,0,189,246,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,678,0,0,0,0,0,0,0,0,0,0,0,0,285,35,0,517,0,0,0,0,0,0,0,0,0,0,
+540,214,667,0,74,0,0,125,0,0,0,0,0,761,131,0,0,0,0,0,0,0,0,0,0,0,0,0,333,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1338,94,0,0,0,0,0,0,0,0,0,0,0,0,449,0,646,103,
+86,641,2028,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,869,87,277,117,39,0,0,0,0,0,0,0,0,938,
+297,0,0,0,0,558,464,0,0,0,0,0,0,0,0,0,0,731,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1608,0,
+0,0,0,0,0,0,1429,0,0,733,1010,0,0,338,1656,0,0,0,1038,979,2010,0,0,0,0,0,0,0,
+1005,0,0,121,0,0,0,219,20,0,0,0,0,0,0,872,1440,0,0,0,683,0,1070,0,0,522,0,0,0,0,
+439,669,0,0,0,0,0,0,0,0,1245,0,0,0,0,0,1218,0,0,547,233,0,0,0,0,0,0,0,0,0,482,0,
+0,0,0,0,0,0,886,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,795,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,371,0,0,0,0,0,0,0,0,0,0,0,0,0,622,0,625,0,0,0,339,29,0,0,338,0,0,0,
+0,130,0,0,0,0,0,0,0,0,0,307,0,0,0,0,0,0,0,0,0,0,2044,0,0,0,0,0,0,0,0,308,770,0,
+0,0,0,0,1266,0,0,0,0,0,0,0,0,0,400,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,690,739,0,0,
+0,0,0,0,0,990,0,0,0,1831,0,0,0,0,0,0,0,0,0,0,0,0,0,613,0,0,0,0,0,0,0,0,0,0,0,0,
+0,763,0,878,0,0,0,977,0,100,0,0,0,0,0,0,0,0,0,463,0,0,0,0,623,318,0,0,296,463,
+137,0,0,454,0,0,0,1527,58,0,0,0,0,0,0,0,18,48,0,0,0,0,0,729,0,0,0,442,0,0,0,0,
+40,449,0,853,0,0,0,0,0,0,227,0,0,0,0,0,0,1491,0,0,0,0,0,0,0,0,0,0,161,55,0,450,
+0,1174,62,0,207,0,0,0,0,0,0,0,0,869,0,0,0,0,80,213,0,0,0,0,0,0,0,0,0,0,354,820,
+0,0,747,0,0,0,954,0,0,1073,0,556,0,0,0,692,0,191,0,804,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,831,162,0,0,35,0,0,0,0,0,0,0,0,1235,0,0,0,0,0,1234,0,0,
+0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,149,0,0,0,902,204,0,0,833,0,287,366,0,0,0,0,0,
+0,992,2020,0,0,0,0,0,0,0,0,0,0,0,356,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,784,0,0,567,
+630,0,0,0,539,0,0,27,0,0,0,0,0,0,0,0,0,0,755,0,0,0,0,0,0,0,0,0,0,0,0,814,0,0,0,
+0,0,0,0,0,0,0,0,0,0,987,0,0,255,761,194,0,1086,0,0,0,0,0,0,1016,0,0,1396,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,562,271,913,0,0,0,0,0,0,0,0,320,153,45,475,0,0,
+0,0,0,0,0,713,0,327,0,0,0,0,0,0,604,552,3,359,0,0,0,0,853,80,0,0,0,0,0,0,0,2016,
+6,887,0,0,0,0,975,0,961,0,0,0,0,0,916,1891,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,100,101,390,708,0,0,0,587,983,512,0,0,0,0,0,0,0,0,0,0,0,645,0,0,0,851,0,0,0,
+0,0,498,140,217,0,0,0,1448,0,0,0,0,0,0,0,0,0,905,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+643,105,0,792,0,0,0,0,0,0,0,0,0,0,0,0,56,0,0,0,0,0,0,0,0,0,0,535,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1748,0,0,0,0,0,754,0,0,0,0,0,0,0,0,0,0,0,0,91,0,0,1565,0,91,792,
+939,3,370,0,0,0,0,95,0,0,0,0,551,7,619,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1150,0,
+0,0,0,0,0,0,0,0,0,0,0,0,671,0,0,0,0,0,888,368,149,0,0,105,1134,0,983,0,0,458,31,
+0,643,0,0,0,312,0,740,0,0,0,1642,0,0,0,0,0,0,0,236,0,0,0,0,0,0,0,59,68,0,0,0,0,
+0,867,795,0,0,0,0,970,1977,0,0,0,0,0,0,0,1148,0,775,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,970,0,0,0,0,0,0,0,0,0,665,71,0,0,0,0,827,0,0,0,0,0,0,0,0,0,
+0,479,0,0,0,0,0,0,0,0,99,607,0,0,0,0,0,0,0,1960,0,0,0,793,0,0,871,41,0,0,241,94,
+0,0,0,0,209,0,0,1497,0,0,0,0,0,0,0,0,0,98,0,0,0,463,0,0,0,0,291,0,0,0,0,0,0,0,0,
+0,0,984,0,0,0,0,0,205,0,0,0,0,0,0,205,42,0,801,0,0,0,0,0,635,0,0,533,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,371,0,1282,0,0,0,825,0,0,0,0,0,0,0,0,0,357,879,467,0,317,0,0,
+0,0,0,0,0,924,0,0,0,0,849,1795,0,0,0,0,895,1799,43,0,0,0,0,0,0,0,0,0,0,1820,0,0,
+0,0,0,0,0,525,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,110,0,493,0,174,417,0,0,
+0,0,0,583,733,0,0,0,0,0,0,481,215,0,0,0,0,477,0,0,0,0,0,0,0,0,308,0,0,0,0,0,0,0,
+0,297,126,0,0,361,1551,0,0,0,0,0,0,871,1807,0,0,0,0,0,1307,0,685,0,0,0,0,0,0,0,
+797,0,858,0,565,0,0,0,0,0,0,0,0,0,0,0,0,434,252,826,0,0,0,0,0,0,791,0,0,0,0,509,
+231,178,601,0,0,0,0,0,0,0,0,43,1591,0,0,0,0,0,1683,0,0,0,0,45,0,0,0,0,0,0,0,0,0,
+0,1120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,556,494,0,398,0,0,0,1030,0,0,0,0,0,0,
+168,0,0,0,0,0,0,0,0,0,0,973,0,642,0,0,0,0,0,0,0,0,0,1615,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,378,594,0,1093,0,679,112,0,0,0,0,1492,540,1374,714,
+1486,0,0,0,0,825,1511,0,0,0,0,0,0,0,0,0,0,0,0,0,952,0,0,736,143,0,700,0,1540,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1557,0,0,0,860,990,0,0,0,807,0,0,0,0,0,131,
+515,0,646,0,0,0,0,117,728,508,121,0,0,0,0,0,0,357,0,0,0,0,0,0,237,0,0,0,0,0,0,0,
+0,0,1784,0,0,0,0,0,0,0,0,0,0,0,713,348,1536,0,738,0,0,0,0,0,0,0,434,0,0,0,0,0,0,
+366,1877,39,0,0,0,0,0,0,580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,873,0,0,0,0,171,0,625,
+550,107,343,943,0,0,0,0,0,0,0,768,0,0,0,0,0,0,0,799,0,0,0,894,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1673,0,0,0,0,0,0,0,0,0,0,0,1052,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+272,0,441,0,0,3,9,0,0,0,1182,0,1346,0,0,0,0,0,0,0,0,682,0,0,1004,24,0,0,968,0,0,
+0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,0,0,0,578,
+474,0,0,0,0,0,0,0,0,0,0,0,0,0,0,113,530,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,556,0,0,0,0,0,0,16,1317,0,0,97,0,0,0,703,0,0,0,0,0,0,0,0,892,0,0,0,1571,0,0,
+426,186,0,1101,0,0,0,0,0,0,0,0,937,585,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,644,291,
+0,0,0,0,749,0,162,0,0,381,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,762,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,628,21,0,0,0,0,0,0,0,0,919,0,0,0,0,0,0,0,0,0,
+633,0,0,0,0,332,0,0,0,0,0,0,0,0,0,1489,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,832,398,0,645,0,0,0,13,0,0,0,0,0,0,0,0,0,0,20,0,800,0,0,0,0,0,0,0,0,0,
+0,0,0,0,1993,0,0,0,0,769,0,0,0,665,0,0,0,0,0,0,0,0,0,0,1426,0,0,0,0,60,0,0,0,
+641,1874,0,644,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1757,0,0,0,0,0,937,0,1652,0,654,0,
+0,0,0,0,0,0,527,0,0,0,0,0,0,0,0,0,0,0,0,0,226,0,0,0,0,0,1486,0,0,0,0,0,0,0,0,0,
+0,0,325,0,0,0,0,0,0,0,1345,0,0,91,0,404,0,0,0,0,0,0,0,0,0,0,0,0,973,0,0,0,0,0,0,
+0,1176,0,549,0,0,0,0,0,0,0,0,0,0,976,0,0,0,0,0,21,0,0,0,0,0,51,0,0,0,0,314,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,198,6,0,1093,0,0,0,0,0,0,0,0,0,
+0,0,0,0,1776,0,0,0,0,0,1528,0,419,0,0,0,0,0,0,0,0,76,138,0,0,0,0,638,29,0,0,0,0,
+0,0,0,1418,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1710,0,0,0,0,0,
+0,0,0,0,0,0,0,532,23,0,0,0,0,0,0,0,862,0,0,946,592,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,70,0,0,0,0,0,0,0,0,0,812,0,0,0,76,0,0,988,0,442,0,0,0,896,0,0,0,0,0,0,
+483,0,0,0,0,1709,0,0,0,0,0,0,119,0,0,0,117,0,309,0,0,0,0,0,596,976,0,0,0,0,0,0,
+0,0,0,0,0,768,0,0,0,0,0,0,0,0,0,518,0,0,0,0,0,0,0,0,0,0,0,0,0,0,863,0,0,0,24,
+145,1020,0,0,1984,0,0,0,0,0,0,0,658,0,0,0,0,0,0,0,0,0,0,106,1827,0,1010,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,582,87,0,0,0,0,0,0,0,267,0,0,0,703,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,496,0,0,0,0,1121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,249,561,0,0,0,0,0,
+0,0,760,0,0,154,0,0,0,255,0,419,323,0,0,0,0,0,368,0,0,0,0,0,0,0,0,0,0,522,0,0,0,
+0,0,0,0,551,562,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,92,0,0,0,0,
+0,0,0,284,525,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,958,0,0,594,0,0,0,0,0,0,6,479,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,61,0,0,0,0,0,0,0,820,1641,0,1556,0,0,0,0,0,0,0,302,0,0,
+0,0,0,148,0,0,676,0,0,0,0,0,0,1674,0,0,0,0,0,0,178,0,0,0,0,0,0,0,94,389,0,0,0,0,
+91,8,0,0,0,0,0,0,0,0,0,0,112,0,0,0,0,0,0,0,0,0,0,747,0,0,0,0,0,0,0,1746,0,0,0,0,
+0,24,0,1352,158,1530,0,0,718,130,280,1401,0,0,0,0,0,1946,8,0,0,0,0,1607,0,0,0,0,
+0,0,882,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,417,0,0,0,1597,633,433,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,234,0,0,0,0,0,0,0,0,680,1950,0,0,0,0,249,5,0,0,0,
+0,0,0,0,0,0,1216,0,1773,0,0,0,0,0,0,0,0,0,0,0,0,0,0,509,180,0,0,0,0,0,0,0,1002,
+0,0,0,0,0,0,0,0,0,0,0,0,0,931,0,0,0,0,0,0,0,0,747,943,0,1837,0,0,0,0,0,0,0,641,
+0,0,0,0,280,0,0,0,5,0,0,0,0,0,72,545,0,0,0,0,0,0,0,0,0,742,0,0,254,151,872,0,0,
+0,0,0,0,0,0,0,0,0,0,921,0,0,517,833,0,1680,0,0,436,251,584,0,0,0,0,0,0,0,0,0,0,
+0,24,500,0,0,0,0,0,0,0,0,195,1775,514,389,0,0,0,0,0,0,0,743,0,0,0,0,0,0,292,0,0,
+0,227,1283,774,1805,0,0,0,0,0,0,0,0,0,0,119,81,0,0,0,0,0,0,0,0,0,0,0,0,0,0,913,
+1910,0,0,0,1826,490,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1162,700,30,
+0,0,0,721,839,0,0,0,617,0,0,0,0,0,0,0,0,0,169,428,0,0,0,0,0,1648,637,1205,0,0,0,
+1596,0,0,4,266,0,0,0,0,0,0,0,0,0,0,0,862,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,
+0,279,157,391,604,0,0,713,945,877,973,0,0,0,0,0,0,0,0,0,0,0,0,0,0,859,567,628,
+1846,0,0,0,0,0,0,0,0,0,762,0,0,191,0,0,0,0,298,0,0,767,909,0,0,0,0,0,0,0,795,0,
+0,301,0,0,1970,0,0,0,0,0,0,0,0,0,1236,0,0,0,0,0,0,644,369,15,0,160,71,0,0,0,0,0,
+1447,0,0,0,0,0,0,0,0,735,1255,76,0,0,0,0,0,0,0,0,0,0,474,0,0,0,0,0,0,0,0,0,0,
+841,0,0,0,0,0,0,0,0,0,0,836,0,0,0,0,0,1622,0,0,735,0,0,0,0,1601,804,1390,394,0,
+0,0,0,0,0,96,0,289,0,0,35,688,0,0,0,667,0,513,0,0,0,0,0,0,0,2034,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,704,0,1524,0,1078,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,306,
+0,0,0,0,0,0,0,431,0,1196,0,0,54,0,15,1448,0,1418,0,0,0,0,0,0,0,0,0,907,0,0,0,0,
+0,0,194,1767,0,0,0,0,0,840,0,900,0,0,0,0,0,0,0,0,0,0,0,1436,0,0,0,0,642,1560,0,
+0,0,0,0,0,94,386,0,0,0,0,0,0,0,0,0,0,830,416,0,0,20,731,0,0,0,0,0,0,0,0,697,0,0,
+662,0,0,0,0,0,0,0,0,0,861,0,0,0,0,0,0,0,871,671,864,0,928,7,0,332,0,0,0,0,1055,
+0,0,0,0,0,0,986,0,0,0,0,0,44,76,0,0,0,0,0,0,0,0,0,0,300,0,0,0,0,0,0,0,175,518,
+831,1108,0,0,0,836,0,1852,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,843,1804,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,246,0,0,0,610,202,0,0,36,0,0,0,240,654,13,0,0,0,0,0,0,0,
+0,391,0,403,0,0,0,0,0,0,0,0,0,0,75,0,366,815,0,0,631,0,0,0,0,0,0,0,0,345,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,952,0,0,0,0,0,0,0,0,0,0,0,673,35,662,0,287,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,5,34,0,0,0,0,0,0,0,0,151,0,427,0,0,382,0,0,0,329,0,0,279,0,0,0,
+0,0,0,0,0,0,0,906,0,0,366,843,0,1443,0,1372,992,0,36,123,0,649,0,0,0,0,0,767,0,
+1018,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,995,0,0,0,0,0,0,0,72,368,0,0,1345,0,0,0,
+589,0,0,0,0,0,0,0,0,0,1988,0,0,220,541,0,0,0,686,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,32,196,0,0,0,0,0,0,0,0,0,0,0,0,0,381,0,0,0,0,0,0,0,0,0,1452,0,
+0,0,616,0,0,0,0,0,0,0,0,0,1229,0,0,0,0,0,0,0,0,0,0,667,120,0,0,0,0,0,0,0,1146,0,
+0,0,0,0,0,0,0,0,0,0,352,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0,0,935,0,1050,0,
+147,88,0,0,923,0,0,0,0,0,934,0,0,0,0,0,0,0,0,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,341,222,0,0,0,0,0,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0,
+637,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1159,0,0,0,847,0,0,0,0,0,0,683,0,867,944,0,0,
+0,0,0,1809,0,0,0,0,0,0,0,0,0,0,395,170,0,0,0,0,0,0,0,0,0,0,618,535,0,1625,0,0,0,
+0,0,0,0,0,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,778,0,0,0,0,0,46,0,2032,0,0,37,
+1458,0,938,363,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,314,0,0,0,0,0,0,889,0,0,0,0,0,0,0,
+0,0,0,0,462,0,0,0,0,525,0,0,23,0,0,0,0,0,0,0,0,0,0,0,676,0,0,0,0,0,0,0,0,0,0,0,
+0,498,725,0,0,0,0,7,0,0,0,0,773,0,0,0,164,0,0,0,0,0,0,0,0,936,583,659,1462,0,
+220,0,0,0,0,803,0,0,544,119,0,0,0,0,0,0,0,0,0,0,0,181,176,0,1192,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1878,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,0,0,0,0,0,0,
+944,0,0,0,0,0,0,0,273,0,0,0,0,0,855,0,0,0,0,5,127,0,0,0,0,0,0,0,0,752,230,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,162,0,654,48,156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197,
+0,0,0,0,0,0,0,963,0,0,0,0,0,0,0,0,0,0,858,0,0,0,0,0,0,0,0,0,0,676,1978,0,0,102,
+972,0,0,0,0,0,0,0,361,0,461,0,0,0,472,0,0,0,0,0,0,0,0,0,0,0,0,0,0,747,905,0,0,0,
+155,0,0,0,0,0,0,0,0,0,0,319,163,0,0,0,0,0,0,0,0,0,848,0,0,36,631,0,0,0,0,0,1769,
+0,0,0,0,0,144,0,0,0,0,0,0,0,0,0,0,369,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,555,247,0,0,
+996,0,0,189,0,0,0,0,0,0,0,0,0,0,280,0,0,0,0,0,0,0,0,0,0,0,526,746,0,0,345,0,0,0,
+1017,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,651,428,0,0,0,1162,230,327,546,792,0,0,0,
+1203,0,0,0,0,0,0,0,0,0,672,189,0,0,0,0,0,0,99,0,0,0,298,0,0,0,0,0,0,555,397,0,0,
+0,0,0,1157,0,0,0,0,0,0,0,0,0,0,398,1523,0,366,0,0,787,0,0,0,282,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,157,0,941,0,0,0,0,0,1336,0,0,116,0,0,0,0,0,0,787,0,0,0,0,0,0,0,0,0,
+0,170,160,0,1815,0,0,0,0,0,866,0,0,0,0,0,0,0,0,0,689,0,0,0,0,820,0,498,108,0,0,
+0,1119,0,0,0,244,609,1005,0,581,0,0,0,0,0,895,0,0,0,1898,0,0,0,0,0,926,0,0,0,0,
+0,0,0,0,0,0,0,0,0,538,496,294,301,0,0,0,18,0,0,757,0,0,0,0,0,1263,0,820,0,722,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2028,0,0,0,0,124,1875,0,0,0,881,0,0,0,1348,
+0,0,0,0,0,0,0,911,0,954,0,0,0,0,414,0,0,0,0,517,0,0,0,0,0,816,0,0,0,0,0,0,0,0,
+713,0,0,0,0,0,0,0,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,593,150,0,0,0,0,
+0,553,0,0,0,0,0,0,0,0,0,0,108,0,0,0,0,420,0,0,0,0,0,0,0,0,0,0,0,1777,0,0,55,493,
+0,0,81,0,321,980,0,0,0,0,0,0,0,0,0,0,0,0,0,0,362,112,0,74,0,0,0,0,0,0,0,625,0,0,
+0,0,0,0,377,16,0,0,61,281,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,1031,0,0,0,0,0,0,51,0,
+0,0,0,0,0,0,211,309,15,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,789,173,0,439,9,648,
+0,0,294,0,0,0,0,0,0,0,374,8,0,1099,0,0,0,0,0,0,0,575,0,0,0,518,0,0,0,702,0,0,0,
+0,0,0,87,0,0,0,438,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,464,122,0,0,0,1802,0,0,0,0,
+0,0,499,0,0,0,87,476,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,840,283,0,0,0,0,1620,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,609,1160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,600,
+323,372,0,0,0,0,471,722,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,
+477,1304,0,1774,0,0,88,0,438,12,0,0,0,0,0,0,0,0,671,997,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,639,22,0,0,782,681,0,0,0,0,0,0,0,0,0,0,1013,664,0,942,0,1349,0,0,0,0,0,0,0,
+0,0,0,0,0,356,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,215,289,0,1975,
+109,450,0,0,0,0,0,0,0,0,0,0,705,0,0,664,0,0,0,0,0,0,0,1238,0,0,318,0,0,0,0,0,0,
+0,0,0,0,0,0,0,960,1872,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,0,0,0,0,0,0,0,0,0,239,
+777,0,26,0,0,0,0,0,0,0,0,0,0,0,0,375,414,0,17,0,0,0,1350,0,955,0,0,0,0,0,0,0,0,
+887,960,0,0,0,0,0,0,0,0,0,0,708,710,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,919,0,0,0,
+0,502,280,7,45,0,0,0,0,777,0,0,0,0,410,0,1110,0,0,0,0,0,0,414,341,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,787,0,0,0,436,0,0,0,0,0,0,0,1707,613,377,96,0,0,0,0,451,
+0,0,0,0,0,0,0,0,0,0,0,0,0,680,0,483,916,0,0,0,0,0,0,937,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,739,0,0,0,0,0,0,0,0,82,0,0,663,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,128,0,0,0,0,0,0,0,0,1087,0,0,0,0,0,0,0,503,0,0,0,0,0,0,9,113,104,324,0,460,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,935,702,434,485,1014,949,423,0,900,
+0,0,0,0,0,0,0,2018,574,0,0,0,0,0,0,0,0,0,0,0,0,1206,0,0,0,0,0,0,0,0,38,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1022,0,0,0,0,143,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,2029,0,0,0,0,0,0,0,0,0,0,0,0,523,0,0,0,0,0,0,625,0,0,425,37,0,0,0,1943,0,0,0,
+0,0,765,0,0,0,0,0,0,0,0,0,0,551,0,0,0,0,0,0,0,0,0,0,0,0,168,0,0,1010,0,0,1994,0,
+0,0,91,0,0,0,0,532,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1884,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,240,15,0,0,0,1227,0,1534,0,0,0,0,0,0,0,0,0,0,0,0,0,0,392,0,
+0,0,0,0,0,0,0,0,0,0,0,655,562,395,0,0,0,501,1019,0,0,0,0,509,267,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1099,0,0,0,0,0,0,948,0,0,0,0,0,0,0,
+462,114,0,0,258,404,0,1717,0,0,0,0,82,1061,0,724,0,0,0,0,0,1133,0,0,0,0,0,0,
+1021,841,0,1021,0,0,0,0,0,0,0,0,0,0,488,373,37,0,0,0,0,564,0,0,0,0,0,513,0,0,0,
+825,0,0,899,0,0,778,0,0,12,1417,0,1116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,114,545,0,5,
+0,0,0,0,0,0,0,192,0,0,763,0,0,0,0,0,0,0,755,759,0,0,0,0,0,0,0,0,0,370,0,1237,0,
+0,0,0,0,0,298,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,0,0,
+0,0,0,0,814,991,0,757,57,0,0,0,0,0,0,0,0,0,540,0,0,0,0,608,0,0,0,0,0,0,0,0,1014,
+0,0,0,902,0,0,0,0,553,1668,0,0,0,0,0,0,0,0,0,559,60,0,0,0,0,0,511,0,0,675,0,0,
+156,0,0,0,0,0,0,709,0,698,0,0,0,1745,0,0,0,0,0,0,0,0,0,714,0,0,0,0,0,0,0,0,206,
+8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,776,0,0,0,0,0,0,0,0,0,1272,0,0,
+0,0,0,1059,0,0,0,0,0,0,406,0,0,0,0,0,0,0,0,0,0,947,0,0,0,0,0,0,168,0,0,0,0,0,0,
+870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,554,0,0,0,0,784,908,0,0,0,0,0,0,
+0,396,358,0,0,0,0,0,0,0,0,2,228,0,0,0,0,0,0,0,0,0,0,0,845,14,0,716,1820,594,0,
+81,1428,0,161,0,782,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,998,0,
+0,0,0,0,0,0,0,0,0,0,0,1043,0,1496,0,0,0,0,0,0,0,0,781,0,0,0,0,0,0,0,817,1114,0,
+1814,958,0,0,0,0,812,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,139,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,236,643,0,0,0,0,0,0,0,0,0,1172,0,0,0,0,0,0,0,0,0,1338,0,0,0,
+0,0,0,0,0,0,0,0,54,0,0,0,256,0,0,351,0,955,1885,0,469,0,0,0,1270,0,744,0,313,0,
+0,0,0,0,0,0,0,402,969,0,0,0,0,0,0,50,0,0,0,0,572,0,0,0,0,847,0,0,0,0,0,0,0,248,
+43,0,369,0,0,0,0,0,0,0,0,0,0,0,0,0,766,0,363,0,0,0,0,0,0,0,0,0,0,0,678,0,0,409,
+258,82,249,0,0,0,0,0,0,0,0,0,0,0,0,32,393,0,788,0,0,0,1281,509,1968,0,0,0,0,39,
+291,0,0,0,589,0,0,54,1059,0,0,0,0,0,0,824,0,0,0,0,0,0,0,0,0,0,1005,0,1598,0,0,0,
+0,0,919,0,0,0,0,0,0,0,0,52,132,0,0,0,0,0,328,0,0,0,0,173,0,0,0,0,0,65,1411,0,0,
+0,0,0,0,0,0,0,0,442,0,842,0,0,0,0,0,0,0,0,0,534,0,0,0,0,0,0,0,0,0,0,0,0,0,845,
+210,0,0,0,0,0,0,0,0,892,0,0,223,0,0,0,0,529,0,0,0,807,0,137,218,0,1444,0,0,0,0,
+0,332,661,0,0,0,0,0,0,0,76,1517,0,0,0,0,0,0,0,0,0,0,0,418,0,0,0,0,0,0,0,0,481,
+379,0,0,0,0,0,149,18,0,0,0,0,0,0,0,0,742,304,142,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,799,925,195,51,0,0,0,0,688,0,0,0,0,697,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1169,751,0,0,0,452,929,0,221,0,1437,0,0,0,0,955,1251,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,0,132,0,0,0,0,0,865,0,0,0,0,0,0,0,767,
+672,42,0,0,0,1050,0,0,0,0,0,0,0,0,368,44,0,0,0,0,0,0,0,570,29,0,0,0,0,0,0,227,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,522,0,0,0,0,0,0,0,1529,0,0,0,0,0,0,739,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1667,0,0,0,0,0,0,132,511,0,138,208,1020,0,0,23,565,0,344,0,0,0,
+0,0,922,0,0,0,0,0,0,0,240,0,0,415,171,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,402,0,0,754,31,716,0,982,731,0,0,0,0,0,0,0,888,0,0,0,803,847,0,0,823,
+0,0,0,0,0,0,785,0,0,2,0,0,0,0,0,0,0,532,0,0,681,0,0,314,0,384,684,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,649,447,0,1818,1007,0,321,0,66,360,0,0,0,385,0,0,0,0,0,0,
+0,900,73,254,0,0,0,0,683,1959,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,86,0,0,725,0,0,0,0,0,196,0,0,0,0,0,831,0,0,0,0,723,0,0,0,0,0,994,627,0,0,
+0,0,0,0,0,0,0,0,764,66,0,0,0,0,205,36,0,0,0,0,0,0,0,950,0,0,0,887,111,0,0,831,
+388,165,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,780,755,0,0,0,0,898,146,0,0,0,
+0,0,0,0,45,7,0,0,0,0,0,0,0,0,607,0,0,0,0,0,0,65,0,0,0,0,0,0,0,0,0,88,0,0,0,0,0,
+621,600,0,367,0,0,0,0,0,0,0,561,0,559,0,585,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+287,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,672,157,0,0,0,0,714,0,0,0,
+0,0,456,0,925,0,0,0,0,0,0,0,0,19,0,0,0,0,1473,0,0,0,0,0,0,0,0,0,0,113,0,0,0,0,0,
+0,0,0,0,0,0,0,0,69,463,0,0,82,193,2,471,0,0,0,0,633,0,0,0,0,0,0,1148,129,1392,
+542,803,0,0,0,0,0,0,0,0,0,0,0,0,438,0,0,0,0,0,0,875,0,0,0,0,0,237,0,0,0,0,0,0,0,
+65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,563,0,0,0,9,444,0,0,43,1260,0,0,0,0,0,0,
+971,0,0,699,0,0,0,0,0,1116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,829,242,0,
+0,593,0,0,0,0,0,0,0,0,201,36,224,0,0,0,0,0,0,1430,0,1806,0,523,0,0,212,1889,0,0,
+0,827,0,0,0,0,0,2043,136,242,0,0,0,0,0,0,284,148,10,0,0,0,0,0,0,1249,0,0,0,807,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,94,0,0,0,494,0,0,0,0,0,0,0,0,1510,0,0,0,0,0,
+0,0,0,0,0,505,1306,0,0,764,268,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,384,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1703,0,0,0,0,159,964,583,0,0,0,
+0,0,0,515,0,0,854,0,0,0,0,0,0,0,0,0,0,0,0,1123,0,0,0,0,0,0,0,136,0,0,0,0,0,1782,
+0,0,44,1287,0,0,0,0,0,732,0,0,0,0,313,679,0,0,316,0,0,0,0,595,0,0,0,0,0,0,753,
+147,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,137,0,0,0,0,414,0,1762,0,0,0,0,0,0,0,0,
+0,0,0,599,0,0,0,0,0,0,0,0,0,1749,0,0,0,1627,0,488,0,0,0,0,0,83,0,0,0,0,676,0,0,
+1639,0,0,0,0,0,0,0,0,0,278,0,0,0,0,0,0,97,0,14,1085,0,0,0,0,0,0,781,388,0,849,
+59,229,0,0,0,0,0,1115,0,0,0,0,108,0,0,0,0,700,0,0,0,0,0,0,0,0,0,1414,0,0,0,0,0,
+0,0,0,0,0,0,0,0,660,737,1035,0,0,0,0,0,0,521,690,0,0,0,0,0,0,0,0,0,0,0,0,272,0,
+0,0,0,0,0,0,0,0,0,1744,0,0,0,0,0,0,128,733,0,0,277,0,0,0,0,0,0,0,0,0,4,0,0,0,0,
+0,0,0,0,0,0,0,0,0,936,1981,40,0,0,0,0,0,0,0,0,775,0,0,0,0,0,0,0,0,0,306,0,0,0,0,
+0,0,0,979,0,0,0,0,0,611,0,0,0,0,0,178,0,0,0,1969,0,0,0,0,0,0,0,664,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,390,0,0,0,1510,0,0,0,0,0,0,0,0,0,0,0,493,0,0,37,0,0,0,0,724,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,1537,0,0,168,473,0,0,0,105,0,0,0,0,
+627,438,0,0,0,0,0,0,0,0,0,0,11,1256,0,0,0,1626,0,779,0,0,0,0,25,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,308,0,0,0,0,0,741,0,671,0,0,0,0,649,150,0,0,99,521,0,0,3,339,0,0,0,
+543,0,0,0,0,0,0,0,0,0,1358,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,234,155,
+0,0,0,0,0,0,0,1628,0,766,0,0,0,0,0,0,0,0,0,0,0,0,0,829,0,0,0,1445,0,0,0,486,0,0,
+0,0,2,1635,0,0,0,0,558,0,0,0,0,0,0,0,0,0,0,1461,0,0,0,0,0,599,0,0,0,0,0,0,0,0,0,
+1376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,93,0,0,0,0,0,0,447,0,0,66,1432,0,0,0,0,
+0,0,307,0,413,609,0,0,0,930,0,0,0,0,21,939,0,0,0,0,0,962,4,651,0,0,0,0,15,579,0,
+0,0,0,0,597,0,0,0,0,0,981,0,0,0,545,0,0,0,0,0,0,0,1558,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,800,17,0,0,17,0,907,0,0,0,110,0,0,0,53,458,0,1983,0,0,0,0,0,0,0,0,0,0,443,0,
+0,0,0,0,0,0,0,0,0,0,924,1844,0,1232,0,0,0,0,70,519,0,993,0,0,0,0,0,0,14,530,0,
+907,0,0,0,0,0,733,0,0,0,0,0,0,0,0,55,0,188,531,56,0,0,1693,0,0,0,0,0,0,0,0,441,
+0,192,928,0,0,0,0,0,241,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1525,0,259,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,512,185,0,464,1603,0,0,0,0,0,0,0,0,0,0,0,1113,
+284,720,0,0,722,0,0,0,0,0,13,0,0,0,0,0,0,0,4,289,43,0,0,0,0,0,0,1694,0,0,0,0,
+193,0,0,0,0,409,0,0,0,0,0,0,0,0,0,0,0,0,308,0,0,1863,0,0,0,0,0,0,0,0,0,790,0,0,
+745,1002,0,0,0,0,0,0,0,0,0,289,68,477,13,0,0,0,0,0,0,0,0,0,0,609,0,0,0,0,0,0,0,
+0,0,0,0,367,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,528,0,0,0,0,0,0,0,0,0,694,58,
+548,0,0,0,0,0,0,687,0,0,0,0,1749,0,0,0,0,0,0,0,0,1004,661,0,0,0,0,0,0,445,0,0,0,
+74,0,0,0,0,213,0,0,0,0,0,0,0,0,0,0,0,0,0,834,0,0,189,1672,0,0,0,0,0,0,0,1548,
+192,0,0,0,0,0,0,0,0,0,0,0,0,0,32,751,0,78,0,0,0,0,0,0,544,1602,105,473,0,0,0,0,
+0,0,156,1949,0,1779,0,0,0,0,0,0,0,0,0,0,0,763,0,0,0,0,0,0,0,0,29,0,0,0,0,0,0,0,
+0,0,0,883,0,0,0,0,0,0,0,488,0,617,0,0,50,0,694,1518,785,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,546,0,0,0,0,0,0,0,0,0,0,22,0,0,0,0,1016,0,0,0,577,0,0,0,0,0,0,
+184,935,114,720,0,0,100,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,95,14,0,969,0,0,0,0,0,0,0,
+727,0,1021,0,0,0,0,0,1190,0,0,0,0,0,0,0,0,0,0,0,0,0,153,0,0,0,0,0,0,0,0,0,798,0,
+587,0,0,695,42,0,1929,141,957,0,465,7,908,0,0,450,148,0,0,0,1166,0,0,0,0,0,0,0,
+0,0,0,0,0,253,0,1003,0,0,0,0,0,0,0,0,0,0,0,46,0,0,879,0,806,0,1868,0,0,0,0,0,
+1846,0,0,0,730,0,0,0,0,0,0,0,965,0,0,0,0,506,0,0,0,10,0,0,0,22,0,0,0,0,0,0,0,0,
+0,0,0,0,0,960,296,0,0,0,0,0,0,0,0,0,0,0,587,0,0,0,0,20,0,0,0,32,982,0,0,0,0,0,0,
+0,0,0,0,941,0,0,0,0,435,0,0,0,0,0,0,71,419,0,0,0,0,0,0,688,740,94,345,0,0,679,
+582,0,0,0,0,0,0,0,945,0,0,0,0,0,0,0,0,0,0,0,0,539,0,684,1993,0,0,0,659,0,583,0,
+803,0,704,0,0,0,0,0,198,181,347,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,481,405,203,0,0,99,826,0,0,0,0,0,0,0,492,0,408,0,0,0,0,0,0,0,0,0,0,4,0,0,
+0,0,665,349,137,0,0,0,0,612,1270,0,0,0,0,0,371,0,0,0,826,0,0,0,0,21,1535,858,
+374,0,0,0,0,0,0,311,0,0,0,991,1968,0,0,0,0,494,1647,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,769,0,0,0,0,0,642,0,0,157,123,0,0,0,1435,0,0,0,0,0,0,0,0,0,0,79,0,0,0,
+0,0,0,1425,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,106,393,486,1690,0,0,0,0,
+0,0,0,0,0,0,0,0,756,184,0,0,0,1382,0,0,0,175,0,1493,0,1007,0,0,0,0,0,0,0,0,0,0,
+0,219,0,0,0,0,515,99,0,851,0,0,0,0,0,1278,0,0,0,0,0,0,0,1000,982,0,762,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,910,1819,0,0,0,0,0,0,906,0,0,0,0,0,0,0,0,0,0,1730,0,0,
+0,0,0,0,0,0,0,0,0,1185,0,0,0,0,0,0,0,0,40,0,0,0,147,0,0,0,0,0,0,0,0,0,0,0,0,0,
+650,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,30,0,553,0,0,20,597,0,1614,0,0,0,0,0,327,
+49,0,0,0,0,0,0,0,78,0,0,786,134,0,0,0,12,496,0,0,0,0,0,0,0,0,0,0,42,204,0,614,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,147,247,0,0,0,0,942,0,0,2023,0,0,0,0,
+0,0,67,285,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1309,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,532,0,0,0,0,0,0,0,
+1692,0,0,0,0,55,1704,0,0,0,0,988,0,0,0,223,0,0,0,0,0,0,0,57,1123,0,0,0,0,0,1764,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2015,0,0,0,1599,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,534,0,0,0,0,0,0,0,0,0,0,0,
+0,0,504,621,1248,321,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1397,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,441,75,0,0,0,0,0,0,0,0,0,0,841,0,0,0,0,0,693,0,650,314,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,913,0,0,0,0,0,0,0,0,0,0,0,0,0,0,880,0,475,0,
+0,1016,179,602,111,329,0,0,0,1864,0,0,0,0,846,1888,0,0,780,0,0,0,82,0,0,0,0,821,
+0,0,0,0,0,0,0,0,0,0,0,956,112,0,0,0,261,455,0,0,0,0,0,0,337,385,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,184,1865,0,0,721,16,0,486,0,0,0,265,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,621,0,0,0,0,0,0,0,0,234,0,0,815,0,0,743,
+1987,205,197,0,0,0,0,0,0,0,0,0,314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,219,452,589,0,
+176,333,0,0,0,0,0,0,0,1110,47,0,0,0,0,0,0,0,0,0,0,0,864,0,0,300,0,1237,0,0,0,0,
+0,0,0,0,0,0,0,1685,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,135,395,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,631,0,0,0,0,0,0,835,0,0,0,606,459,0,979,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,612,0,0,0,0,0,0,0,0,158,372,0,854,0,0,0,0,0,
+0,0,1492,0,0,0,833,0,0,0,0,0,0,0,1739,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+195,0,0,0,0,0,0,0,0,730,1997,0,0,0,0,0,0,0,0,61,0,0,0,0,0,0,0,266,751,0,0,0,0,0,
+0,0,821,0,0,0,715,0,0,0,868,0,959,0,0,0,0,0,0,0,0,0,0,0,1053,0,0,0,950,0,1081,0,
+1595,0,0,0,0,59,0,0,0,0,0,0,0,0,0,0,47,684,0,0,0,0,0,0,1606,0,777,0,1020,0,0,0,
+1094,0,0,0,0,0,0,0,350,0,0,0,0,0,0,242,1812,0,0,0,967,0,0,0,473,286,0,0,0,0,0,0,
+798,629,222,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,513,337,306,0,0,0,0,0,0,0,0,0,
+146,0,0,1646,0,0,0,0,0,465,0,0,0,525,0,0,0,0,0,0,299,165,0,0,0,0,0,0,0,1064,0,0,
+0,0,0,596,0,0,0,0,0,0,0,0,0,0,0,0,0,0,238,1741,0,1233,451,1824,0,0,0,0,733,495,
+0,0,0,0,0,1204,0,0,0,559,341,0,224,21,0,0,0,0,0,0,0,0,97,1446,0,0,0,0,0,0,0,729,
+0,0,565,727,0,1948,0,0,0,519,0,0,0,0,0,0,0,0,0,1193,0,0,0,0,0,0,790,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,323,2,201,0,0,59,0,0,34,0,896,961,0,1285,0,0,46,0,479,0,0,
+0,0,549,0,663,0,0,0,0,0,783,65,682,0,0,0,0,0,11,0,0,0,0,0,522,0,0,0,52,0,0,0,0,
+0,383,0,0,0,0,0,0,0,0,127,0,0,0,0,0,397,194,0,0,635,0,0,0,0,0,0,0,0,0,0,975,0,0,
+0,0,0,0,0,0,0,0,116,0,51,0,0,858,0,1075,535,448,0,0,0,0,0,610,0,0,0,0,0,0,0,0,0,
+0,191,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,267,673,319,94,92,0,551,0,0,218,
+1406,69,256,0,0,952,1980,0,833,0,0,0,0,0,0,0,0,0,0,0,0,39,0,0,0,0,0,0,0,81,0,0,
+0,352,634,0,0,0,0,0,618,0,0,0,0,0,0,73,339,0,0,0,0,0,0,0,0,0,0,0,0,0,0,169,759,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1075,0,0,0,0,0,0,482,649,0,0,0,0,0,0,0,0,386,336,0,0,
+0,1035,0,0,0,0,0,0,0,0,0,0,0,924,0,73,0,0,0,0,0,1971,0,0,0,0,0,0,0,0,0,1344,0,
+501,0,0,0,0,0,0,0,0,46,799,0,0,0,0,0,0,0,276,0,0,0,0,0,0,0,770,0,0,0,0,0,0,0,0,
+0,0,0,0,0,158,0,0,0,0,0,1432,0,0,0,0,0,0,0,0,0,0,25,0,0,2001,0,0,0,0,0,0,0,0,0,
+0,0,0,0,478,0,0,0,0,0,0,91,1461,211,602,0,0,0,0,0,0,0,0,0,1068,0,0,124,567,0,0,
+0,1006,0,0,0,0,0,0,0,0,0,735,812,0,0,323,0,0,0,304,0,0,0,0,0,0,0,0,0,148,0,0,0,
+0,0,0,0,0,0,523,0,0,144,730,0,0,981,0,0,111,0,0,132,0,0,0,0,0,0,890,0,0,0,0,0,
+444,0,1787,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,2041,932,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,937,0,995,0,0,255,0,0,138,863,965,0,0,631,0,0,0,0,1394,16,652,0,0,0,0,0,0,
+0,0,0,0,0,0,0,897,0,321,0,0,0,0,0,922,0,619,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,844,0,0,0,0,0,0,1659,0,1100,0,0,0,1173,0,1930,268,251,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,390,711,0,0,0,0,0,0,0,0,0,0,0,0,0,744,0,0,0,0,0,0,0,0,0,624,0,0,0,
+1998,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1125,0,0,0,594,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,268,0,0,0,0,0,0,0,563,0,0,0,0,0,0,0,0,2,39,0,0,0,1332,0,0,0,0,0,
+0,0,508,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66,796,0,0,0,0,527,0,0,0,0,98,0,0,576,0,
+0,0,0,0,122,0,276,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,645,0,0,0,0,
+0,0,0,0,0,0,0,290,0,0,762,1292,0,0,0,1315,0,1955,0,0,0,0,0,0,0,0,0,0,210,131,0,
+0,0,0,797,0,38,0,11,488,0,936,0,441,0,0,0,0,0,595,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+991,0,0,0,0,0,0,0,0,0,0,0,653,0,523,0,0,0,903,0,0,0,0,0,0,0,0,0,0,0,0,80,0,0,0,
+0,0,0,0,0,0,432,0,0,314,0,0,0,0,232,1368,534,0,0,0,0,0,27,0,0,0,12,0,0,0,0,0,0,
+0,0,0,264,736,0,1657,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1117,0,127,0,0,0,1208,0,1294,
+0,0,0,0,364,0,0,0,0,0,125,1334,0,0,0,0,0,0,0,0,0,0,0,0,0,0,792,0,0,0,0,0,0,0,
+849,699,0,0,0,0,0,968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1446,
+124,397,0,0,0,0,0,0,0,0,0,0,0,641,0,0,0,0,0,0,0,0,0,0,0,0,127,346,0,0,517,75,0,
+0,0,0,0,0,0,0,83,0,0,0,0,0,0,1031,0,0,0,0,0,0,0,1470,0,954,0,0,345,304,410,0,0,
+0,0,734,0,0,0,0,0,1822,0,0,0,1798,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,161,
+1865,69,0,0,0,0,0,0,922,0,0,0,0,0,0,0,0,0,0,0,541,0,627,0,0,0,0,0,0,0,0,0,166,0,
+0,0,0,0,0,0,0,0,849,0,0,0,0,0,0,0,717,0,0,0,0,0,0,0,0,0,0,0,0,0,0,600,0,0,0,0,0,
+0,654,0,0,188,273,0,0,0,543,0,410,87,0,0,941,0,0,186,250,0,1785,0,0,0,0,0,1339,
+462,961,0,780,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,529,0,0,0,0,0,0,474,1276,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,24,948,0,0,0,0,657,753,0,0,0,0,941,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,706,985,837,0,1861,0,0,0,0,0,0,0,0,0,0,0,0,0,0,292,933,0,0,0,0,0,
+0,0,0,0,767,0,0,0,0,0,0,0,641,0,0,0,1233,114,0,883,0,274,2008,0,1794,285,0,0,
+571,0,0,0,0,0,0,0,0,0,0,823,960,16,617,0,431,0,0,0,0,0,0,0,0,0,0,567,0,401,0,2,
+781,424,33,0,2006,0,0,274,0,0,1882,0,794,0,0,0,1848,0,0,0,0,0,0,448,47,0,0,0,
+1199,0,0,0,0,0,0,0,0,417,0,0,0,0,0,0,0,0,0,0,295,0,0,0,0,0,0,0,1019,0,0,0,0,0,0,
+0,0,0,0,0,0,0,620,0,0,0,0,464,0,0,0,0,208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,442,0,930,0,0,0,0,0,516,68,0,0,0,0,0,1128,104,0,0,0,0,0,0,0,0,787,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,491,0,0,0,0,0,0,711,0,0,9,0,101,441,0,0,0,0,0,0,0,0,
+0,0,160,396,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,679,326,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,1128,0,0,0,0,0,737,0,1796,0,0,0,0,0,0,0,0,0,0,0,0,338,574,0,0,
+0,0,0,1096,491,405,0,0,0,0,0,1081,0,0,0,0,0,0,0,0,0,0,0,0,0,1676,0,1207,0,0,0,0,
+0,0,969,354,0,0,0,0,598,0,297,0,0,0,0,0,0,0,0,1772,751,0,37,0,0,1828,0,0,0,0,0,
+0,0,0,0,257,191,582,0,0,0,0,0,0,790,0,0,0,0,0,47,0,0,0,0,0,0,0,449,306,1011,0,0,
+0,0,0,299,0,0,0,0,0,0,837,0,0,0,0,0,0,10,329,0,0,0,0,0,1320,0,0,0,0,0,0,158,657,
+0,1191,0,0,0,0,0,0,7,0,974,1939,0,1665,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,288,
+66,0,0,0,0,494,175,0,1643,0,0,0,0,0,0,0,0,570,750,719,0,0,0,0,0,0,0,0,0,0,0,0,0,
+13,0,0,1247,0,0,221,356,0,0,0,0,0,0,0,0,0,0,694,1809,0,0,0,0,0,0,0,411,0,44,31,
+0,0,0,0,669,0,673,0,0,0,0,0,0,0,0,0,1303,704,299,0,0,0,275,0,0,216,1761,0,0,0,0,
+0,0,0,0,0,0,0,1319,0,0,428,0,0,0,0,0,0,0,0,0,0,514,0,0,0,0,0,0,49,55,102,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,364,0,0,0,0,379,0,921,971,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1258,0,0,0,1058,0,0,0,0,0,656,0,0,0,0,0,144,0,0,0,0,0,0,0,0,0,0,
+0,1373,10,605,0,0,0,0,0,0,0,838,0,1012,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154,365,0,0,
+0,0,0,0,0,0,0,340,0,0,0,0,0,810,0,0,0,0,0,0,495,0,0,0,0,0,0,0,0,0,261,0,535,248,
+0,358,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,567,445,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,697,0,0,0,1336,0,0,0,0,0,0,0,0,917,174,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,972,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,351,0,0,0,0,0,0,0,0,0,0,
+0,0,0,286,0,0,56,438,0,0,0,0,0,1950,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,738,0,0,0,0,0,
+0,0,0,0,0,969,2047,0,0,0,0,0,0,0,818,0,0,0,0,0,0,0,866,0,0,0,0,0,0,0,1467,0,0,0,
+0,0,0,0,0,0,0,0,0,0,972,0,355,0,0,0,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,267,189,104,0,0,0,0,1613,0,0,0,0,0,0,0,116,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,886,0,86,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45,0,0,863,0,0,0,0,0,
+0,0,1953,450,1773,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,381,0,0,0,0,0,0,0,
+0,0,0,0,0,1142,0,1189,0,0,0,663,0,0,0,0,0,0,0,846,0,0,528,0,393,378,0,0,0,0,0,0,
+325,899,680,1880,0,1770,0,0,0,0,0,648,0,0,0,0,0,0,185,167,0,2046,0,0,0,0,0,0,
+249,1645,0,152,0,0,0,1733,0,0,0,0,0,1006,0,0,0,0,0,420,0,0,0,832,0,0,0,0,0,351,
+0,0,0,0,6,40,0,0,60,0,0,0,0,1354,745,724,0,0,0,0,0,0,0,0,772,1951,275,108,639,0,
+0,0,0,0,0,0,0,0,500,1758,0,0,0,0,0,0,0,0,0,0,0,1886,711,205,0,0,965,865,0,0,0,
+534,0,0,0,0,691,0,0,0,237,443,0,878,0,0,0,0,0,1410,0,0,0,0,0,0,0,0,0,0,0,0,0,
+995,0,0,0,0,0,0,0,0,0,0,0,0,0,578,0,0,0,0,881,0,0,0,0,0,0,0,0,822,0,923,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,924,0,0,0,665,0,0,0,0,0,1901,0,0,0,0,0,950,498,93,
+0,0,0,1451,0,0,0,0,0,747,828,788,400,184,0,198,0,0,0,0,0,0,0,0,0,0,0,994,0,0,0,
+0,0,0,0,0,615,320,0,0,0,978,843,905,0,0,0,0,0,0,0,0,850,974,0,0,0,0,6,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,509,0,0,0,0,0,273,0,0,0,0,0,0,0,0,0,0,0,0,0,
+201,0,0,0,1041,0,0,0,1040,0,0,0,0,0,0,0,0,0,693,234,774,0,336,0,1399,22,0,805,
+802,777,167,789,0,0,1705,0,0,0,0,0,0,0,0,0,0,0,10,13,11,0,0,204,264,0,0,56,0,0,
+1917,0,470,0,0,0,0,0,0,0,0,0,0,0,1198,0,0,0,0,0,0,0,0,0,0,1015,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,715,0,0,1002,0,0,0,298,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,867,0,0,724,0,0,0,0,0,0,0,0,0,0,0,0,768,0,0,0,0,0,1066,0,0,0,0,67,0,174,948,
+0,0,0,0,0,0,0,0,0,0,0,0,0,764,0,0,0,0,75,137,0,756,0,0,0,0,0,0,1008,842,643,0,0,
+0,67,0,0,0,0,0,0,0,0,0,0,0,135,821,0,0,0,0,0,0,0,0,736,0,389,355,0,0,786,0,0,0,
+0,0,0,2044,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1030,0,0,0,1083,0,0,0,0,0,
+1226,0,0,0,0,356,319,8,389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,474,0,0,0,427,
+0,413,0,730,0,0,0,0,0,373,0,0,0,0,0,0,0,0,0,799,0,0,0,1793,0,0,0,322,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,290,2,0,0,0,0,0,0,0,0,0,0,672,
+699,1860,0,0,0,737,0,0,0,1612,0,0,0,0,0,0,0,0,0,0,0,145,124,884,0,0,0,0,0,387,0,
+0,0,0,0,0,0,0,0,0,0,679,0,550,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1305,0,0,0,0,0,0,0,
+576,0,0,0,0,0,0,0,686,0,607,0,0,37,0,0,0,0,0,0,0,0,0,101,1726,0,0,0,0,0,958,0,0,
+0,903,0,0,0,0,147,0,0,0,0,0,0,0,0,0,0,0,367,0,0,0,0,690,0,705,273,0,0,887,0,0,0,
+0,0,0,0,0,0,0,0,90,0,0,0,0,0,0,0,908,0,0,0,0,0,0,0,1261,0,0,497,1235,0,429,0,0,
+0,0,904,0,12,125,0,0,0,841,0,0,0,0,0,860,946,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,768,0,770,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,271,0,0,0,0,0,0,0,719,0,699,581,0,0,0,0,0,0,0,0,0,0,862,304,0,631,0,0,0,0,880,
+1513,0,0,0,0,0,981,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,434,0,0,0,0,0,550,0,0,476,930,
+824,553,0,0,452,0,151,0,0,0,0,0,0,772,0,292,135,0,0,0,0,0,0,0,504,0,0,1089,0,0,
+0,0,0,0,0,0,0,0,0,783,0,0,0,0,0,0,206,393,0,0,0,0,0,0,0,0,232,912,0,0,0,0,0,977,
+0,0,716,98,0,0,0,0,0,733,0,0,0,0,0,0,0,0,19,0,0,0,0,668,0,360,0,0,0,0,0,0,656,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,726,0,0,0,0,0,0,0,0,0,0,0,0,72,0,0,1269,0,0,463,0,
+0,0,0,0,0,1454,0,1287,245,0,989,0,0,0,0,0,0,0,0,0,107,164,0,0,0,0,0,0,0,1061,0,
+0,0,0,2,484,0,0,0,0,0,0,0,1127,0,0,0,0,0,0,0,460,0,0,0,0,0,932,0,0,0,0,0,0,0,
+588,625,0,0,0,0,76,92,0,0,0,0,0,0,0,0,0,0,0,0,0,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+763,0,622,0,0,0,253,0,546,0,0,110,0,256,916,0,0,35,212,0,0,746,0,0,0,150,0,0,
+1466,0,0,0,1299,0,0,0,0,0,0,0,0,0,1518,0,0,0,0,0,0,0,0,0,0,0,0,0,1229,0,0,0,816,
+0,0,0,0,0,0,159,0,0,0,0,0,734,869,126,1716,0,0,0,0,0,0,202,232,0,0,0,0,212,0,0,
+0,0,0,111,1003,0,0,0,0,0,0,0,0,0,0,0,1712,0,0,216,0,0,0,0,516,0,0,0,0,0,650,0,0,
+0,0,57,99,0,0,0,0,300,574,0,0,0,0,1023,0,0,302,0,1871,0,728,252,0,0,461,0,0,0,
+323,0,0,0,0,0,0,775,461,0,0,0,0,0,0,172,0,0,464,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,73,727,0,1023,0,0,0,0,0,0,0,0,0,0,577,0,0,0,0,0,0,0,0,1037,0,0,0,0,0,0,
+0,0,280,677,0,0,0,0,0,0,0,0,0,0,0,799,0,0,0,0,159,0,446,1730,0,0,0,0,0,0,0,0,0,
+395,0,0,0,0,145,0,0,0,0,0,0,0,20,0,0,426,608,0,0,0,0,0,977,0,250,0,0,0,0,0,100,
+0,0,0,0,1982,0,0,0,0,0,476,0,0,0,0,0,0,594,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,447,0,0,0,0,526,0,0,14,1124,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,188,0,0,0,0,0,0,0,0,362,301,0,0,0,1743,0,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,872,0,831,0,0,208,202,0,0,0,0,0,0,0,1954,0,
+0,0,0,516,872,0,0,313,224,0,0,24,0,11,546,0,0,0,1937,242,241,46,0,0,0,830,1273,
+0,0,0,0,0,0,0,825,327,1006,0,0,0,0,0,1580,516,366,0,0,0,0,0,1736,0,0,0,0,0,0,0,
+0,0,0,0,1935,0,826,0,0,0,0,139,331,0,0,0,0,0,0,0,0,0,0,0,288,0,916,0,0,0,0,0,
+1888,0,0,0,0,0,0,0,1471,0,1570,0,394,0,0,0,0,0,0,0,1931,0,1719,0,658,228,0,0,0,
+0,0,374,0,0,0,0,735,0,0,0,0,0,0,323,498,0,1063,0,0,0,0,155,0,0,0,0,0,0,0,0,906,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1139,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,616,
+902,0,0,0,0,0,692,0,0,0,0,0,0,823,0,0,0,305,0,0,0,0,0,0,0,681,0,0,0,0,0,214,
+1004,0,0,0,0,0,0,0,23,0,0,1703,0,0,0,0,0,0,0,0,0,1443,0,0,19,714,0,0,0,0,64,737,
+0,0,345,1758,0,0,579,47,0,0,539,139,0,0,0,0,388,0,0,0,0,253,0,0,0,0,0,0,252,0,
+745,0,0,0,0,0,0,0,0,0,0,0,504,107,0,871,0,0,0,229,0,0,0,0,0,903,0,0,71,0,0,549,
+6,47,0,0,0,0,0,0,0,0,0,980,865,705,0,0,0,161,0,0,0,0,143,1331,0,0,0,1388,33,724,
+0,0,0,19,0,0,0,395,0,0,0,0,0,846,210,0,0,0,122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,695,937,497,0,0,0,0,0,718,0,0,0,0,0,0,0,1581,0,
+0,0,0,0,0,161,49,0,0,0,0,0,0,0,0,0,597,0,0,0,1094,0,0,0,811,908,0,0,0,0,0,0,0,0,
+0,0,1471,0,0,0,0,0,0,0,0,0,0,42,1935,0,0,0,2014,66,2007,0,0,586,0,0,0,0,0,0,0,0,
+0,28,1077,0,0,0,1221,0,0,62,0,0,0,0,0,0,0,0,0,0,1766,0,0,0,0,0,0,0,0,0,0,0,0,25,
+0,499,1388,0,0,97,10,0,0,0,0,0,481,0,0,0,0,0,0,0,0,0,0,37,134,155,486,0,1442,0,
+0,0,0,0,591,0,0,0,0,0,0,310,1173,0,0,0,0,409,1156,0,0,0,482,0,0,263,926,0,0,0,0,
+0,0,0,0,0,0,0,0,0,804,0,0,0,0,0,0,0,0,0,0,0,0,0,1265,0,415,0,348,0,0,0,1012,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,165,1803,0,0,0,0,0,0,0,408,
+0,0,0,0,0,0,257,1321,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1138,0,0,0,249,0,
+0,0,576,0,0,0,0,231,0,0,0,288,0,0,0,0,0,0,0,0,0,433,1487,569,1678,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,0,0,0,0,0,779,538,0,0,0,413,0,0,0,
+0,0,0,0,0,0,0,495,0,0,0,0,0,191,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,530,567,
+0,0,0,0,0,1484,0,0,0,0,0,0,815,609,0,0,0,0,0,484,0,0,0,0,0,0,0,0,0,0,900,0,0,0,
+0,1335,0,1724,0,0,0,0,0,0,0,0,0,0,0,640,0,0,0,0,0,0,0,0,0,0,0,1831,0,0,0,0,0,0,
+0,0,0,0,0,0,0,474,0,0,0,0,0,0,0,0,0,1103,0,1504,655,1034,0,0,0,0,0,305,0,0,0,0,
+0,0,0,0,0,1236,0,0,429,217,0,0,0,0,739,278,0,0,0,0,0,0,0,708,0,0,0,0,0,1840,233,
+0,0,0,0,0,0,0,0,2017,0,0,0,0,0,1488,0,0,0,1590,0,0,0,0,0,1800,28,0,0,0,0,0,0,0,
+0,0,45,0,36,0,22,1442,378,0,0,0,0,0,0,1507,0,0,0,0,0,0,0,0,0,0,39,0,0,1054,725,
+1955,0,2036,0,0,0,0,0,0,0,0,0,0,896,1871,0,0,0,0,0,0,0,0,0,0,805,0,0,0,0,2046,0,
+0,0,0,17,712,0,617,55,320,271,0,0,0,0,0,0,0,0,0,445,0,184,103,0,0,0,0,0,0,0,0,
+659,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,676,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+337,0,0,0,506,0,0,0,0,0,843,77,0,458,0,0,0,0,0,1420,382,109,142,330,0,0,0,0,0,0,
+0,0,0,0,0,0,87,0,0,0,492,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1239,0,0,0,0,0,0,
+211,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1049,0,321,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1985,0,0,122,0,0,234,0,0,0,1098,0,0,0,0,0,0,549,253,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,522,131,0,0,149,0,0,0,0,0,0,0,0,0,0,0,0,0,0,507,0,0,0,0,811,630,0,0,0,343,
+0,0,0,0,0,448,591,455,0,1381,0,0,0,0,0,0,0,575,0,0,0,0,0,1175,0,0,0,0,0,0,0,0,0,
+653,0,0,0,1761,0,1198,0,0,0,0,297,1127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,678,0,0,
+164,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35,0,45,0,0,0,0,0,121,0,0,0,0,0,0,
+0,0,125,0,0,0,1622,0,0,0,0,0,721,145,0,0,0,970,792,0,0,0,715,0,0,0,0,0,1999,0,0,
+74,531,0,0,65,0,0,0,105,220,0,0,0,0,0,0,0,960,0,0,0,0,0,0,428,19,0,0,401,96,0,0,
+0,0,0,1595,116,0,1021,0,0,0,0,0,750,1961,0,0,148,0,0,0,0,0,0,0,0,0,0,0,0,0,75,0,
+0,1383,0,0,0,0,0,0,0,0,0,0,0,0,0,0,779,0,0,0,0,0,0,0,0,598,0,424,0,0,0,0,0,0,0,
+1222,0,0,0,876,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,133,0,0,0,0,187,0,8,0,0,0,0,0,
+0,0,429,0,685,0,0,0,0,0,0,0,0,0,0,0,132,472,0,0,0,0,0,0,0,0,0,938,0,0,874,0,0,0,
+0,0,774,0,0,0,0,0,92,0,0,0,0,0,0,830,701,0,0,0,0,0,426,350,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,603,59,0,0,0,0,0,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0,0,0,441,163,4,0,
+0,0,0,0,0,0,0,0,806,0,0,0,0,0,0,233,0,0,0,0,1994,0,1739,0,0,393,0,47,1038,0,0,0,
+309,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,363,0,0,0,175,0,0,0,0,0,0,0,666,
+0,0,1675,0,1600,0,0,0,808,0,0,0,0,0,0,0,0,0,0,0,280,54,0,0,0,0,0,0,0,0,421,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,249,0,0,103,254,0,262,1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,805,0,0,0,0,0,0,0,0,0,1630,0,0,0,0,0,0,0,0,0,0,0,0,0,671,972,989,0,0,
+0,0,0,0,0,889,0,0,0,1382,0,0,0,0,0,0,0,775,0,0,0,0,0,0,0,0,0,0,388,202,0,0,0,0,
+16,560,0,0,0,841,0,0,566,0,0,0,938,0,0,0,0,0,0,0,0,0,0,912,0,0,0,1361,0,0,0,0,0,
+0,618,236,0,1854,0,0,318,190,0,1376,0,0,0,0,0,0,0,349,0,0,0,0,951,1972,0,0,0,0,
+0,0,344,0,0,0,0,0,0,0,0,850,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,163,85,0,487,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,145,0,83,0,0,1013,0,0,0,1922,0,0,169,557,66,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,1193,82,0,352,454,57,0,0,1333,396,107,0,370,0,0,0,0,0,0,0,0,0,204,0,0,0,
+0,0,1706,0,0,0,0,0,0,0,0,0,0,0,0,394,1204,0,0,0,0,0,1007,0,0,0,1696,0,1519,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,981,0,0,0,0,1072,0,0,0,712,0,1629,0,0,0,0,0,0,0,728,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1271,0,0,0,1608,16,0,0,0,0,485,0,0,0,0,0,0,
+153,27,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1991,0,0,0,0,0,0,0,0,52,0,21,0,
+0,0,0,0,0,0,0,0,819,0,0,0,0,0,917,0,0,0,0,784,0,0,0,0,135,0,0,0,0,0,454,0,0,0,0,
+0,0,0,0,0,852,1719,0,0,0,0,0,852,0,0,0,0,0,952,0,0,0,0,568,0,0,0,0,0,448,0,0,0,
+67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1826,657,0,729,666,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+669,0,0,0,0,0,0,0,402,0,0,152,0,0,0,0,912,0,0,0,0,0,0,51,320,0,445,0,0,0,0,308,
+0,0,0,0,0,386,0,0,239,0,0,130,83,0,143,0,348,0,0,0,0,0,0,0,958,0,0,0,0,0,210,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,430,0,0,0,0,0,0,0,0,0,0,0,0,7,213,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,801,0,0,0,0,0,0,0,0,0,936,0,108,0,0,
+0,0,0,0,0,0,0,885,587,219,398,364,0,1165,0,0,342,241,303,0,0,0,0,0,0,0,0,0,0,
+1454,0,0,0,0,0,0,0,0,0,0,254,562,0,786,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1294,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,493,216,0,0,0,0,219,341,0,0,0,0,0,
+0,0,0,0,0,130,1734,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,701,604,0,0,879,0,195,
+666,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1669,0,0,0,1791,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1228,0,0,0,0,0,623,0,0,0,0,0,0,0,798,0,0,0,0,0,0,0,0,0,0,0,0,84,
+122,0,0,0,837,0,0,0,0,0,0,1013,0,0,577,0,0,0,460,932,0,0,0,0,0,0,0,0,0,0,0,31,
+131,0,0,0,605,0,0,0,1246,0,0,0,0,68,278,165,307,781,0,0,0,0,0,0,33,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,1113,0,0,720,1953,203,0,0,0,0,0,0,0,425,326,0,0,0,0,0,
+0,0,0,0,0,241,1316,0,0,0,0,0,416,0,0,0,1300,0,847,0,0,662,358,0,0,0,0,839,1823,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,654,1522,0,0,0,0,0,0,163,0,0,0,0,0,314,978,0,0,0,
+601,0,0,0,0,0,946,434,0,0,0,402,411,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,1467,
+410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,483,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,0,70,0,0,0,0,1405,0,0,0,0,0,0,108,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,777,0,0,0,0,0,747,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,505,0,326,0,0,164,628,654,0,0,0,
+37,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,668,152,0,0,0,0,0,0,0,0,0,0,0,581,
+0,0,0,0,44,126,89,0,0,0,0,0,0,0,0,1531,0,0,0,0,0,0,0,0,203,1167,0,0,0,0,0,0,0,0,
+531,1232,0,0,0,0,0,943,0,670,231,880,0,1617,0,0,0,1957,0,0,0,0,0,0,0,975,0,0,0,
+0,0,0,0,0,0,0,0,242,0,0,0,0,0,0,0,0,0,421,0,0,14,834,0,0,0,0,0,0,0,0,0,0,0,0,
+465,0,0,0,0,0,834,688,413,855,0,0,0,590,0,0,0,0,0,0,0,0,114,0,0,0,0,0,0,0,0,0,0,
+0,45,169,0,0,0,0,0,0,0,0,0,0,0,198,0,0,565,585,0,0,0,0,0,0,0,0,0,0,0,0,0,691,0,
+0,0,593,0,0,0,0,0,0,0,0,0,913,116,0,0,0,0,1360,0,0,0,802,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,673,308,0,709,1006,1895,0,228,0,0,0,1840,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,608,0,0,0,0,0,0,0,0,0,1573,0,2039,136,540,0,0,0,0,0,0,0,
+897,0,0,938,1878,0,0,0,0,0,0,0,0,0,1469,0,999,0,299,0,0,0,0,0,0,0,578,0,0,0,0,0,
+456,0,0,0,1679,163,693,0,0,0,0,0,0,48,755,0,0,0,0,0,0,0,0,0,0,0,0,338,0,0,0,0,
+1091,0,0,0,0,695,0,0,1464,0,0,0,0,0,975,0,0,335,0,0,1979,0,0,0,0,269,1566,630,
+396,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1815,634,0,0,0,966,0,0,0,0,0,0,0,9,
+412,0,958,0,0,579,382,0,212,0,0,0,0,965,681,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,655,
+0,0,0,0,67,0,0,0,0,0,0,751,0,0,0,0,423,231,0,0,1016,300,0,0,0,0,100,237,0,0,0,
+1370,0,0,0,1208,0,0,0,0,0,1219,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,199,0,0,427,0,0,
+0,0,949,665,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,712,0,0,0,0,0,1186,0,0,0,0,0,0,0,0,0,0,295,312,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+151,0,0,0,0,588,4,0,0,0,0,0,414,104,0,0,757,263,0,561,0,0,0,320,0,0,0,0,0,0,0,0,
+0,0,0,225,0,0,0,0,37,817,0,974,0,0,0,0,0,0,0,0,0,0,0,0,0,2026,131,235,16,0,590,
+1157,0,0,0,0,0,0,0,0,221,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,140,390,0,0,0,0,
+0,0,0,1144,0,0,0,464,0,0,0,0,0,0,0,0,0,0,0,0,204,407,303,1218,0,0,0,0,5,325,0,0,
+0,0,12,800,0,1783,0,0,0,0,0,0,0,0,0,0,504,621,0,0,0,0,0,0,0,0,0,920,0,376,0,0,0,
+0,0,218,580,0,768,454,0,0,0,0,0,0,0,0,0,0,0,0,676,0,0,0,0,0,0,164,0,0,0,0,0,0,0,
+0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,120,285,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,226,343,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,0,0,1812,0,0,8,0,0,0,21,1125,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1327,0,0,0,0,575,1598,0,0,0,0,0,0,0,0,0,895,0,0,0,959,0,0,
+0,0,0,1759,173,0,0,0,0,266,261,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,1427,0,0,300,1033,0,0,0,0,0,0,0,0,0,0,0,584,0,0,0,0,52,734,
+0,0,217,239,0,1129,0,0,0,0,0,0,0,0,732,20,0,0,0,0,0,0,0,0,0,0,0,418,0,0,0,613,0,
+0,0,0,0,0,0,0,0,632,0,0,85,984,0,0,0,0,909,694,7,1109,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,167,0,0,0,0,280,62,0,0,33,0,0,359,186,980,0,0,0,0,0,0,0,0,0,0,0,585,0,0,0,
+211,0,0,336,145,0,1130,0,873,0,0,840,263,0,0,0,0,0,0,0,0,0,916,0,0,0,0,0,0,0,0,
+0,0,155,0,0,0,461,97,0,0,0,0,0,1356,0,0,0,0,0,0,0,593,0,0,0,0,0,1392,0,0,0,0,
+126,0,0,0,0,1179,0,0,0,0,0,162,0,0,0,0,0,765,0,187,0,1286,0,0,0,0,0,0,0,0,0,635,
+0,0,23,215,0,0,0,1306,0,0,97,716,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,657,0,
+0,0,0,0,0,0,0,299,0,0,0,0,0,0,134,0,0,0,0,0,0,0,0,0,0,0,658,1082,0,0,0,0,0,2002,
+0,0,0,0,0,0,833,248,0,0,0,0,0,1654,0,0,531,0,0,0,0,0,0,634,0,0,0,0,0,0,0,0,0,
+853,573,249,0,0,0,0,0,0,0,0,527,0,0,0,0,1419,0,0,0,0,0,0,20,49,0,0,0,992,0,0,0,
+728,0,0,0,0,0,0,0,0,0,0,0,0,497,1579,0,0,0,0,62,268,0,0,0,0,0,0,0,1201,0,0,0,0,
+0,0,0,0,0,0,0,0,495,193,0,0,0,0,106,0,0,859,0,0,23,0,0,0,0,0,0,0,813,925,0,0,
+223,613,953,0,0,0,0,0,0,0,0,666,0,0,0,0,0,0,0,0,0,670,0,0,40,216,0,0,0,0,0,0,
+259,0,0,0,440,1114,0,0,0,0,0,0,0,0,74,475,0,0,188,139,0,797,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1572,0,0,0,0,39,0,0,0,0,0,0,0,0,0,0,0,0,1594,0,0,0,0,0,0,0,290,0,232,
+0,0,887,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,521,14,0,0,0,0,0,741,0,0,0,992,0,
+0,0,0,0,0,0,0,111,0,0,425,0,0,0,0,0,789,0,0,0,1593,0,1768,0,0,233,0,0,0,0,943,0,
+0,0,0,0,0,0,955,225,245,0,0,0,0,0,0,241,0,0,0,0,1943,0,0,0,1284,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,709,0,0,0,0,0,0,554,0,0,0,0,0,0,0,0,1564,0,0,0,
+443,0,0,0,0,0,0,280,0,0,0,0,0,0,0,0,729,0,0,0,348,0,0,0,0,0,0,0,758,848,298,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,829,1422,189,121,0,0,632,812,0,0,556,0,0,0,0,0,436,172,
+530,844,232,984,0,0,0,0,0,0,0,0,0,0,147,0,0,0,0,0,0,0,0,537,0,0,0,0,0,859,0,0,
+842,0,0,0,0,0,0,0,0,0,0,1291,0,0,0,0,0,0,0,0,0,0,0,1482,612,392,0,0,0,262,31,0,
+0,0,0,0,0,0,0,0,0,753,549,0,0,0,0,0,0,696,0,0,0,0,0,0,0,834,0,0,0,0,0,771,0,0,0,
+0,0,0,0,0,0,0,0,0,0,921,0,0,0,674,0,0,0,0,0,0,0,0,0,0,308,444,0,0,0,0,0,0,805,
+180,0,0,278,271,0,0,214,505,0,1215,0,0,0,0,0,0,387,271,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,1645,42,92,0,459,0,0,330,1557,0,0,0,0,0,0,0,0,113,18,0,0,0,
+1742,0,0,0,965,0,0,0,0,0,0,0,0,0,0,0,0,0,182,0,0,65,0,0,0,0,0,0,0,0,0,0,0,0,973,
+0,0,0,0,0,328,0,0,588,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1786,
+0,0,962,1985,0,0,0,308,508,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,588,0,0,0,0,0,0,614,793,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,290,0,0,0,0,0,0,0,0,0,0,1136,0,0,0,0,0,0,0,0,0,0,796,719,0,0,
+326,210,0,0,0,701,758,472,0,0,0,1947,278,1079,0,0,0,0,0,0,497,41,0,0,634,46,961,
+0,810,524,0,0,33,0,0,0,0,0,0,0,0,0,0,0,0,532,0,997,0,0,0,0,0,0,0,0,0,0,0,1301,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1298,0,671,0,0,0,306,0,0,0,0,0,0,0,0,0,0,
+693,1823,0,0,0,759,0,0,0,0,0,1932,0,0,0,0,0,0,0,0,0,0,0,0,0,0,88,182,0,0,0,1964,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,521,0,0,0,0,0,0,424,857,0,0,0,0,671,328,0,
+529,0,0,0,0,0,716,0,1509,80,67,0,0,0,0,59,141,0,0,0,0,0,0,783,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1498,0,0,0,0,343,430,803,1183,677,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,19817,0,5579,9350,0,0,21002,19718,0,0,0,21926,0,0,0,0,0,0,0,0,0,0,0,0,0,20711,
-0,0,0,20197,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40550,0,0,0,57510,0,0,0,53895,
-0,0,15017,0,17000,39367,2347,0,0,0,0,0,0,0,0,0,8588,0,0,0,0,0,3273,17862,3498,
-2085,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19048,0,0,0,0,0,11978,58631,0,0,0,0
-,0,0,523,0,12969,198,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28197,0,47846,0,0,0,0,0,0
-,0,0,0,4549,0,0,0,0,0,0,0,0,0,0,687,14917,748,8229,0,0,0,0,0,0,2476,12935,0,0,0,
-0,0,0,22792,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27528,59142,0,0,20876,20134,0,0,0,
-0,440,12068,0,58951,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48038,0,0,0,60999,0,0,0,0,
-0,0,0,0,0,0,0,0,0,15716,7498,5476,0,0,0,0,20202,37959,0,0,0,0,0,0,0,0,0,0,0,0,
-29801,0,5451,0,0,0,0,0,0,0,0,0,0,50790,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24485,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13573,0,0,22856,0,0,0,0,21927,0,0,0,0,0
-,0,9130,0,0,0,0,0,0,13732,0,0,0,0,0,0,0,0,0,0,2282,583,0,0,0,0,0,0,0,0,0,0,3726,
-26503,0,0,0,0,0,0,9258,0,0,0,0,0,0,0,0,21604,0,0,0,45574,0,0,0,0,0,20710,0,0,0,
-42694,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1163,6694,0,0,0,0,0,0,0,10948,0,0,0,29700,0,0,
-0,0,0,58823,3796,27399,20939,10180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-19,29287,28649,14534,0,0,16428,45607,0,0,0,0,0,0,25322,0,4908,0,0,0,0,0,0,25476,
-29097,14246,11053,0,0,0,0,0,0,0,0,18502,0,0,0,44390,0,0,0,17765,0,0,0,0,0,0,
-24520,0,0,0,0,0,0,0,0,0,0,17319,0,0,0,0,0,0,0,0,0,0,0,0,0,28166,0,0,0,0,0,48198,
-0,0,31467,0,24585,0,0,0,0,18692,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23596,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,7236,968,13637,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-3763,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14791,0,0,0,12324,0,12741,0,0,0
-,0,0,0,0,0,0,11108,0,0,0,0,4009,40295,20616,4357,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-15015,0,0,0,0,0,43751,0,0,0,0,0,0,0,0,0,0,0,23013,0,0,0,0,0,0,0,0,0,0,0,0,0,
-45542,0,0,0,0,0,0,0,0,0,23974,0,0,0,0,17480,20647,0,0,0,0,0,0,8876,0,0,40806,0,0
-,0,0,0,0,0,14502,17160,17764,0,0,31594,35431,0,0,2890,0,0,0,0,0,0,0,0,27524,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8228,0,56583,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,34278,0,0,0,0,0,0,0,0,0,0,0,0,0,2662,0,26724,0,0,0,0,0,0,0,64198,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22281,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3049,
-54983,0,0,0,0,0,0,0,837,0,17604,0,0,0,0,0,28838,0,0,0,0,0,0,26312,0,0,3910,0,0,0
-,25830,0,0,0,0,0,8391,0,19845,19240,1092,0,0,5449,0,0,0,0,17188,0,0,0,0,0,0,0,0,
-0,10629,0,0,6671,61094,5832,8358,0,0,0,55078,0,0,0,0,0,29860,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,51494,0,28647,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25989,0,0,30153,61318
-,0,0,0,0,0,0,0,24903,0,0,0,4388,0,42054,0,0,0,0,0,0,0,53158,0,0,0,0,0,0,0,50918,
-0,0,0,0,0,0,26251,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5929,2853,0,37126,
-7372,197,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2027,934,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,55686,0,0,5672,5447,0,62758,0,0,0,0,0,0,0,0,0,0,0,0,2923,0,556,1415,
-0,0,0,0,0,0,0,0,0,8645,0,9477,0,0,0,0,0,0,0,48742,0,0,0,0,0,0,0,0,0,0,24235,228,
-0,0,0,0,0,0,0,0,0,0,16970,18823,0,0,0,0,0,0,0,0,0,25158,0,0,0,0,0,18567,20072,
-2823,14313,1830,0,0,0,0,0,0,0,0,27048,23526,0,0,0,0,0,997,492,0,14730,16677,396,
-13574,0,0,0,41671,0,0,0,0,0,0,0,19045,0,0,0,421,17545,3110,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,47111,14475,56551,0,0,0,0,0,0,0,0,0,0,3697,0,0,0,0,0,0,49382,0,35559,0,
-0,0,0,40,0,11496,15621,0,8550,0,0,0,63462,0,0,0,0,0,0,0,36966,0,50406,0,46022,
-1001,0,0,12069,3249,0,0,0,0,0,0,0,0,0,0,0,0,0,15241,0,0,0,0,0,0,0,0,64743,0,0,0,
-0,0,58759,0,0,0,0,1136,26981,0,0,0,0,0,0,0,17732,0,0,0,17157,20011,6629,0,43879,
-0,0,0,13572,25128,10759,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28676,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,875,24007,0,0,0,0,7628,0,0,0,0,0,12268,0,0,0,0,0,0,0,0,19300
-,23210,356,0,0,0,0,0,0,0,0,0,15236,0,0,0,0,0,49670,0,0,0,0,0,0,0,21764,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,13931,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45799,0,0,436,3589,
-0,0,11402,0,0,0,0,0,0,0,0,0,0,62822,0,0,0,39814,588,0,0,0,0,0,0,27750,0,0,0,0,0,
-0,1609,22660,2346,18951,0,16068,0,0,0,0,0,0,5162,11110,0,0,0,0,15048,1060,0,7879
-,18280,326,0,14886,19656,0,7594,0,0,0,0,0,781,581,0,16198,0,0,0,0,0,0,1078,9892,
-0,0,0,0,0,0,0,0,0,0,4489,0,0,0,0,33798,0,0,0,54534,0,0,0,0,0,0,0,33158,0,0,0,0,0
-,0,0,0,0,42086,13834,2757,8456,16773,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3434,0,0,0,
-0,0,3946,29668,0,0,30634,36775,0,0,0,0,0,24901,0,16069,6280,0,0,0,0,41990,0,0,0,
-0,0,0,0,27365,0,0,0,0,0,0,0,0,0,0,1450,44807,0,0,0,32100,0,0,0,0,0,35110,0,0,0,0
-,0,0,0,0,17448,19591,0,0,0,0,0,0,0,0,0,0,0,0,1739,0,0,0,0,5511,0,0,0,32934,0,0,0
-,0,0,0,0,0,0,18180,0,0,0,23428,19754,0,0,31174,3021,31655,23464,0,0,0,0,0,0,
-57255,0,0,21292,64487,0,0,0,0,0,0,25802,9189,0,0,0,0,0,49254,0,0,0,0,0,0,0,0,0,0
-,5837,50023,0,0,0,0,0,0,0,0,0,15495,0,0,0,0,0,51942,0,0,0,0,0,0,0,0,28104,58662,
-0,50214,0,0,0,0,0,0,0,0,2988,0,22888,31812,0,0,0,0,0,2020,0,18916,0,0,0,0,0,0,0,
-23973,0,0,0,0,17516,11717,0,0,0,55911,0,0,0,0,0,0,0,2855,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,46822,0,24710,28586,0,0,0,1556,0,0,30117,0,0,22090,57127,3403,14087,0
-,0,0,0,0,0,0,0,0,0,1041,0,10633,6916,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27269,0,0,13322,18055,0,29380,0,56454,0,0,120
-,0,0,8773,0,0,0,0,16040,0,0,0,0,0,0,0,27242,23781,0,1572,0,28134,0,0,1512,0,0,0,
-0,0,0,27684,0,38470,0,0,0,0,0,0,1513,8709,0,0,0,0,0,0,0,0,0,0,0,46566,0,0,0,0,
-28521,61159,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24356,0,0,0,0,0,0,0,0,0,13028,0,
-5863,0,0,15693,0,0,0,0,0,0,0,1131,23398,0,0,0,0,0,0,0,26212,0,0,0,0,0,0,0,0,0,0,
-0,0,0,18404,0,0,0,0,1457,26183,0,0,2475,7110,0,0,0,0,27180,60166,0,0,0,20262,0,
-41862,0,0,0,0,0,0,0,0,0,0,2762,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26148,0,0,0,0,0,0,0,0
-,0,28229,0,0,0,29254,0,0,0,0,0,0,0,0,0,0,27690,0,0,13636,12776,1862,0,0,0,0,0,0,
-17225,3271,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28039,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,4457,18117,0,2023,402,0,0,0,0,0,0,0,0,0,0,0,0,0,104,3654,0,0,
-0,0,0,0,0,0,18440,0,0,0,0,0,0,0,0,29861,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,22150,0,0,0,0,0,0,0,0,0,0,0,0,24074,0,0,0,0,0,0,0,0,12004,0,32358,
-0,0,3081,0,0,0,0,0,0,0,0,0,4749,0,0,0,0,0,0,0,0,0,0,0,10792,1799,21322,0,7880,
-12613,0,0,0,0,0,0,0,0,13993,0,0,0,16202,0,0,0,0,32102,0,37223,0,10500,0,0,0,0,0,
-0,0,0,32008,0,0,0,0,0,23816,3236,0,0,0,0,0,23237,0,0,5642,0,4684,294,0,0,0,0,0,0
-,0,0,0,0,0,0,0,0,0,0,0,0,0,26852,0,0,0,0,0,0,7148,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,7890,61798,939,0,0,56679,0,0,0,0,0,27078,202,5029,0,0,0,0,0,
-0,0,0,0,28005,0,0,15273,24741,5676,20452,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55910,0,0
-,0,0,5069,27942,0,21092,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12517,0,0,0,0,0,0,
-0,0,0,0,0,0,21384,28260,0,2502,20108,0,0,0,0,0,0,0,0,0,0,0,0,46726,0,30790,0,0,0
-,0,0,14725,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1099,6372,0,0,0,12422,15182,0,8683,0,
-10665,19462,0,0,0,0,0,0,1590,0,31628,0,22632,19750,0,0,0,0,0,0,0,24198,0,0,0,0,0
-,50662,0,0,0,0,0,0,0,0,0,0,9131,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11015,0,0,0,0,0,0,0,
-0,16490,54695,0,0,0,0,0,0,0,0,12937,0,0,0,0,16004,0,0,0,0,0,0,0,0,0,2181,6923,0,
-0,0,0,0,0,0,15624,11302,0,0,5673,7559,0,0,14668,15684,0,0,0,0,0,0,24204,48134,0,
-24230,0,55527,0,0,3464,19141,0,0,0,0};
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1357,53,0,0,0,0,590,0,0,0,0,0,0,0,0,0,0,
+0,0,0,329,0,0,0,0,0,0,0,469,0,0,0,0,0,0,0,0,0,0,460,0,0,1743,0,0,963,340,0,0,0,
+0,0,1603,0,0,250,0,0,0,0,0,646,218,0,1794,0,0,0,571,0,455,0,0,0,1012,0,0,0,0,0,
+0,0,0,0,0,0,0,597,161,0,349,0,524,0,0,0,0,0,0,0,0,0,0,0,0,322,432,0,0,0,0,0,0,
+325,223,0,0,0,0,0,566,0,0,0,1394,481,436,0,48,457,610,756,618,0,0,0,755,0,1217,
+0,0,0,0,0,197,0,0,0,0,0,0,0,0,0,0,0,0,0,0,544,492,107,414,0,0,0,0,0,0,0,0,0,0,0,
+1007,0,0,0,0,5,0,0,1580,0,0,0,0,0,0,0,0,0,0,0,0,0,673,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,1843,0,0,0,0,0,0,0,0,0,165,0,0,0,0,0,0,809,885,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,498,0,0,0,306,9,0,0,0,0,0,0,0,437,721,146,0,0,0,0,0,0,0,0,0,0,0,177,0,0,0,0,
+0,0,0,1377,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,200,0,959,0,0,0,1928,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1435,0,481,0,0,0,0,0,0,142,84,0,0,0,0,0,
+1015,0,0,0,315,0,0,0,0,0,0,759,0,0,0,0,0,0,0,0,712,0,0,0,1722,0,0,0,0,0,0,0,0,0,
+0,0,0,222,0,985,1414,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1273,
+538,706,0,0,0,0,0,0,0,0,115,0,0,0,0,0,0,0,0,0,0,1781,0,0,0,0,0,431,97,665,42,
+237,0,0,0,264,0,0,213,0,0,0,0,0,0,0,455,0,0,0,906,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+624,0,574,0,0,0,0,0,0,0,0,0,0,0,0,354,0,0,0,1558,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,
+235,723,1813,0,0,0,957,0,830,0,0,0,0,0,0,0,0,0,0,0,0,23,0,0,496,0,0,0,0,0,0,0,
+547,239,88,0,0,0,0,0,0,0,0,0,1310,0,0,0,0,0,0,0,0,80,1076,0,0,118,0,0,0,479,274,
+0,0,0,0,0,0,0,0,0,0,0,497,0,0,669,261,0,0,0,0,13,0,0,0,0,0,0,791,250,642,0,0,0,
+1429,939,949,0,0,0,0,0,0,0,0,0,0,0,0,0,818,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,982,330,0,0,0,0,545,0,0,0,0,0,0,947,0,1188,0,0,0,0,0,904,0,0,0,0,0,1372,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,693,377,0,0,0,0,0,0,0,0,0,0,0,0,0,0,695,0,0,
+713,386,0,0,0,0,128,1575,0,0,0,0,0,0,424,893,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,904,0,0,0,0,0,552,322,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,1808,49,0,0,0,0,
+1832,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,421,0,0,442,415,0,0,289,
+0,0,0,0,0,206,110,0,0,0,0,0,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+19,1539,0,0,0,0,0,1340,0,1194,0,0,0,0,0,0,0,0,549,0,0,0,0,0,0,0,0,1720,0,0,0,0,
+0,0,0,0,0,319,0,0,0,0,112,1180,0,0,0,0,0,0,0,0,0,0,0,967,0,0,0,0,0,0,0,0,0,1940,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,735,0,0,0,0,0,0,0,0,0,897,132,0,0,0,0,0,0,0,
+0,0,0,38,838,0,0,0,379,218,8,660,1017,0,0,0,0,0,0,111,387,647,877,0,0,53,790,0,
+0,0,0,0,0,0,0,458,0,0,0,0,0,0,954,0,0,0,394,0,1367,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,882,0,0,0,0,0,0,0,1409,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,38,124,342,199,0,0,0,0,
+0,0,0,0,0,0,724,628,0,0,0,0,804,266,0,0,0,0,0,208,0,79,0,0,0,0,0,0,0,0,741,0,0,
+0,0,0,0,0,0,0,0,606,0,1494,821,1553,0,0,135,405,0,0,178,100,0,0,0,0,0,0,0,0,0,0,
+0,0,0,481,0,0,0,1378,0,0,0,0,0,0,0,0,0,0,0,0,0,791,33,1227,857,0,467,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,447,0,0,0,0,0,0,86,128,0,0,0,0,0,0,587,0,0,0,692,1018,0,
+195,0,0,0,0,0,0,0,1546,0,0,0,0,0,0,0,0,0,0,0,684,0,0,345,0,0,0,0,0,0,365,0,1683,
+0,0,472,0,433,0,0,0,0,0,0,0,28,0,0,0,997,0,705,3,0,0,0,0,0,0,0,0,0,229,0,0,0,0,
+102,0,0,0,0,866,1022,0,0,0,0,0,0,0,0,0,55,0,115,0,0,0,0,933,0,0,0,0,0,0,0,702,0,
+0,0,0,0,0,0,1728,26,484,0,0,0,185,618,417,0,803,0,0,0,0,0,0,0,0,0,0,0,1262,0,0,
+0,0,0,0,0,0,0,0,0,0,0,633,0,0,0,0,0,0,0,0,0,0,0,0,0,479,262,0,0,0,0,0,0,830,0,0,
+0,0,26,70,0,0,0,0,0,0,0,0,217,0,640,51,0,0,360,1586,0,0,0,0,0,652,0,0,0,0,0,766,
+0,0,0,0,298,737,0,0,0,0,0,0,0,0,0,0,655,222,906,0,0,1013,991,2009,0,0,0,0,503,0,
+0,0,216,154,0,0,0,716,0,844,0,0,0,0,621,252,0,0,0,0,748,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,103,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,576,0,0,0,648,0,0,0,331,0,0,0,
+0,0,0,0,0,0,0,0,0,632,0,0,0,518,107,0,0,0,0,0,0,0,0,851,0,0,0,0,504,0,0,0,0,0,0,
+0,0,0,0,0,0,7,883,0,0,0,0,0,0,0,922,0,0,0,0,0,0,0,0,91,993,0,0,0,0,0,0,200,131,
+10,0,0,0,0,0,0,0,0,0,0,0,0,0,365,1433,0,0,0,0,28,103,0,0,798,1013,0,0,0,0,0,0,0,
+0,39,1925,0,853,0,0,271,519,0,0,0,0,338,0,0,300,470,419,0,0,0,0,0,0,836,0,0,0,0,
+0,0,1937,0,0,0,0,0,393,0,0,357,0,0,0,0,0,703,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,387,0,0,0,0,0,0,75,708,453,1351,0,303,0,0,772,0,0,0,0,0,0,0,0,749,0,0,
+0,0,0,0,0,0,0,0,0,0,0,1065,0,0,717,226,0,0,0,0,0,890,431,626,0,0,0,0,706,0,0,0,
+51,698,0,0,0,0,0,0,0,0,0,0,0,828,0,0,17,0,0,0,0,1929,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,84,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,871,498,0,101,1793,0,0,0,0,0,0,435,0,
+0,0,0,0,966,0,129,1644,0,0,0,0,0,0,0,0,0,0,0,0,0,997,502,0,0,0,0,0,0,0,0,0,0,0,
+0,823,0,1927,0,0,0,0,98,1756,0,0,0,0,0,0,0,0,0,0,0,0,8,0,160,1046,0,492,0,0,0,0,
+0,0,129,45,0,0,0,0,0,0,353,558,0,0,0,0,0,785,0,0,0,1145,189,0,0,0,26,353,0,0,0,
+0,0,2024,0,0,0,606,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,855,0,0,0,0,0,0,0,0,0,0,0,
+0,0,2011,0,0,5,4,0,0,461,764,0,0,0,1449,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1445,0,0,
+0,1168,0,0,0,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,216,0,0,0,286,0,0,0,
+3,0,0,0,723,536,0,0,0,0,0,285,0,0,0,560,0,0,0,0,0,690,0,0,0,0,0,1246,0,0,63,0,
+33,0,0,0,0,0,520,1862,0,0,0,0,0,0,0,0,0,0,0,0,630,0,0,0,0,554,0,0,0,0,0,1001,0,
+0,0,0,0,446,0,0,0,0,0,0,0,1313,0,0,837,636,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,278,
+0,0,0,0,0,0,0,0,868,0,0,0,0,1010,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1231,0,304,0,506,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,0,93,1408,794,
+843,704,0,285,114,485,898,145,0,19,2035,0,0,0,1933,0,0,0,0,0,0,0,1728,0,0,0,0,0,
+0,0,0,746,0,0,0,0,0,0,0,995,1964,0,0,0,0,0,0,0,0,0,0,0,1550,0,874,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1018,0,0,0,814,126,0,0,1264,0,0,814,955,0,0,0,0,0,0,
+0,981,0,0,0,0,0,0,0,0,915,56,0,0,100,0,0,0,0,0,0,0,0,0,638,0,0,0,0,738,0,0,0,0,
+0,0,0,0,0,758,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1112,0,0,214,0,0,0,133,0,196,
+168,0,0,0,0,0,1152,0,1245,0,0,538,169,871,1816,0,0,413,133,0,0,0,978,0,0,43,93,
+371,0,0,0,0,0,0,526,25,0,754,335,0,0,0,0,182,0,0,0,0,0,0,0,0,0,0,0,39,601,0,0,0,
+0,0,0,0,181,370,0,0,1652,358,0,0,0,0,0,0,0,0,0,176,286,0,788,0,0,0,0,0,1223,780,
+254,1003,896,0,0,0,1447,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,744,0,0,0,0,0,126,0,
+41,788,0,0,0,629,0,0,0,0,0,0,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,420,37,1900,0,0,0,0,542,1570,957,0,0,0,0,0,0,
+0,373,31,0,0,0,0,125,325,0,0,0,0,0,0,323,0,0,1547,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1216,0,0,0,0,0,0,198,1905,629,15,0,0,0,0,0,0,20,75,543,1353,0,0,0,533,0,0,6,0,0,
+0,0,0,0,538,0,0,0,0,0,0,0,0,0,0,0,338,0,0,0,0,11,0,0,0,284,659,0,989,0,0,0,0,0,
+0,0,0,0,848,0,0,507,0,0,0,0,0,0,0,0,188,991,884,0,0,0,0,60,959,0,0,0,0,0,1653,0,
+0,922,337,0,638,0,0,500,0,0,0,0,0,0,0,0,0,0,0,166,0,0,0,0,0,0,0,0,0,0,0,0,418,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,760,0,0,0,0,0,0,1277,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,770,0,0,0,0,0,0,0,243,89,0,0,0,0,0,0,0,0,0,1396,0,
+560,0,0,3,1658,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,586,0,0,1271,0,0,0,505,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,637,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1947,
+41,445,0,0,0,0,0,0,0,0,57,189,0,0,371,0,0,0,0,552,0,883,0,923,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,875,0,0,0,1788,49,0,0,0,0,0,
+0,0,0,0,0,0,661,0,0,1945,0,0,0,0,0,794,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,1135,0,0,0,745,0,0,0,0,0,0,0,84,0,0,0,0,0,0,0,410,0,976,0,0,0,0,0,703,0,0,
+0,0,0,0,187,322,0,0,0,227,0,0,0,0,560,0,31,1395,0,0,0,0,0,466,0,0,0,0,643,167,0,
+0,0,1428,0,412,0,0,0,0,0,0,0,0,0,1118,562,0,0,0,0,0,256,0,0,0,0,0,0,1771,0,0,0,
+0,0,1190,132,0,66,0,0,0,0,0,0,0,0,0,0,317,0,0,0,63,0,0,0,0,0,0,0,1475,0,0,0,0,0,
+0,0,288,0,0,0,0,608,0,0,0,0,0,0,0,0,1225,0,1189,0,0,0,0,0,0,0,1468,0,0,0,0,0,
+689,120,0,0,0,0,0,0,0,1,0,329,0,0,0,0,226,0,0,0,0,0,1855,0,0,461,0,0,0,0,1346,0,
+0,0,0,0,85,0,0,299,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1171,0,0,
+0,980,0,0,0,0,0,0,0,0,637,279,0,0,0,0,0,293,0,0,0,0,528,17,0,0,0,0,5,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,0,0,0,0,0,0,0,601,0,0,0,0,0,0,779,0,
+196,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1322,737,752,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,412,192,80,0,0,8,1470,0,0,0,0,0,0,0,0,0,873,0,0,0,0,0,835,0,0,0,0,256,
+38,986,0,0,0,0,0,0,0,0,0,91,257,278,911,0,0,0,0,0,0,0,0,749,151,0,0,0,0,0,0,0,0,
+0,0,0,0,989,0,0,990,0,0,90,194,0,0,0,0,0,425,0,0,0,0,0,774,0,0,0,0,0,0,0,0,0,0,
+646,827,752,0,0,0,662,0,22,21,0,0,0,0,0,0,95,239,0,0,0,431,0,0,0,0,0,874,0,0,
+265,65,0,0,0,1350,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1887,0,0,0,0,0,0,0,809,
+0,696,0,1074,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,630,0,0,802,0,0,0,56,776,0,
+970,0,0,797,0,0,0,0,0,400,0,0,1951,0,0,41,0,11,118,0,0,0,0,0,0,0,0,251,615,0,0,
+0,1044,0,0,0,0,0,0,0,0,0,0,0,225,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,370,0,0,0,0,
+104,48,209,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,930,0,0,0,0,
+0,0,0,0,0,0,0,1286,0,759,0,120,385,0,0,0,429,0,0,0,0,0,0,0,0,820,0,0,0,0,0,0,
+199,0,10,151,0,0,0,761,365,0,0,0,0,0,0,0,0,0,46,1086,0,0,0,0,11,1624,58,344,0,0,
+1008,1868,0,0,0,888,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,711,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,440,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,914,1913,0,958,0,885,0,0,0,0,0,0,0,0,0,0,0,
+0,0,847,276,0,302,65,0,0,0,510,0,1514,0,0,0,0,0,0,152,291,0,0,0,0,0,0,0,0,0,0,0,
+0,282,589,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,463,42,0,0,0,0,0,372,0,0,0,0,0,0,0,
+0,0,680,0,0,0,0,0,0,0,0,977,1997,0,0,0,810,0,0,0,0,0,0,0,0,0,1390,0,0,0,644,0,0,
+867,982,0,0,0,0,0,0,0,540,0,123,0,0,0,1978,0,0,0,0,789,623,0,1723,0,1220,0,0,0,
+0,0,0,0,480,0,0,0,0,0,0,0,0,0,0,0,888,0,0,0,0,0,0,0,0,0,0,0,0,299,1995,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,788,179,0,0,0,0,0,0,431,156,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1373,39,80,196,0,0,507,0,0,0,646,0,0,0,0,
+0,1214,0,0,0,0,926,0,0,0,1,114,0,0,0,0,0,446,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,490,0,0,0,491,0,1584,0,0,507,250,0,0,0,158,
+10,362,1,0,0,0,0,0,0,0,0,0,408,228,860,480,0,779,0,0,0,557,0,0,142,197,0,0,0,0,
+0,0,0,0,0,0,0,1490,11,378,316,1057,0,0,18,579,299,1546,0,177,0,0,0,0,0,0,0,0,0,
+411,0,0,0,0,727,439,0,0,0,0,0,1528,0,0,0,0,0,0,58,0,482,0,0,0,505,1952,0,0,0,0,
+0,0,0,0,0,0,0,242,0,0,0,0,0,0,0,953,0,0,0,0,802,0,0,0,0,0,0,0,0,0,0,290,0,0,791,
+52,0,0,0,0,0,0,0,0,0,0,0,112,0,0,0,0,0,1028,0,0,138,0,0,0,0,1811,0,0,0,0,0,0,
+934,1821,0,0,0,0,371,38,0,0,0,1296,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,723,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1330,0,0,0,0,0,0,0,1255,296,109,0,0,0,0,0,660,0,0,0,0,270,591,0,
+0,0,0,0,0,0,1090,81,0,0,0,0,391,0,0,0,0,249,322,0,0,0,0,0,0,0,1412,0,0,0,0,0,0,
+0,0,0,0,526,632,0,0,0,0,0,0,235,144,0,0,0,0,0,940,0,0,0,52,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,309,196,0,0,0,0,0,1912,0,1290,0,686,0,0,625,0,0,0,0,0,0,0,0,0,0,0,412,0,
+0,0,0,43,0,0,0,0,11,967,758,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,0,0,0,0,0,0,0,0,0,
+873,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,890,0,0,2,0,0,0,0,0,0,0,0,1774,
+393,263,0,0,0,0,0,0,818,456,0,0,251,178,393,97,0,0,0,0,0,674,168,0,0,0,0,0,0,0,
+159,1639,0,0,0,0,0,0,0,0,59,934,0,191,0,0,0,0,346,165,0,877,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,128,0,0,0,0,0,0,1297,0,0,0,0,0,0,164,0,0,0,15,132,241,1073,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,228,324,53,0,0,910,0,0,0,0,0,0,0,0,734,705,
+217,73,0,0,0,0,0,0,0,0,636,389,0,1409,0,0,0,0,0,893,0,0,0,0,21,0,0,0,0,0,0,0,0,
+0,0,0,0,0,721,0,0,0,959,0,0,0,0,1433,0,0,0,0,0,0,0,0,0,0,0,0,174,189,0,0,0,0,0,
+0,0,0,0,0,22,2,0,0,815,354,0,0,0,0,425,0,411,60,13,1611,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1478,596,0,0,398,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,1159,0,0,0,0,0,
+592,223,0,0,0,0,0,0,0,245,64,0,0,0,0,278,0,604,0,0,1502,265,0,0,0,0,0,0,0,310,
+1763,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,1356,0,0,0,0,0,0,0,
+0,505,0,0,0,0,0,0,0,1000,0,0,966,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,839,0,0,0,0,0,0,
+0,0,0,0,0,0,0,637,0,0,0,0,0,0,0,0,0,0,0,0,0,0,590,0,0,0,0,280,0,0,0,1386,0,0,0,
+281,0,1064,0,0,0,0,0,917,0,0,15,555,0,0,1014,1883,0,0,0,965,0,0,117,33,0,0,0,
+801,0,0,0,0,0,877,0,824,0,0,0,0,0,0,0,0,0,0,0,365,0,0,0,0,0,0,774,7,0,430,0,0,
+231,360,0,0,0,0,0,0,0,0,822,740,0,0,929,1485,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,852,0,0,0,0,17,0,0,0,0,0,0,1001,0,0,0,0,35,831,0,0,384,457,0,0,0,1351,0,27,
+0,0,984,0,264,552,0,401,0,0,0,710,0,1211,0,0,11,205,0,0,0,0,0,0,0,0,0,0,0,0,5,
+579,0,717,0,0,1011,0,0,0,0,0,0,0,0,0,0,0,0,0,0,805,0,0,0,0,0,0,0,0,0,0,0,489,0,
+0,0,1024,0,0,0,0,0,0,0,0,0,892,0,0,0,0,0,0,0,0,0,0,0,0,473,0,0,0,659,864,0,0,0,
+0,0,0,152,819,0,51,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,229,0,0,0,0,674,0,0,0,0,0,
+0,0,0,0,770,52,79,0,0,0,1666,0,409,0,0,0,0,0,0,0,195,0,688,0,0,0,0,0,0,0,0,0,0,
+0,889,174,160,0,0,0,0,0,0,0,0,0,0,0,0,0,872,0,918,569,268,0,0,0,1224,0,1361,0,0,
+0,0,0,0,0,0,0,374,0,0,0,0,0,731,0,0,0,0,190,0,0,0,0,0,0,0,202,506,444,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,835,0,17,1526,0,0,0,0,0,477,0,0,
+994,1374,76,0,0,0,0,0,0,0,355,287,0,1389,0,0,0,0,0,0,455,384,0,0,0,264,0,0,0,0,
+0,0,0,0,0,0,0,0,1001,0,0,0,0,0,0,0,0,0,0,0,0,28,0,0,0,851,175,359,0,0,0,0,0,0,0,
+0,287,740,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+819,1402,0,0,0,0,0,0,174,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1649,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,655,573,0,0,0,0,0,0,0,0,128,351,0,0,0,0,0,0,
+0,0,0,0,0,918,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,687,0,0,0,0,0,0,0,0,0,1525,
+0,0,0,1009,0,0,0,0,0,0,0,340,0,0,0,0,0,0,0,0,0,0,861,0,176,0,0,0,0,0,0,0,0,0,96,
+985,0,615,0,0,0,0,0,0,0,1919,0,0,0,0,0,1131,0,0,0,0,0,0,0,247,0,0,0,0,27,23,0,0,
+0,0,0,0,0,0,38,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1015,0,0,0,0,0,1088,0,0,
+0,0,0,1585,0,0,0,0,227,0,0,0,478,360,0,0,0,95,0,0,0,0,0,0,699,0,0,0,26,0,0,0,0,
+1119,0,0,0,739,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,741,67,0,0,0,0,0,0,464,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42,0,96,0,0,0,26,342,0,0,0,0,0,0,203,0,0,449,0,
+0,0,0,0,0,0,0,0,0,256,311,0,0,0,0,0,0,758,0,0,0,0,0,0,0,0,827,0,0,0,0,581,64,0,
+1047,0,0,0,0,0,288,0,0,0,0,0,1375,0,0,0,0,0,0,0,0,0,0,0,1309,0,0,0,0,0,0,0,0,
+376,12,0,0,0,0,0,154,0,1520,0,1753,95,502,0,0,0,0,0,0,0,269,291,1197,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,1341,0,1017,0,0,0,0,0,0,0,
+0,857,1810,533,0,0,1453,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,836,211,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,19,0,156,0,0,0,0,1009,0,0,0,0,0,0,0,0,0,0,0,0,0,820,0,0,
+0,0,0,0,0,0,0,228,0,0,0,1131,0,1276,0,0,0,0,0,0,0,0,0,0,0,0,849,1792,0,0,389,
+291,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,525,0,0,
+0,453,0,0,0,0,666,0,0,0,422,0,355,0,0,0,0,165,0,260,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,865,0,0,0,0,0,0,0,1625,0,0,0,234,0,1383,0,0,0,0,0,0,0,0,306,0,0,0,802,1921,
+0,0,0,0,0,0,180,0,0,0,0,1312,814,0,0,0,0,0,0,0,0,0,0,707,0,0,0,1493,11,61,733,0,
+0,0,341,0,0,0,98,0,0,0,0,0,0,0,0,0,0,0,1014,0,0,0,0,0,0,0,142,102,0,0,30,0,0,
+823,0,1045,0,0,0,1930,0,1512,0,0,0,0,0,0,0,87,0,1243,245,0,0,0,0,0,0,0,48,68,0,
+0,0,0,0,0,0,0,126,77,625,938,0,0,351,0,0,0,174,1668,0,707,0,0,0,0,0,0,0,0,0,0,0,
+403,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,282,0,0,0,0,0,0,8,44,0,0,363,115,0,0,0,0,0,0,
+0,0,0,0,0,0,545,761,0,0,835,1254,0,0,0,0,930,1936,0,0,0,0,0,0,0,0,653,0,0,0,0,0,
+344,0,0,1483,673,185,0,0,460,93,753,478,0,0,0,0,0,1020,0,0,0,0,0,0,0,103,0,0,0,
+499,0,0,0,0,0,0,207,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,968,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,3,0,0,0,0,399,0,0,0,0,224,563,0,0,0,0,0,704,0,0,0,0,0,0,0,0,0,0,0,
+1559,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,861,0,0,0,0,946,333,746,0,0,0,0,0,
+0,0,910,0,0,0,0,0,0,0,0,0,0,0,0,0,652,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1393,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1514,0,0,0,0,201,0,510,717,0,0,528,0,0,0,0,
+20,0,0,0,1251,0,0,0,1163,0,0,0,307,0,0,0,0,0,1091,0,0,0,0,0,0,0,0,0,0,0,429,0,0,
+0,881,0,0,0,0,0,621,0,0,0,0,0,0,0,736,0,348,0,868,0,0,0,0,433,0,0,0,771,1495,0,
+0,0,0,215,0,0,0,0,0,124,0,0,0,0,0,0,0,0,0,0,0,55,0,0,0,0,0,0,0,112,62,0,856,270,
+0,572,0,0,0,0,939,0,0,0,0,0,0,0,352,0,0,0,0,0,0,0,0,0,647,0,0,0,0,10,0,0,0,0,0,
+0,0,220,0,0,0,0,0,0,0,0,0,0,0,0,0,464,0,0,109,0,0,0,1746,0,0,0,515,0,0,0,566,0,
+0,0,0,0,0,67,40,0,0,722,992,0,0,923,0,0,0,0,0,0,1145,0,0,0,0,0,0,0,0,0,0,0,568,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,247,0,0,0,0,645,0,0,328,0,0,0,0,0,0,0,0,0,0,0,0,
+1363,0,0,0,0,0,1280,0,0,0,0,0,0,0,0,0,0,7,28,360,162,0,0,0,0,0,0,0,0,0,0,0,764,
+0,0,833,862,0,856,0,0,0,0,0,0,736,92,0,0,948,1944,0,1479,63,590,0,0,0,1521,0,0,
+0,709,0,0,61,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,483,0,0,0,0,1213,
+0,0,0,0,29,1022,0,1712,0,466,0,0,0,0,0,0,0,0,0,0,0,0,0,731,0,0,0,0,0,0,171,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,241,0,0,0,0,0,0,0,0,0,0,0,964,2005,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1100,0,0,0,954,0,0,0,0,0,0,0,0,0,1958,0,0,34,549,994,0,0,449,
+137,850,0,0,670,146,0,0,0,0,518,159,0,0,0,0,0,0,0,0,151,0,0,1027,0,0,0,0,0,0,0,
+0,0,0,983,0,0,0,0,993,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,141,501,0,0,0,
+0,0,0,0,0,0,452,0,0,0,0,0,0,0,0,0,0,233,149,0,0,0,0,0,0,0,0,582,0,0,0,801,0,0,0,
+0,0,0,70,0,0,369,0,36,0,0,0,0,0,0,0,204,721,430,241,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1817,16,1078,1021,0,0,
+406,0,0,0,0,0,69,0,0,0,0,0,1830,0,0,0,824,0,0,0,0,0,0,0,0,0,826,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,816,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,717,1845,0,423,0,0,
+0,0,0,0,0,0,510,0,0,1048,0,0,0,618,0,0,0,520,0,0,0,0,990,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,321,0,0,0,0,0,0,0,1135,0,0,921,0,0,0,24,397,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,856,0,0,0,139,282,981,0,288,0,0,0,1890,651,56,0,0,0,0,0,0,0,
+0,261,0,0,0,0,0,0,0,0,0,0,0,617,1403,0,1205,0,0,563,0,0,0,0,0,0,0,0,333,0,0,0,0,
+0,369,0,0,0,0,0,0,0,0,0,622,0,0,0,1407,0,0,0,0,0,0,0,0,0,0,0,0,624,160,0,363,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,619,0,174,292,0,0,656,616,0,0,0,685,0,0,0,0,0,0,0,0,0,0,0,0,0,647,0,0,0,631,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1267,0,0,0,1797,0,0,0,1684,0,0,469,0,531,
+1230,73,0,0,0,0,0,0,0,0,0,268,0,0,0,0,0,102,558,109,65,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,595,0,0,0,0,0,374,1832,0,0,0,0,0,0,16,0,405,6,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,881,0,1495,0,0,0,0,0,0,0,0,0,142,0,0,0,0,0,0,0,0,0,0,21,466,23,
+257,0,0,0,0,0,0,77,404,0,0,0,0,0,0,712,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,860,
+1848,0,0,652,629,0,0,0,0,13,377,0,1842,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1501,0,
+0,0,1906,0,0,0,0,0,0,0,0,0,0,0,0,0,491,234,171,0,0,0,0,631,1186,0,0,0,0,0,0,0,0,
+0,0,0,0,931,0,170,0,0,0,0,0,0,0,0,0,0,1587,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+765,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,424,0,0,714,0,0,0,0,685,0,0,0,0,0,
+0,285,0,0,0,0,0,0,429,0,0,0,0,0,0,0,0,0,0,71,18,0,0,0,0,0,0,0,0,0,0,116,828,0,0,
+0,0,0,0,289,0,0,0,0,0,0,0,0,675,0,0,0,1424,0,0,0,0,0,647,0,0,0,1334,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,36,209,0,0,0,0,0,0,0,342,0,0,0,928,0,0,0,0,0,1838,118,856,654,
+318,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,915,895,454,0,0,513,1425,0,0,
+0,0,0,0,791,0,153,0,0,0,0,0,0,796,909,445,345,0,0,0,0,0,0,0,0,578,0,0,0,1387,0,
+0,0,555,0,0,0,0,0,0,766,0,0,0,0,0,0,0,0,0,0,541,0,0,0,0,0,0,0,0,0,0,0,0,0,880,0,
+0,0,0,0,1506,0,0,983,0,768,0,0,0,0,584,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,737,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,226,30,426,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,462,0,0,0,385,0,398,0,0,0,0,0,0,
+0,0,0,347,0,0,0,0,125,1259,644,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,469,0,0,0,0,0,
+1367,0,0,0,0,0,0,0,0,0,0,0,719,0,0,0,0,0,0,0,0,0,0,0,0,0,1423,0,0,0,0,0,0,0,0,0,
+749,0,0,0,0,546,645,0,0,0,0,0,0,277,0,0,1275,0,0,0,0,0,0,0,453,536,555,0,0,987,
+1107,0,0,90,0,0,0,0,0,0,0,0,860,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+257,0,1768,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1071,0,0,0,0,0,0,0,0,0,0,0,0,0,83,
+0,835,0,0,0,0,0,0,0,2006,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,696,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,95,1718,0,0,0,0,0,0,0,26,0,550,0,0,0,0,0,901,0,0,0,0,0,
+0,822,0,0,122,0,0,0,807,0,0,0,0,0,262,0,620,601,34,0,0,170,0,0,0,0,537,0,0,0,0,
+0,0,0,0,0,332,0,0,208,1909,182,261,0,0,0,1721,0,0,0,0,0,933,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,1609,0,895,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,812,0,0,942,1916,0,0,0,0,
+0,0,0,778,0,0,0,137,0,1314,0,0,0,0,0,0,0,1661,0,0,0,0,0,0,0,1591,0,0,0,0,0,0,
+820,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,89,0,1160,230,6,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,63,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1740,0,0,177,
+170,0,1961,0,0,0,0,0,0,0,0,0,0,0,0,91,0,17,44,0,0,0,0,0,0,0,0,0,270,0,296,0,0,0,
+0,0,0,0,1523,0,0,0,0,0,0,0,0,0,0,757,7,0,0,0,0,0,0,0,0,0,0,530,588,0,0,0,0,0,0,
+0,0,0,786,0,0,0,0,0,580,627,88,447,57,0,0,0,0,0,0,0,0,845,735,0,0,0,0,0,31,15,0,
+460,521,12,424,0,0,0,1302,0,0,0,0,0,0,0,595,0,0,0,13,548,97,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,1472,452,1767,0,0,0,0,0,0,0,0,0,0,115,0,0,0,0,0,0,1543,0,1111,0,0,0,0,
+1,0,359,488,0,267,0,0,0,1983,0,0,0,0,0,0,0,1155,0,1575,0,1438,31,0,0,377,101,0,
+0,0,0,0,0,0,0,0,0,0,0,0,476,0,0,0,0,0,0,0,0,2023,0,0,0,0,0,1836,0,0,0,0,35,843,
+0,0,0,0,0,0,0,554,0,0,0,536,625,207,0,1371,0,0,0,424,785,336,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,896,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,750,0,0,0,0,238,0,0,
+0,0,0,383,0,0,0,0,0,0,0,0,603,725,11,0,0,0,0,0,0,0,0,0,476,0,0,0,0,0,1552,0,0,0,
+0,0,0,0,680,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,435,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1431,0,0,13,112,0,0,356,0,0,0,0,0,0,0,0,0,0,1963,0,0,0,1244,18,0,0,0,0,0,0,867,
+0,0,0,0,0,0,50,708,73,592,0,502,0,0,0,0,0,0,161,347,0,0,0,0,470,33,0,246,571,10,
+0,465,614,0,237,0,0,0,0,0,24,18,0,506,0,0,0,0,0,0,33,309,0,0,0,0,0,0,0,0,0,0,
+140,0,0,0,0,1056,0,0,0,1704,0,0,0,0,0,0,0,1036,0,0,0,0,0,0,0,0,0,1315,432,86,
+264,524,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,107,0,0,0,0,0,123,927,0,0,957,1149,0,0,
+0,0,0,778,0,502,196,0,0,0,0,1312,0,0,0,0,0,0,0,855,0,0,0,0,0,0,0,0,0,0,45,1400,
+0,0,0,1003,0,0,0,0,0,1097,0,0,0,0,0,0,0,0,545,612,0,0,0,0,0,0,0,0,0,0,0,0,54,0,
+0,0,0,172,0,0,0,1029,0,0,0,0,0,0,0,0,0,568,0,0,0,732,617,0,0,974,94,989,733,0,0,
+0,0,0,0,1789,0,0,665,2015,0,0,0,0,0,0,806,287,0,0,0,0,0,1539,0,0,0,0,0,0,0,0,0,
+0,182,1563,0,0,0,0,0,0,0,0,0,484,0,0,0,0,0,1623,0,0,0,0,0,0,0,0,878,1833,0,1569,
+0,0,0,0,0,0,0,0,93,0,715,994,0,0,0,0,0,63,0,591,0,0,0,0,0,0,0,749,0,0,0,0,547,
+366,0,0,0,1747,0,0,0,0,0,0,0,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1463,0,772,
+893,0,0,0,48,0,0,941,0,0,690,1785,106,440,0,0,0,0,0,0,0,0,0,0,32,0,332,216,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,852,0,
+0,416,564,0,918,0,1764,0,0,3,0,0,274,0,0,0,0,501,0,0,0,0,0,0,0,851,743,0,49,0,
+879,0,0,47,0,0,0,0,0,0,865,0,1202,0,0,0,0,0,0,47,272,0,0,0,0,0,0,0,0,0,0,0,1455,
+0,0,0,0,891,1911,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,761,0,0,0,0,0,0,0,0,0,407,0,
+183,0,0,490,0,0,0,0,0,0,0,35,731,0,0,0,0,0,0,0,819,0,0,0,0,0,0,0,0,0,0,0,0,0,
+575,0,0,0,0,45,818,0,0,77,222,0,0,0,0,849,1880,0,0,0,633,0,1308,0,0,0,0,0,0,0,0,
+0,0,86,0,0,0,0,0,0,0,0,0,0,0,0,0,0,817,0,0,0,0,0,0,0,0,0,882,0,0,0,914,0,0,0,0,
+0,0,0,0,0,0,865,0,0,426,399,58,0,0,0,0,0,0,538,102,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,876,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,139,566,0,63,12,0,0,0,
+0,0,0,0,0,0,0,0,0,0,3,114,0,0,0,0,0,0,0,0,576,0,0,0,0,0,0,0,0,933,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,692,0,0,0,0,0,0,0,0,0,0,0,0,752,0,0,0,0,
+0,0,0,0,375,0,1011,0,0,96,0,0,0,0,0,0,0,0,0,148,0,0,0,0,0,0,0,0,0,0,0,337,56,
+666,0,246,394,0,0,0,0,0,0,0,0,437,0,0,0,506,0,0,0,0,1003,0,1163,0,328,0,0,0,0,0,
+0,0,0,1000,0,0,0,0,0,744,101,0,0,0,0,0,726,0,0,176,0,146,9,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,839,0,0,0,0,0,0,223,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,246,1931,29,0,0,1771,0,0,0,0,0,846,6,157,0,0,0,0,0,0,0,0,0,875,0,0,477,
+773,177,639,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1747,0,0,0,0,158,873,0,659,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,391,0,0,0,0,0,0,0,0,0,0,0,0,668,883,0,78,628,0,0,0,
+0,0,0,0,0,0,0,0,0,1460,0,962,0,0,0,0,0,460,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,199,0,
+0,0,388,474,0,271,0,333,608,0,0,0,0,0,0,49,0,988,0,707,617,0,0,0,0,0,0,0,756,0,
+0,0,0,0,1583,0,0,0,0,0,0,0,0,0,0,285,0,0,0,0,0,0,0,0,0,0,0,0,0,0,344,0,0,0,0,0,
+0,0,0,515,1709,0,0,0,0,0,0,0,0,404,0,0,0,0,500,0,0,0,0,0,0,0,0,0,68,216,0,0,0,0,
+0,0,0,488,353,0,0,177,236,0,0,458,490,0,0,0,0,0,0,756,1504,0,757,0,1735,0,0,108,
+598,0,0,0,0};
+BROTLI_INTERNAL const uint8_t kStaticDictionaryHashLengths[32768] = {
+8,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,12,0,0,0,0,4,22,5,0,
+4,0,0,0,0,0,0,0,0,0,0,0,0,14,6,0,0,0,5,0,0,0,0,0,0,0,7,13,0,0,4,0,0,0,0,0,0,0,0,
+0,6,0,0,0,0,8,0,0,0,0,0,0,7,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,4,0,0,0,4,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,10,4,0,5,13,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,8,7,0,0,9,0,8,0,0,0,0,0,0,6,0,
+0,9,0,0,0,11,0,0,6,8,7,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,6,8,0,0,0,0,0,
+0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,9,0,0,0,8,4,13,7,0,0,0,0,0,
+7,0,5,0,0,0,0,8,5,0,5,0,0,8,7,0,0,0,0,0,0,0,0,0,0,9,0,0,0,8,0,0,0,10,4,0,5,0,4,
+0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,8,7,0,4,9,4,0,0,0,0,0,0,
+9,0,0,0,8,5,0,0,0,6,0,0,0,0,0,0,0,0,0,7,18,0,0,0,0,4,9,0,0,4,0,6,0,0,0,6,0,6,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,5,8,7,0,0,0,
+0,9,0,0,0,0,0,0,0,8,6,10,6,0,0,0,4,0,6,8,6,0,0,0,4,0,0,0,0,0,5,0,0,0,6,0,0,0,0,
+10,0,12,7,0,0,0,0,0,4,0,0,0,0,0,5,0,0,8,7,0,0,0,0,0,0,0,0,9,5,0,0,0,0,0,0,0,0,0,
+0,0,0,0,6,11,0,0,0,0,0,0,0,0,0,8,7,0,0,10,0,0,0,0,0,0,0,0,6,10,0,17,0,8,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,8,6,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+7,0,0,11,4,0,5,0,0,0,0,0,0,0,0,0,0,10,5,0,6,8,5,0,0,0,0,0,0,0,0,0,0,11,5,0,0,0,
+0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,9,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,8,7,0,0,0,0,0,
+0,0,0,0,0,0,5,0,0,0,6,0,0,10,0,0,0,20,0,0,0,0,0,0,0,0,6,9,5,0,0,0,0,10,4,8,0,0,
+4,13,0,0,0,0,0,0,0,9,0,9,0,0,0,0,0,0,0,0,0,0,0,0,4,8,6,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,12,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,12,5,0,0,10,4,10,7,13,
+0,0,0,0,0,0,0,0,6,0,6,0,6,0,0,0,0,0,0,19,0,0,4,12,6,9,0,0,0,0,4,0,4,11,0,0,0,0,
+0,0,0,12,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,4,0,0,0,0,0,0,0,0,0,6,0,0,0,0,
+0,5,0,0,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,9,6,0,0,0,0,0,4,0,4,0,0,0,0,0,0,0,0,0,4,0,0,0,
+6,0,0,0,0,0,0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,6,0,0,
+0,0,0,5,0,0,0,0,14,4,0,0,0,4,12,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,6,0,
+0,0,0,0,0,12,0,9,6,0,0,0,0,13,0,0,5,0,0,0,0,0,4,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,13,0,9,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,5,0,0,0,6,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,8,7,8,4,0,0,0,0,0,0,0,0,0,0,0,7,0,7,0,0,0,4,0,
+0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,6,8,4,0,0,0,0,0,6,0,7,0,
+0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,7,0,0,0,0,0,0,9,5,0,0,
+0,0,0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,9,4,0,0,0,0,0,0,0,4,
+12,5,11,0,0,0,0,0,0,0,0,0,8,7,0,5,0,0,8,7,0,5,0,0,0,0,8,0,0,0,0,7,0,4,10,0,0,0,
+0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+13,5,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,0,14,5,0,0,0,7,0,0,10,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,6,0,4,0,5,0,0,0,0,8,5,0,0,0,0,0,0,9,5,9,0,0,0,0,0,0,0,0,6,9,0,
+0,4,0,0,0,7,0,0,0,6,0,0,10,4,0,0,0,0,0,6,0,0,10,0,0,0,8,5,0,0,0,0,0,0,0,0,10,0,
+0,0,0,0,18,4,12,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,8,7,0,0,0,
+0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,4,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,
+0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,8,0,0,0,0,0,0,6,0,0,0,4,10,5,0,0,0,0,0,0,0,0,0,0,
+0,4,8,7,0,0,8,6,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,
+0,0,0,8,6,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0,
+0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,8,7,0,0,0,0,8,0,12,6,0,6,0,0,0,0,9,7,11,7,0,0,0,
+0,0,0,0,0,0,0,0,0,11,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,10,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,
+0,0,0,6,0,0,0,7,0,4,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,14,0,0,0,0,0,8,4,0,4,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,20,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,12,5,0,7,0,5,0,0,10,0,0,7,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,6,0,4,9,7,0,0,0,
+0,0,7,0,0,0,0,0,0,10,0,9,0,9,0,0,0,0,0,0,0,0,4,9,0,0,0,0,6,0,0,0,0,0,0,0,0,11,4,
+0,6,0,0,0,0,0,0,8,0,8,0,0,0,0,0,0,0,0,0,0,4,0,0,0,5,0,0,0,0,0,0,0,0,13,6,0,0,11,
+0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,6,18,0,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,
+0,5,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,6,0,0,0,0,9,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,11,
+4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,4,0,0,0,0,8,
+6,0,0,0,0,0,0,9,6,0,0,0,0,0,4,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,0,
+0,6,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,6,0,6,0,0,10,6,0,0,0,7,0,0,8,0,8,7,0,
+0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,0,0,0,0,5,0,0,18,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,
+0,0,0,8,7,0,0,0,0,0,0,0,0,12,0,12,0,0,0,11,6,0,5,0,0,12,0,12,5,0,7,11,6,0,0,11,
+0,0,0,12,0,0,4,12,7,8,6,0,0,0,0,8,5,0,0,0,0,0,0,0,4,11,0,0,6,0,7,0,0,0,0,0,0,0,
+5,0,6,0,0,0,0,8,0,10,0,0,0,0,0,0,0,0,0,0,0,9,7,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,
+0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,0,0,10,0,0,5,0,0,12,6,0,0,0,0,0,0,10,6,0,0,0,0,8,
+6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,5,0,0,0,0,11,0,10,6,0,0,8,6,0,0,0,6,0,7,10,6,0,
+0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,10,7,0,0,0,0,
+10,6,0,0,0,0,0,0,8,5,11,0,8,4,0,0,0,4,0,0,0,0,9,4,8,0,0,0,0,0,0,0,11,6,0,0,0,0,
+10,7,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,7,0,0,0,0,9,6,0,5,0,7,0,0,0,0,0,7,0,0,11,0,0,
+0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,
+0,0,0,0,13,0,8,6,13,0,0,0,11,7,0,7,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,6,0,0,9,6,0,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,5,9,0,0,0,0,0,0,0,0,0,0,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,9,7,0,7,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,
+5,11,5,0,0,0,0,0,0,0,0,0,4,0,7,0,6,0,0,0,6,20,0,0,0,10,7,0,5,14,4,0,0,0,0,0,0,0,
+0,0,6,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,
+0,0,6,0,4,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,11,6,15,0,0,0,0,0,
+10,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,7,0,0,0,0,0,0,0,0,9,7,13,0,0,0,0,0,
+0,7,0,0,8,6,0,0,0,0,0,0,0,0,9,4,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,5,0,0,0,0,0,0,0,0,0,0,0,0,8,5,0,4,0,0,0,0,0,0,0,0,0,0,12,6,8,0,12,0,0,7,0,0,0,
+0,0,5,10,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,
+14,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,8,7,10,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,18,6,
+14,7,0,0,0,0,0,0,0,0,11,6,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,11,7,0,0,10,7,0,0,0,6,8,6,0,0,0,0,0,0,0,6,0,0,
+19,0,0,0,9,5,0,0,0,0,0,0,11,7,0,0,0,7,0,6,0,0,11,0,0,0,0,4,8,0,0,0,0,0,0,0,0,6,
+0,0,0,0,0,6,0,0,8,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,
+0,7,0,0,0,7,15,0,0,5,0,0,0,0,10,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,7,0,0,
+0,0,0,0,0,0,9,6,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+11,7,0,0,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,0,4,0,0,0,4,0,4,0,0,0,0,0,0,0,0,0,6,0,0,0,0,11,6,0,0,8,5,14,0,0,4,0,0,0,7,
+17,0,0,0,0,0,0,0,13,5,0,0,0,0,0,5,0,0,0,5,0,0,0,0,16,6,0,4,0,0,0,0,0,0,12,0,0,0,
+0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,5,0,5,0,6,10,0,12,0,0,0,0,0,0,0,0,7,0,0,0,0,8,4,
+0,0,0,0,0,0,0,0,0,0,8,7,0,0,8,0,0,0,8,0,0,6,0,7,0,0,0,5,0,6,0,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,22,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,
+0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,18,0,0,0,9,4,0,0,8,0,9,7,0,0,0,0,0,0,8,6,0,0,0,0,
+0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,9,7,0,0,0,6,0,0,14,0,0,0,0,
+0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,7,10,4,
+0,6,0,0,0,0,0,0,8,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,9,6,0,0,0,0,0,0,
+0,0,11,6,12,7,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,0,9,6,11,6,0,0,0,0,9,5,0,0,0,0,0,0,
+0,6,8,5,0,0,0,0,8,0,10,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,
+5,10,7,0,0,0,5,8,7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,4,8,7,0,0,0,6,0,0,
+0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,22,
+0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,5,0,0,0,0,0,0,0,
+0,0,0,0,0,17,0,0,6,0,6,12,4,19,6,0,0,0,0,16,0,0,0,0,7,15,7,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,4,10,4,0,0,8,7,0,7,0,0,9,
+4,0,6,0,0,0,4,0,5,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,7,10,0,0,0,0,0,11,7,0,0,
+0,0,12,6,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,
+0,0,0,0,0,0,0,0,0,10,4,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,8,7,0,0,
+0,0,0,0,0,6,0,0,0,4,0,0,11,4,0,0,12,7,0,0,0,0,9,0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,
+4,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,9,4,0,6,0,0,0,0,0,4,
+0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0,0,0,5,0,0,0,0,0,0,0,0,0,7,9,6,0,7,0,
+0,0,0,0,0,0,6,0,0,0,0,8,6,0,0,0,0,10,6,11,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,5,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,5,0,4,8,0,0,0,0,0,9,7,0,0,0,0,0,0,
+13,5,0,0,0,0,8,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,5,0,0,11,7,0,0,0,0,0,0,8,6,0,
+0,0,0,0,7,0,4,0,0,0,0,0,0,0,5,0,6,0,5,0,0,0,0,0,0,0,0,0,0,0,0,10,4,9,0,0,0,0,0,
+0,4,0,0,0,0,10,5,10,7,0,0,0,0,0,0,0,0,16,7,0,0,0,0,0,7,0,0,0,0,11,0,0,0,0,0,0,0,
+0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,5,0,4,0,0,0,7,0,0,0,0,0,0,13,0,0,
+0,0,0,0,0,0,0,0,7,0,4,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,13,7,0,7,0,4,16,0,0,0,0,6,8,7,9,7,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,
+0,6,0,0,8,5,0,4,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,11,7,0,0,11,
+0,0,0,0,0,9,5,0,4,0,0,0,0,9,7,8,6,0,0,0,0,0,0,10,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,
+0,7,0,0,0,0,0,0,0,0,0,0,0,4,10,6,0,7,0,0,0,0,0,0,0,5,0,0,0,0,0,0,10,7,10,0,0,0,
+0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,7,0,6,8,7,12,4,0,0,0,0,0,0,0,5,14,
+0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,
+6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0,0,20,4,0,0,0,7,0,6,0,0,0,0,0,0,0,0,8,0,
+0,6,15,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,12,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,5,0,0,0,0,0,0,8,6,0,0,18,0,0,0,10,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,9,6,0,
+6,0,0,0,0,0,0,0,0,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,9,0,9,0,0,4,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,9,5,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,10,0,0,0,0,7,0,0,0,0,0,0,0,0,0,7,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,0,8,0,0,0,16,0,0,0,0,0,0,0,
+0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,8,0,0,0,11,0,0,0,0,0,0,0,0,0,0,
+6,0,0,0,0,11,0,0,0,9,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,7,0,7,0,6,
+0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,
+0,0,0,0,0,0,0,6,0,0,18,0,8,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,7,0,4,0,0,0,
+0,0,0,0,0,0,0,8,0,0,0,0,0,16,0,0,0,0,0,16,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,18,0,0,0,0,0,0,0,0,0,9,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,4,0,
+0,0,0,0,0,0,0,9,4,0,0,0,0,12,5,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,12,5,0,0,0,0,0,0,0,5,0,0,10,6,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,9,0,0,0,11,0,0,6,0,6,0,0,
+0,7,0,0,0,0,0,0,8,0,0,0,0,6,0,0,0,0,0,0,19,0,0,0,12,0,9,0,0,0,0,0,10,7,0,0,0,0,
+0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,16,7,12,
+0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,6,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,10,5,0,0,0,0,0,0,0,4,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,7,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,0,4,0,0,9,0,0,0,8,0,12,4,0,0,0,0,
+0,4,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,5,0,
+0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,0,0,8,6,0,6,0,0,0,0,0,0,
+0,4,0,0,0,0,0,6,0,0,9,0,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,10,6,0,0,0,0,8,
+6,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,7,0,6,
+10,7,0,0,10,5,11,6,0,0,0,0,0,7,16,0,0,0,0,6,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,5,0,0,0,7,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,
+0,0,0,0,0,8,7,0,0,0,0,11,6,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+8,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,12,7,0,7,0,0,0,
+0,0,0,0,6,0,0,0,0,9,0,0,0,23,0,0,0,0,0,10,5,0,0,0,0,0,0,0,0,0,4,0,0,11,7,10,0,0,
+0,0,0,0,0,0,0,0,0,0,6,0,0,8,7,0,7,0,0,8,7,8,0,0,0,0,0,0,0,0,0,0,0,14,5,0,0,0,0,
+0,0,0,0,18,6,8,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,11,0,0,0,9,7,12,6,0,0,0,0,0,0,0,0,
+0,0,12,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,7,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,6,8,7,0,0,0,6,10,0,0,0,9,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,6,
+10,7,0,0,0,7,0,0,8,4,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0,
+0,0,0,8,7,8,6,0,0,11,7,10,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,4,8,7,0,0,0,0,0,0,0,0,
+0,5,0,0,13,0,0,0,0,5,0,0,9,7,0,0,0,0,0,0,0,4,0,0,11,0,0,7,0,0,0,0,0,0,0,0,0,6,0,
+0,0,0,0,0,12,7,19,0,8,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,10,6,8,0,0,0,0,0,0,0,0,0,0,
+6,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,7,0,0,12,0,0,0,0,6,9,6,
+14,0,0,0,0,0,0,6,0,5,0,0,8,7,0,0,0,6,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,4,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,0,
+7,0,0,10,0,9,7,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,12,6,0,0,0,0,0,5,0,6,0,0,0,0,
+0,0,0,0,0,0,0,6,0,0,0,0,9,7,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,0,0,0,11,7,0,0,13,7,
+0,0,0,0,0,0,0,0,12,0,0,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,6,11,5,0,5,13,0,8,0,
+0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,11,5,
+9,6,0,0,0,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,10,0,0,0,8,5,0,0,9,0,0,0,8,7,9,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,0,
+0,11,0,13,6,0,0,9,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,
+0,0,0,0,0,5,21,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,5,0,0,0,0,0,0,0,0,10,0,8,0,
+0,6,0,0,0,4,0,0,9,0,0,0,0,0,0,0,0,0,0,4,0,0,8,6,0,6,0,7,10,0,8,4,0,4,0,0,0,0,0,
+5,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,6,12,0,0,7,0,0,0,5,0,0,
+0,0,0,0,0,0,0,6,0,0,8,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,24,7,0,0,0,0,0,0,0,0,0,
+7,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0,
+0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,4,12,0,0,7,0,0,0,0,0,5,0,0,0,0,0,0,0,0,15,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,8,0,0,0,
+0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,9,0,9,6,
+0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,8,4,0,7,0,0,0,0,0,0,0,0,
+22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,4,0,7,0,0,21,7,0,7,9,6,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,8,0,0,6,
+0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,23,0,0,0,0,7,0,0,0,
+4,0,0,0,0,0,0,0,0,9,4,11,7,0,5,0,0,0,0,11,0,0,4,20,0,0,0,0,0,0,0,0,0,0,0,11,5,0,
+7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+21,0,0,0,0,0,0,7,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,11,6,0,0,0,0,0,0,0,0,9,6,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,5,0,4,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,
+0,0,0,10,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,7,0,0,11,7,0,0,0,0,0,0,0,4,
+0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,8,7,0,
+0,0,0,0,0,0,0,0,6,0,0,21,6,0,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,14,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,8,0,0,7,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,
+0,0,0,8,7,0,0,11,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0,7,13,7,10,4,0,
+0,0,6,0,0,0,0,0,0,0,0,0,5,10,0,0,0,0,0,0,5,0,0,0,7,0,0,0,0,0,0,8,4,0,0,0,0,0,6,
+0,0,0,0,0,0,0,0,0,0,12,7,0,6,0,0,10,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0,
+0,0,0,0,7,0,0,8,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,10,5,0,6,0,0,0,0,0,4,0,0,0,0,
+0,0,0,0,0,4,0,0,0,0,9,0,11,4,0,0,0,6,0,0,0,5,12,7,0,5,0,0,0,0,0,4,0,0,0,7,0,0,0,
+0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,13,6,10,0,0,0,17,0,0,4,0,0,0,0,0,6,0,4,0,5,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,11,7,0,0,0,7,0,0,0,6,0,0,0,0,0,0,
+0,6,0,4,0,0,0,0,8,0,0,0,0,5,0,0,0,0,0,4,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,9,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,0,0,
+0,0,7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,16,4,0,0,11,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+8,7,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,8,6,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,
+7,0,0,0,0,0,0,9,0,0,0,0,0,0,0,12,5,10,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,
+5,18,7,0,0,14,0,0,0,0,0,0,0,9,4,0,7,0,0,0,0,0,0,0,5,0,0,0,6,0,0,0,6,0,0,0,0,0,0,
+8,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0,7,0,0,0,0,0,0,11,0,0,0,
+10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,14,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+11,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,14,6,0,0,0,0,11,4,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,10,7,0,6,0,0,9,0,9,5,0,0,0,0,0,
+0,0,0,10,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,8,5,0,0,0,0,0,0,0,0,0,0,11,4,0,6,
+0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,12,4,0,6,8,6,0,0,0,0,0,0,0,0,0,0,8,0,0,5,0,0,0,0,0,0,0,7,0,0,13,0,0,0,0,0,0,0,
+0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,12,7,0,6,0,0,0,
+0,0,0,0,0,0,0,0,0,13,4,0,7,0,0,0,7,0,7,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,0,0,0,0,
+9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,10,6,21,5,0,0,0,0,8,0,0,0,0,4,0,
+7,0,0,0,0,0,0,11,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,4,0,0,0,0,0,0,
+0,7,9,6,11,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,7,10,0,0,0,0,0,0,6,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,19,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,18,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,9,4,10,4,0,7,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,9,7,9,7,10,4,0,7,0,0,0,0,0,0,0,6,12,0,
+0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,
+0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,8,0,
+0,0,0,0,0,5,0,0,8,7,0,0,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,
+0,0,0,0,4,0,0,8,0,0,6,0,0,0,7,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,7,9,7,0,0,0,4,8,0,0,0,0,6,11,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,10,0,0,0,0,0,0,0,13,4,0,0,
+12,6,0,6,0,0,0,0,8,7,0,7,0,0,0,0,0,6,0,0,0,0,0,0,12,6,0,4,0,0,0,0,0,0,0,0,0,0,9,
+7,22,0,0,0,0,4,0,0,0,0,0,6,0,0,0,4,0,0,9,0,0,6,0,0,24,7,0,7,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,10,6,0,5,0,0,0,0,0,0,0,7,0,0,8,0,0,0,0,0,0,0,10,5,0,0,0,0,0,0,0,0,0,7,0,
+7,0,0,0,0,0,0,13,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,
+0,0,0,0,0,7,12,0,9,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,8,0,0,0,0,0,0,0,0,4,0,0,0,7,0,
+0,0,0,8,7,0,0,0,0,0,0,0,0,0,4,18,0,0,0,0,0,10,0,0,5,0,0,11,0,0,0,0,0,0,5,0,6,0,
+0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,
+4,0,0,0,0,0,0,10,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,
+0,0,0,5,8,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,20,7,0,0,0,0,0,0,0,0,0,0,0,4,9,0,12,
+6,8,0,14,7,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,10,0,0,
+0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,9,6,0,7,12,0,0,0,0,4,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,
+0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,4,0,0,9,0,
+12,6,0,5,0,0,0,6,0,4,0,6,0,0,0,0,0,0,0,0,10,7,0,0,0,0,0,0,8,0,0,0,0,4,0,0,0,0,
+10,0,0,0,0,0,0,0,8,6,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,0,0,0,0,0,0,0,0,0,0,0,
+6,0,0,12,6,20,5,0,0,0,0,0,0,0,0,0,0,0,0,9,5,0,5,0,0,0,6,13,7,0,0,0,0,15,6,0,0,0,
+6,0,0,13,7,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,5,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,
+10,6,0,0,0,0,0,6,0,0,0,0,9,0,0,0,0,0,19,6,0,0,0,0,0,0,0,0,0,0,13,0,11,0,0,0,0,0,
+0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,0,10,0,0,6,0,0,0,0,8,0,0,
+0,9,0,15,4,0,6,0,0,0,0,0,6,12,0,0,0,0,0,0,0,14,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,
+0,0,0,0,0,8,7,0,0,0,0,0,6,10,0,0,0,0,0,0,0,0,7,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,10,5,0,0,0,0,8,0,0,0,0,4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,6,12,0,0,0,10,7,0,5,0,6,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,6,0,4,0,0,0,0,0,7,0,0,0,0,0,0,0,4,9,6,0,0,0,7,0,0,0,0,0,0,0,0,8,6,0,0,
+0,0,0,0,0,4,12,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,7,0,
+0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,12,6,0,6,9,4,0,0,8,4,0,6,
+0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,8,0,0,6,13,4,0,5,8,0,0,0,0,0,0,0,8,0,0,0,10,5,0,0,9,0,0,0,0,0,0,6,0,0,
+24,0,0,0,0,0,0,0,8,0,0,7,0,0,12,0,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,
+6,8,0,10,0,9,7,0,0,0,5,0,0,0,0,0,0,0,4,8,5,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,4,0,0,0,0,0,6,0,0,0,0,0,5,0,0,0,0,8,0,0,
+0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,10,4,0,0,0,0,0,0,0,6,0,0,0,4,20,0,0,7,
+10,6,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,9,6,0,0,0,0,0,0,0,4,
+12,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,9,4,0,5,0,0,
+0,0,0,0,0,6,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,6,9,0,0,0,0,7,0,0,0,0,0,6,0,5,0,0,0,0,0,0,0,0,9,0,0,0,
+0,6,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,17,7,0,0,13,6,14,6,0,0,0,0,
+8,0,0,0,0,0,0,7,12,7,8,7,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,4,0,0,0,0,0,4,0,
+0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,12,4,0,0,10,7,0,0,0,
+0,0,0,10,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,12,0,0,6,
+0,0,0,0,0,0,0,0,8,7,12,0,0,0,0,0,0,6,0,6,0,4,0,0,18,6,0,0,0,6,0,0,0,0,0,6,10,6,
+0,0,0,0,0,0,8,7,14,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,
+0,0,0,8,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,7,0,0,10,5,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,
+0,0,9,4,8,0,0,0,0,0,0,4,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,4,0,0,0,0,
+0,6,0,0,9,7,0,0,0,0,0,5,0,0,0,0,8,7,0,0,14,0,0,0,0,6,0,0,0,0,0,0,9,6,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,5,0,7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,
+0,0,0,6,0,0,0,6,0,4,0,0,0,0,0,4,0,0,0,0,12,0,0,7,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,
+0,12,0,16,6,0,0,0,0,0,0,11,7,0,4,8,7,0,0,0,0,0,6,0,0,0,0,16,0,0,0,0,6,0,0,0,0,0,
+0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,10,7,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,
+0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,13,4,0,0,10,0,0,0,0,0,0,0,0,0,19,0,0,0,
+0,0,0,0,0,0,0,0,0,0,8,6,22,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,
+5,0,0,0,0,0,5,0,0,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0,0,18,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,14,7,0,0,11,5,0,0,0,5,0,0,0,0,12,5,0,0,0,0,0,0,0,0,0,0,24,6,0,0,
+0,7,0,4,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,7,0,4,0,0,0,0,8,7,0,0,
+9,6,0,0,14,5,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,12,6,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,7,0,0,0,5,0,0,
+0,0,12,7,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,6,0,0,13,7,0,0,0,0,0,0,14,0,11,4,0,
+0,0,4,0,0,0,0,14,5,0,0,0,0,0,5,11,5,0,0,0,0,22,5,0,0,0,0,0,7,0,0,0,0,0,4,0,0,0,
+4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,17,0,10,0,0,0,8,0,0,0,19,
+5,18,7,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,10,6,0,6,0,0,0,0,10,4,0,4,0,
+0,0,0,0,0,14,7,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,0,9,6,12,0,0,6,0,0,0,0,0,0,0,0,
+12,0,10,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,4,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,5,13,0,9,7,0,0,0,0,0,0,0,0,0,0,0,7,9,7,0,0,8,0,0,0,0,0,
+22,0,0,0,0,0,0,0,23,6,14,0,0,0,0,0,0,7,0,0,0,0,11,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,
+0,0,10,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,8,5,0,0,0,0,0,0,0,0,0,7,11,6,21,0,0,0,0,0,
+0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,
+0,0,0,0,0,0,0,4,9,7,0,0,0,0,0,0,12,0,0,0,0,7,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,9,
+0,0,0,20,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,11,7,0,0,0,0,0,0,0,6,15,0,0,
+0,0,0,0,0,0,0,0,0,0,0,12,4,0,5,0,0,0,0,0,0,11,7,17,6,0,0,0,0,0,0,15,6,0,7,0,0,0,
+0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,6,0,5,
+0,0,11,0,11,7,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,
+17,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0,8,7,9,6,0,0,14,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,
+8,7,0,4,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,
+0,0,0,5,0,4,0,0,8,7,0,6,12,5,0,7,18,7,0,0,8,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,
+10,0,11,0,0,0,0,0,0,0,0,0,0,0,9,0,0,4,0,6,0,7,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,
+7,0,0,0,0,8,0,0,0,15,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,0,0,
+0,0,6,0,0,0,0,23,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,5,0,0,0,0,0,0,8,6,0,0,
+0,0,0,0,12,7,9,7,0,0,10,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,9,0,8,7,0,0,0,
+6,0,6,0,4,0,5,0,0,0,0,0,5,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,7,10,5,0,0,11,6,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,4,9,7,0,
+0,0,0,11,7,0,0,0,0,0,5,0,0,0,7,0,0,0,0,23,6,11,4,0,0,0,0,0,0,9,0,0,0,10,6,0,0,0,
+0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,10,6,0,0,0,7,0,0,
+0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,
+6,11,7,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0,6,0,0,0,5,0,6,0,6,0,0,0,0,0,0,0,0,0,0,
+0,6,0,0,0,0,8,7,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,4,10,0,8,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,10,6,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,
+0,0,0,0,0,0,10,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,11,6,0,4,0,0,14,5,0,7,0,0,0,0,0,6,16,0,0,0,0,0,0,0,10,0,0,7,15,0,0,0,11,7,0,0,
+0,0,0,0,0,0,0,0,8,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,5,0,0,0,
+0,8,0,0,6,0,0,0,0,0,0,9,5,0,0,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,6,0,
+0,0,0,0,0,0,7,0,0,0,0,15,7,0,0,0,0,8,0,0,0,14,0,0,0,0,0,0,0,16,7,0,0,0,0,0,7,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,12,6,11,7,
+9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,
+7,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,12,0,10,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,8,0,0,5,8,7,10,6,0,0,0,7,0,0,0,0,12,6,
+0,0,9,0,0,0,12,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,10,0,0,0,10,5,0,0,0,0,0,0,9,6,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,6,0,0,9,5,0,4,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,9,0,0,5,0,0,8,7,8,
+6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,10,0,9,4,0,0,0,0,0,0,0,6,
+11,0,0,0,0,0,0,0,0,0,0,0,8,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,8,7,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,
+0,0,0,10,0,0,0,8,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,
+0,0,8,4,0,5,0,0,0,0,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,22,0,0,0,0,0,0,0,8,5,0,0,0,
+0,0,0,0,7,0,0,0,6,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,0,6,0,7,0,0,0,0,
+20,0,0,0,0,0,0,0,0,0,0,7,9,0,0,0,0,0,0,6,0,6,0,7,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0,
+0,0,0,14,7,0,0,0,5,0,0,22,4,10,0,0,0,0,0,0,4,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,11,5,13,0,0,0,0,0,0,0,0,0,8,0,0,7,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,10,7,0,
+0,0,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,0,7,14,6,0,0,0,0,9,5,
+0,0,0,0,0,6,0,0,0,5,10,0,8,6,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,6,0,0,8,4,0,6,0,
+0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,
+14,0,0,5,0,0,18,0,8,4,0,6,0,0,20,0,13,0,0,0,0,7,0,4,0,0,0,0,0,4,8,4,0,0,0,0,0,6,
+0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,4,0,0,0,0,0,0,0,0,14,0,0,0,0,0,9,7,0,0,9,0,0,0,0,
+0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,20,0,14,0,0,4,0,6,8,5,0,0,0,0,0,7,0,0,0,0,0,0,
+0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,10,4,12,7,0,6,0,0,9,7,10,5,
+0,0,8,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,0,0,18,0,0,0,14,7,0,0,0,0,0,4,
+0,0,0,0,0,0,17,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,4,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,
+0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,8,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,5,0,7,0,0,0,0,0,
+7,0,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,8,5,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,5,0,
+0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,23,0,0,7,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,0,0,0,0,0,0,12,7,8,4,0,0,0,0,0,0,0,0,0,6,0,0,9,5,0,0,0,7,0,0,0,
+0,0,0,0,0,0,4,10,0,0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,5,0,0,18,7,
+0,0,8,0,0,5,0,0,10,0,0,0,0,0,0,6,0,0,0,0,0,5,0,7,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,
+6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,6,0,0,10,0,0,5,10,4,0,0,12,0,0,0,0,
+6,22,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,7,0,5,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,6,0,7,0,0,0,6,0,6,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,7,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,
+0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,16,6,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,12,7,0,0,0,0,9,0,0,0,0,6,0,0,11,0,0,0,0,0,13,0,9,6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,0,0,10,7,0,0,0,7,0,6,0,
+0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,11,0,15,0,22,7,0,4,0,6,0,0,0,0,0,7,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,
+18,0,0,0,0,0,0,0,0,0,14,0,0,4,0,0,0,0,8,7,9,0,0,0,0,0,9,0,0,0,14,0,0,0,0,0,0,0,
+0,0,11,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,7,0,0,0,6,0,6,0,0,0,0,8,0,0,0,0,
+0,11,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,9,4,0,0,0,0,0,4,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,8,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,
+0,0,0,0,0,0,8,6,0,0,9,5,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,5,0,
+0,10,6,9,0,0,0,0,6,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,
+11,7,12,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,4,0,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,
+0,0,0,0,6,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,5,0,0,10,6,
+0,0,0,4,0,7,13,0,0,4,0,0,11,4,0,6,0,0,0,0,0,6,8,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,5,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,5,0,0,0,0,12,6,0,0,0,0,
+11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,11,5,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,
+7,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0,6,17,0,9,0,10,6,0,6,12,0,0,4,0,0,0,
+0,0,0,0,0,0,0,8,5,12,7,0,4,0,0,0,0,0,0,0,0,0,0,11,0,9,0,10,6,11,5,0,7,0,0,8,0,0,
+7,0,4,0,0,0,7,0,0,0,0,0,0,8,6,0,0,0,6,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,6,0,
+0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,11,0,0,0,0,6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,10,0,0,0,0,0,8,6,0,0,0,0,0,6,12,0,0,0,0,0,
+0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,6,0,0,16,0,11,5,0,0,0,0,0,
+0,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,9,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,6,10,
+7,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,0,9,5,0,0,0,0,8,0,9,0,0,
+0,0,0,0,0,0,7,10,0,13,0,0,6,0,0,0,0,0,0,0,0,0,6,9,4,0,0,0,0,0,0,10,0,0,0,0,0,10,
+0,0,0,0,0,0,0,10,6,11,0,0,0,0,0,9,0,0,0,0,0,0,4,0,0,0,0,0,0,10,5,0,0,0,0,0,6,0,
+0,0,0,0,0,18,4,0,7,0,0,0,0,0,0,24,0,8,6,0,7,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,0,
+0,8,5,0,0,0,0,10,7,0,6,0,0,0,0,0,0,0,0,8,5,10,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,
+6,0,0,8,7,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,4,0,5,15,0,0,0,0,7,0,7,0,0,0,0,
+0,0,0,0,0,6,10,5,0,0,0,6,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,12,0,0,0,0,0,0,0,0,
+0,0,5,0,0,0,0,0,0,14,4,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,11,0,10,4,9,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,7,0,0,0,
+0,0,0,0,0,0,0,0,7,13,7,0,0,0,0,0,0,0,5,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,
+0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,8,0,10,6,0,4,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,
+0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,9,7,0,0,0,0,0,6,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,6,0,0,0,
+0,0,0,0,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0,0,0,5,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,11,0,0,0,0,6,0,0,0,0,0,0,0,6,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,0,0,
+6,0,0,0,0,0,0,0,6,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,
+0,0,0,0,0,0,0,6,0,6,0,0,0,5,0,0,0,0,0,0,0,5,0,0,10,0,11,5,0,0,0,0,0,0,14,7,9,7,
+0,6,0,0,0,0,0,4,0,0,0,0,0,0,11,7,0,6,0,0,0,0,0,0,9,7,0,4,0,0,0,7,0,0,0,0,0,5,0,
+0,0,0,0,5,0,0,0,7,0,0,0,0,0,5,0,0,0,0,17,5,0,0,8,0,0,0,0,6,9,4,0,0,0,0,0,0,0,0,
+8,7,11,7,9,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,6,9,5,0,0,8,6,0,0,0,5,0,
+0,0,0,9,0,0,0,9,6,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,4,0,0,0,0,10,0,0,0,0,0,0,0,0,4,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,4,0,0,0,5,0,0,0,0,0,7,0,0,0,0,0,7,13,5,0,0,0,7,0,0,0,0,0,7,9,6,11,7,0,7,0,0,0,
+0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,8,5,0,0,0,5,9,4,0,0,0,0,0,0,0,0,8,4,0,0,0,0,
+24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,
+0,0,0,0,6,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0,5,11,6,0,4,0,7,20,0,8,5,9,5,9,0,0,6,
+0,0,0,0,0,0,0,0,0,0,0,7,23,5,0,0,8,4,0,0,10,0,0,6,0,5,0,0,0,0,0,0,0,0,0,0,0,7,0,
+0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,9,0,0,0,
+10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,
+6,0,0,0,0,14,0,18,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,9,6,0,4,0,0,0,0,0,0,8,4,
+11,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,0,0,0,12,0,10,7,0,0,10,0,0,0,0,
+0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,6,0,0,0,0,8,
+6,10,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,4,0,6,0,4,0,0,0,0,0,5,0,0,
+0,0,0,0,0,0,0,7,0,0,0,7,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,17,7,11,0,0,0,0,0,0,0,0,0,0,4,12,6,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0,
+0,5,12,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,6,0,0,20,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,4,
+0,0,0,5,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,6,0,4,13,0,0,7,0,0,0,0,0,0,
+0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,12,6,0,7,0,0,0,0,10,0,23,6,0,0,
+0,4,0,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+10,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,11,0,9,7,0,0,
+0,0,0,0,0,0,0,0,9,7,0,4,0,0,0,0,8,7,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
+0,0,0,0,0,6,0,0,10,7,10,5,0,0,8,0,8,0,0,0,0,0,0,4,0,5,10,0,0,0,0,0,0,0,9,0,0,6,
+0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,11,7,0,0,0,0,0,0,0,0,9,4,0,0,0,0,0,6,0,0,8,
+7,0,0,0,0,0,5,0,0,0,0,0,0,0,0,10,0,0,0,0,5,0,4,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,24,7,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,6,0,0,9,0,0,0,0,0,0,7,0,6,13,0,8,
+0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,6,0,0,0,0,8,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,
+4,0,0,0,0,0,4,0,0,0,0,0,0,0,6,8,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,4,0,4,0,0,0,5,0,7,0,0,10,0,10,7,0,0,12,5,0,0,9,0,0,0,10,0,
+0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0,
+12,0,0,0,0,0,8,5,13,6,0,0,0,0,0,0,9,4,0,0,0,0,8,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,
+0,0,6,0,0,14,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,17,6,0,0,0,0,12,6,0,0,0,0,8,0,0,7,0,
+7,0,4,9,0,0,6,0,0,0,6,0,0,0,0,0,0,8,7,0,0,0,0,0,0,11,0,0,4,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,18,7,0,4,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,6,0,0,0,0,0,
+0,0,0,12,5,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,8,0,11,7,0,0,0,0,0,0,0,0,0,4,0,0,0,0,
+11,0,0,0,0,0,0,0,21,0,0,6,10,0,0,0,0,0,9,0,10,0,0,0,0,0,11,0,0,0,0,6,0,0,0,0,0,
+5,0,0,0,0,0,0,10,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,4,0,0,23,7,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,9,7,0,0,0,7,
+0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0,0,
+11,6,0,0,0,0,0,0,0,6,0,0,0,0,10,7,0,0,9,4,0,0,11,0,8,5,0,0,0,7,8,5,22,0,0,0,9,6,
+0,0,0,0,0,0,0,6,10,4,0,0,0,0,0,7,9,4,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0,
+0,0,0,11,6,0,0,0,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,7,0,0,0,0,0,0,0,6,0,6,0,4,0,0,
+0,0,0,0,0,7,0,7,0,4,13,0,0,0,0,0,8,0,0,0,0,7,0,0,0,0,0,0,11,6,0,7,0,0,0,0,9,0,0,
+0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,8,0,0,0,0,0,8,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,6,0,0,0,0,13,5,8,0,0,
+0,0,0,0,0,14,0,0,6,0,0,0,0,0,0,0,0,0,7,0,0,17,6,0,0,0,0,13,4,0,0,9,6,0,0,10,5,0,
+0,10,5,0,0,0,0,13,0,0,0,0,6,0,0,0,0,0,0,10,0,12,0,0,0,0,0,0,0,0,0,0,0,8,4,0,4,0,
+0,0,4,0,0,0,0,0,4,0,0,12,0,0,5,9,4,0,0,0,0,0,0,0,0,0,5,8,5,0,0,0,7,0,0,0,0,8,7,
+0,0,0,6,12,5,0,0,0,5,0,0,0,5,0,0,0,0,0,4,12,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,7,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,
+0,9,6,0,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,4,11,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,
+0,0,0,0,12,7,0,0,0,7,10,7,0,0,11,0,0,0,0,0,0,0,0,0,11,7,0,0,0,6,0,0,11,0,0,0,0,
+0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,22,0,10,7,0,0,8,5,0,0,0,0,0,5,0,0,0,0,0,0,
+0,0,0,0,9,6,8,7,0,6,0,0,0,0,0,5,0,0,0,0,0,0,8,7,0,0,0,0,9,7,0,0,0,6,0,0,8,7,0,0,
+0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,4,0,5,0,0,0,4,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,6,0,0,0,0,0,0,0,4,0,0,0,0,0,0,9,
+6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,5,0,0,0,0,14,0,0,0,
+9,0,0,0,0,0,0,0,0,0,9,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,12,0,0,0,0,0,12,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,10,7,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,6,0,0,0,0,0,0,9,6,0,0,0,0,0,6,0,0,0,0,0,
+0,0,0,0,0,9,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,
+0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,6,0,7,12,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0,
+0,7,0,0,8,6,0,0,0,0,10,7,0,0,0,0,0,0,0,6,0,0,0,0,0,6,12,0,0,0,0,0,0,0,0,6,0,0,0,
+0,0,6,0,0,0,6,0,0,0,0,0,6,16,0,0,0,0,0,0,0,0,0,9,0,17,0,14,7,8,0,0,0,0,0,0,6,0,
+0,0,0,0,0,0,0,0,0,11,0,0,6,8,7,0,6,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,0,0,
+9,0,0,0,0,7,0,0,0,0,11,5,0,4,9,6,8,0,0,0,0,0,0,0,0,0,10,0,11,7,0,0,0,0,0,0,0,0,
+9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,
+0,0,0,12,0,0,0,0,0,10,5,0,4,0,0,0,0,0,7,10,6,11,6,0,0,0,0,0,0,0,0,0,0,0,0,17,0,
+0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,8,0,0,4,0,0,0,6,0,0,0,
+0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,4,0,0,0,0,9,6,0,0,0,4,0,0,0,0,0,4,10,7,0,7,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,
+0,0,0,0,0,0,6,0,0,0,6,0,6,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,18,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,13,0,0,0,0,0,10,0,0,0,0,0,0,0,0,4,
+0,0,0,6,0,0,0,0,0,4,8,0,0,0,11,7,0,0,0,4,0,0,0,0,0,7,0,0,8,5,0,0,16,0,0,0,13,6,
+0,0,0,0,0,0,0,6,0,0,0,0,20,0,11,6,0,0,8,7,0,0,0,0,0,6,17,0,8,0,0,0,0,0,8,7,0,0,
+9,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,
+0,0,4,0,7,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,8,
+0,8,0,0,0,0,0,0,0,11,0,8,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,6,0,0,9,0,
+0,0,0,0,8,0,0,0,0,0,18,0,0,0,0,0,0,4,9,0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,9,6,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,7,0,0,0,0,0,0,0,0,
+0,4,0,0,0,0,0,0,14,0,0,0,0,7,0,6,0,0,8,0,20,7,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,8,0,0,0,14,0,0,0,0,0,0,0,8,0,0,7,0,6,0,0,0,7,0,0,0,0,0,0,0,0,
+0,0,0,4,12,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,10,6,0,
+5,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,
+0,0,0,5,8,4,0,0,0,0,0,0,0,4,0,0,0,7,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,12,7,0,
+0,0,0,13,6,0,0,0,7,0,0,8,0,0,0,8,0,0,0,0,0,0,0,0,0,0,5,0,0,0,7,0,0,0,0,0,0,11,5,
+0,6,0,0,8,5,0,7,0,0,0,0,0,0,0,7,0,0,0,0,8,6,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,4,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+14,0,10,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,19,0,0,4,0,0,0,7,
+0,0,11,5,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,16,0,10,5,18,0,0,7,9,6,0,5,0,0,0,0,0,
+0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,5,0,0,0,7,0,6,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,4,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,23,0,0,0,0,5,0,0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,14,0,20,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,
+11,0,0,0,0,7,0,0,0,0,15,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,7,0,0,0,0,
+0,4,0,0,0,0,10,0,0,0,0,0,9,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,10,0,11,6,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,5,0,0,11,0,0,0,0,7,0,0,0,0,0,0,8,7,0,
+4,0,0,0,0,11,0,0,0,0,0,11,0,0,5,0,0,8,7,0,4,0,7,0,0,0,0,0,0,0,6,0,0,0,0,0,4,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,0,0,
+0,0,4,11,5,10,7,0,7,0,0,9,6,9,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,9,4,0,4,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,8,6,0,0,0,0,11,7,0,0,0,0,0,0,0,0,0,0,11,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,8,5,0,0,8,0,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,
+10,7,0,0,0,6,0,0,0,0,0,0,8,0,0,6,0,0,0,6,10,0,0,0,0,0,0,0,0,0,0,0,8,5,0,0,0,6,0,
+0,0,6,0,0,0,0,9,5,8,5,8,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,
+0,8,7,10,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,0,5,0,0,0,6,0,7,0,0,
+10,5,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,11,0,0,0,0,0,13,4,
+0,0,0,4,0,0,0,0,0,5,8,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,14,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,7,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,5,0,0,15,6,10,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,14,6,10,0,0,0,0,0,0,0,0,6,0,
+0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,6,0,5,11,4,0,6,0,0,0,7,0,0,0,0,
+0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,5,0,0,8,5,0,0,0,0,0,0,0,0,0,0,
+0,0,10,0,0,0,0,0,9,6,9,4,0,0,0,4,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,8,5,0,
+0,0,0,0,0,0,0,0,0,0,4,0,0,11,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0,
+0,0,0,7,12,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,
+4,9,6,0,4,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,6,0,
+7,8,6,0,0,0,0,0,0,0,4,0,0,9,6,0,0,0,0,0,0,0,0,0,6,0,5,0,4,0,0,0,0,0,0,0,5,0,0,0,
+0,0,5,0,0,0,7,12,7,0,0,0,0,0,0,18,4,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,6,0,0,0,
+0,12,0,0,7,0,0,0,0,0,7,0,0,13,0,0,6,0,0,0,0,8,7,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,7,10,5,0,0,8,0,0,0,0,0,0,0,8,6,0,7,0,0,8,4,0,4,0,0,0,0,10,4,0,0,14,0,
+0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,17,0,0,0,0,0,0,6,0,0,0,0,8,6,0,0,10,5,0,0,0,0,8,
+6,0,0,0,6,0,0,0,7,0,0,0,0,0,6,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,12,0,0,0,0,6,
+8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,
+0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,4,24,0,0,
+0,0,0,12,6,0,0,10,6,0,5,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,17,7,0,5,0,0,0,
+0,0,0,0,0,0,0,0,0,0,6,11,5,9,0,8,7,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,10,7,0,0,0,0,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,5,8,7,0,0,0,
+0,8,5,0,0,0,0,10,7,0,7,0,0,0,0,0,0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,6,0,4,0,0,0,0,
+0,6,12,0,8,7,0,0,0,0,0,0,0,0,0,0,16,0,10,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,22,0,0,0,
+0,0,0,0,0,0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,22,0,0,6,0,0,21,0,0,0,22,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+6,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,7,8,0,0,0,0,6,14,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,6,0,0,0,0,0,0,
+0,0,0,0,0,6,0,0,0,0,8,5,0,0,11,7,0,6,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,
+6,0,0,0,5,0,0,0,0,0,0,0,0,0,4,0,0,8,7,0,0,0,0,8,5,11,7,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,0,0,0,0,8,5,0,0,10,0,0,4,13,7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,0,0,13,6,
+0,6,0,7,0,0,8,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,15,0,0,0,10,7,0,0,0,0,0,
+7,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,19,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,6,0,5,
+0,7,0,0,0,0,0,0,0,0,0,6,0,0,11,4,0,0,0,6,0,0,13,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,8,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,
+0,7,0,0,0,0,0,0,11,7,0,0,0,0,0,6,0,0,10,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,5,11,6,
+0,0,0,0,0,0,0,0,10,0,0,0,0,6,0,0,0,0,0,0,8,7,0,0,0,5,0,0,0,5,0,0,0,0,0,0,0,0,0,
+0,0,0,8,7,0,0,0,0,9,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,10,0,
+0,6,0,0,13,0,0,0,0,0,0,0,9,6,0,0,8,6,8,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,0,
+0,9,7,0,0,0,0,0,0,11,0,0,0,10,7,0,0,0,0,0,0,0,0,9,6,0,0,12,4,0,4,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,6,0,0,0,0,21,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,5,0,0,
+9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,
+16,0,0,4,0,0,0,0,0,7,0,0,0,6,0,6,0,0,11,0,0,0,0,5,0,0,0,0,0,0,0,4,8,5,0,0,0,0,0,
+0,14,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,
+0,0,8,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,
+0,0,0,0,6,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,14,7,0,0,9,7,0,0,11,0,0,0,0,0,10,
+4,11,5,13,6,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,5,0,0,0,0,0,4,0,0,9,0,0,0,0,
+0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,6,12,5,0,0,0,6,14,0,0,0,0,0,0,0,0,0,0,4,9,4,
+0,0,0,0,0,5,0,0,0,0,0,0,0,4,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,5,0,0,
+0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,11,6,0,0,13,7,0,0,13,6,0,7,0,0,0,0,0,0,8,6,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,10,6,0,4,0,0,12,6,0,0,0,0,0,0,0,0,10,6,
+0,0,0,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,6,0,
+0,0,0,0,7,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,6,0,
+0,0,7,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,
+0,0,0,5,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,
+0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,8,7,0,0,8,5,0,0,0,4,9,5,0,0,0,7,10,6,0,0,
+0,0,0,0,9,7,0,0,8,5,8,0,8,4,0,0,13,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,0,0,0,0,0,0,0,
+0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,
+0,11,7,0,0,0,7,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,5,0,0,0,7,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,9,7,0,0,0,0,8,5,0,4,0,0,0,0,0,6,0,6,14,
+6,0,0,0,0,9,6,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,6,0,0,0,0,14,7,9,7,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,16,
+0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,14,0,
+0,6,0,0,8,6,0,0,0,0,0,6,0,0,12,0,0,0,0,0,8,5,0,7,11,0,0,5,0,4,0,0,0,6,0,0,0,0,0,
+0,0,0,0,0,0,0,9,6,0,4,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,10,5,0,0,0,0,
+0,4,0,0,0,7,11,6,0,4,8,5,9,5,0,0,0,5,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,8,5,14,7,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,16,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,9,6,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,9,0,0,0,12,5,0,0,0,0,0,0,0,4,10,5,0,0,0,0,0,0,0,0,0,0,0,6,0,
+0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,4,0,0,0,6,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,10,4,0,0,0,0,0,5,0,0,0,4,
+0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,8,0,10,7,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,10,7,0,0,0,0,0,0,0,0,15,0,0,0,
+0,0,0,0,0,0,0,7,0,0,0,0,0,7,10,7,9,7,0,0,0,7,0,0,8,0,0,0,0,0,0,0,9,0,0,0,8,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,8,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,7,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,15,7,12,6,0,0,0,7,0,5,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,5,0,0,0,0,
+0,0,0,6,9,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,9,7,0,0,14,0,0,0,11,7,0,0,0,0,0,
+0,0,0,0,0,0,4,0,0,11,7,0,0,0,0,8,0,0,0,0,0,0,6,8,7,0,0,0,7,10,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,10,0,0,0,0,0,0,
+6,0,6,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,11,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,7,0,0,10,7,0,0,0,0,9,7,0,0,0,0,0,0,13,7,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,12,0,
+0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,9,6,0,0,11,0,0,
+0,0,0,14,4,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,7,0,0,
+0,0,0,6,0,7,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,0,20,
+7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,8,0,0,0,0,0,0,0,0,0,11,5,0,0,0,0,0,0,0,0,0,0,10,4,0,0,0,5,8,5,10,4,0,0,0,0,0,
+0,13,6,9,7,0,0,10,7,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,6,0,0,0,7,0,6,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,10,7,0,0,
+0,0,0,0,0,0,0,0,12,4,0,0,0,0,8,7,0,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,
+0,0,0,0,6,0,6,9,6,0,0,12,5,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,0,
+0,0,0,0,0,0,0,0,0,5,8,7,9,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,11,
+4,0,0,0,0,0,0,8,0,0,0,10,7,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,0,
+0,0,0,0,0,5,0,6,0,0,10,0,14,0,0,0,0,0,0,0,23,0,0,0,12,0,10,5,0,0,0,0,0,0,0,0,0,
+5,0,0,0,0,8,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,22,0,8,0,0,0,0,6,0,0,0,0,0,0,0,5,0,0,
+0,0,0,0,0,6,18,4,0,0,0,7,10,6,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,
+0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,7,10,0,0,0,0,0,0,6,0,0,0,0,11,5,0,0,0,0,0,0,0,0,
+15,0,8,6,0,0,13,7,0,0,0,0,0,7,0,0,0,0,0,7,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,9,5,9,
+0,0,6,8,6,0,0,0,0,10,0,0,0,18,5,0,0,0,5,0,7,0,0,0,0,8,6,0,0,0,0,9,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,14,0,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,6,0,0,0,5,0,
+0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,8,5,0,0,0,0,0,0,0,0,9,0,0,0,0,4,0,0,0,0,0,0,0,0,
+0,0,0,0,20,5,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,9,5,0,0,0,0,0,0,8,4,24,0,0,0,0,0,0,
+0,0,0,0,0,0,0,9,7,0,0,0,0,10,5,0,0,8,5,0,0,0,0,0,0,0,0,12,7,0,6,0,0,10,6,0,0,0,
+0,14,0,0,4,9,5,0,0,0,0,0,0,9,0,0,0,0,0,0,6,0,0,0,0,0,4,0,0,8,0,0,0,0,0,11,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,8,5,11,7,0,4,0,0,10,0,0,0,0,
+0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,11,6,0,0,0,0,0,5,14,6,0,0,0,0,10,0,0,
+0,13,4,0,0,0,0,0,0,0,0,0,0,0,6,0,0,10,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,7,12,0,10,6,0,0,0,0,0,0,10,0,0,0,0,0,10,0,9,
+7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,0,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,0,9,7,0,0,0,
+0,0,0,0,0,0,0,0,0,24,0,11,7,0,7,0,0,0,0,0,0,8,6,0,0,0,0,0,0,8,7,0,0,0,0,0,5,0,0,
+0,6,9,0,0,0,23,5,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,7,0,0,0,
+0,0,0,0,0,0,0,0,0,0,6,0,0,18,4,0,0,11,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,
+0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,9,0,0,0,11,0,0,0,23,0,0,
+0,10,4,0,0,0,0,0,7,0,0,0,7,0,0,0,0,0,4,0,0,0,0,0,7,0,0,19,0,11,0,0,0,0,0,12,7,0,
+0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,5,0,0,0,0,0,5,0,0,0,0,0,5,0,0,0,0,0,0,0,6,0,0,
+9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,4,0,0,0,0,10,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,22,0,8,7,10,4,11,0,13,5,8,7,9,0,8,7,0,0,0,7,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,
+0,8,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,0,0,0,4,11,0,0,6,0,0,8,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,5,0,0,
+20,0,0,0,0,0,0,0,0,0,11,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,7,0,0,14,0,0,0,9,0,13,7,0,0,0,0,0,6,0,7,0,0,8,6,10,6,0,0,8,6,0,0,0,6,0,
+0,12,6,9,0,0,0,0,0,0,5,9,0,12,4,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,8,5,0,0,0,0,0,
+0,0,4,8,0,0,6,8,0,0,0,0,0,0,0,0,0,13,6,0,7,0,0,0,0,0,6,8,7,8,6,0,0,0,7,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,18,0,11,4,0,0,0,5,0,0,0,0,0,0,0,0,0,0,
+0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,14,
+6,0,0,0,0,12,7,8,0,0,0,0,0,0,0,8,7,0,0,0,0,10,4,0,0,0,0,0,0,10,0,0,6,0,0,0,0,0,
+0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,15,6,9,7,0,0,0,0,0,0,15,6,11,7,0,0,0,7,0,0,21,0,0,
+0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,17,6,0,0,10,5,0,5,0,0,0,0,0,0,0,0,0,7,
+0,0,10,0,0,0,0,0,0,0,0,4,11,5,0,0,0,0,16,7,0,0,0,0,0,6,0,0,8,7,0,4,0,0,10,0,0,0,
+0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,8,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,
+0,0,0,10,4,0,0,0,0,0,0,0,0,0,6,0,5,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,
+0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,6,10,7,0,0,0,0,0,0,0,0,8,4,0,0,10,0,0,0,0,4,0,6,0,6,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,7,17,0,0,0,0,0,
+0,0,0,0,0,0,10,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+6,0,0,0,5,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,0,4,0,0,0,0,0,6,0,0,0,0,0,0,10,5,0,0,
+0,5,0,0,0,0,9,0,19,7,0,0,0,0,0,7,0,0,0,0,10,6,0,0,0,6,0,5,0,0,0,0,0,0,0,0,0,6,8,
+0,0,0,0,0,11,0,0,0,0,0,0,6,0,0,0,0,0,7,9,0,15,0,0,0,0,0,0,0,0,0,0,4,0,0,0,5,0,0,
+0,0,0,0,0,6,0,0,0,0,0,0,0,4,0,0,0,0,9,0,0,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,6,0,0,
+0,0,0,6,10,0,0,0,0,0,0,0,23,0,14,0,0,0,0,7,0,0,0,0,0,7,0,0,9,0,0,0,0,7,0,0,0,0,
+0,6,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,
+0,0,0,0,0,9,5,0,0,0,0,0,4,0,0,0,0,9,5,0,0,0,0,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,22,0,0,0,0,0,0,0,10,0,0,0,0,0,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,6,11,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,14,7,0,0,12,7,0,0,0,
+0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,8,6,10,0,0,0,0,0,0,0,0,0,10,7,8,5,0,0,0,0,0,0,
+0,0,8,4,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,5,0,0,9,5,0,0,0,0,0,5,0,0,0,0,0,4,0,0,0,
+0,0,0,0,0,0,0,12,4,11,0,0,0,9,0,11,7,0,0,0,0,0,0,10,6,0,0,0,6,0,0,0,0,15,5,0,0,
+11,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,4,0,4,0,6,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,8,0,0,0,19,7,0,4,0,0,9,0,0,0,0,0,10,0,
+0,6,0,0,13,0,12,6,0,0,0,0,0,0,0,0,10,7,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,13,7,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,4,9,0,0,0,10,0,0,0,0,0,0,0,
+0,5,0,0,0,0,0,0,10,0,23,6,0,0,0,6,8,0,0,0,0,0,0,0,0,0,17,7,0,0,0,0,11,6,22,5,0,
+0,9,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,5,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,4,11,0,9,4,0,0,
+0,7,0,7,0,0,0,0,0,0,12,4,0,0,0,0,0,0,0,0,0,0,0,0,11,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,0,0,11,5,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,6,0,0,0,4,0,0,0,0,
+0,0,0,0,0,7,0,0,0,4,0,0,10,4,0,0,0,0,0,0,0,7,0,7,0,0,0,6,0,0,0,0,8,6,0,6,0,6,0,
+0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,6,22,6,12,0,0,6,0,0,0,6,0,0,0,0,0,7,0,0,0,0,11,0,0,0,
+9,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,6,0,0,0,6,0,6,0,0,8,7,0,0,0,4,9,7,19,0,0,0,0,0,0,0,0,0,9,6,10,6,0,6,0,0,0,
+4,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,6,16,7,10,6,0,0,23,6,11,7,0,4,0,0,0,0,0,0,0,0,0,
+5,0,0,0,0,10,7,0,0,0,0,0,7,0,0,0,0,0,0,15,0,10,0,0,0,14,6,0,0,0,0,0,0,0,0,0,0,0,
+5,0,0,0,0,0,0,0,5,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,5,0,0,11,5,0,0,0,0,0,0,0,0,0,0,
+0,4,0,0,0,0,0,6,0,0,10,0,0,0,0,7,0,0,0,0,0,0,10,6,0,0,0,0,8,4,0,0,0,7,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,12,5,0,0,0,0,
+0,6,0,0,0,0,9,6,0,0,0,0,0,0,0,6,9,0,0,0,0,6,0,0,0,0,8,7,0,0,0,0,0,0,0,6,0,0,0,0,
+0,0,0,0,0,0,10,5,0,0,0,0,0,0,8,6,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,8,5,0,0,0,0,0,7,0,7,0,4,0,0,10,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,5,0,0,0,0,13,
+7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,7,0,0,13,0,0,0,0,0,0,0,0,7,10,5,0,0,0,0,0,0,9,7,0,0,8,6,9,
+5,0,0,0,0,0,6,12,0,0,0,0,0,0,0,18,6,0,0,0,0,0,0,0,0,19,7,0,4,0,0,0,0,9,5,0,5,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,7,0,0,0,0,0,0,14,0,0,0,23,7,8,7,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,22,0,0,7,0,0,0,0,0,0,0,0,9,7,8,4,0,
+0,0,0,0,0,0,0,8,5,0,6,0,0,0,0,0,6,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,
+8,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,12,5,0,0,0,0,0,0,0,0,0,0,8,6,0,0,11,7,0,0,0,
+0,12,0,8,6,19,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,11,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,11,7,0,0,0,0,0,4,10,0,0,0,0,0,0,0,8,7,0,0,0,0,14,0,8,0,0,6,10,0,0,
+0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,0,0,
+0,0,0,0,13,0,0,0,0,0,0,0,11,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,
+0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,5,0,0,0,6,0,0,0,5,0,7,0,0,0,
+0,0,6,0,0,21,7,0,0,9,6,0,0,0,6,0,0,13,7,0,0,0,5,0,0,0,0,0,4,0,6,0,0,0,0,0,0,0,0,
+0,0,0,4,0,0,0,0,0,0,11,5,0,6,0,0,10,5,0,0,0,0,0,0,0,0,9,6,0,0,8,7,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,9,0,0,0,0,0,0,6,0,0,0,0,15,4,0,0,12,7,0,0,0,6,
+0,7,0,0,8,0,9,5,0,4,0,0,0,6,0,6,0,0,23,4,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,4,0,0,8,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,0,0,0,0,0,0,
+7,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,12,6,0,0,0,0,0,0,10,7,0,7,0,0,0,0,0,0,0,0,0,0,
+9,0,0,0,0,0,8,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,11,5,0,0,0,6,0,6,0,0,0,0,0,0,0,6,0,
+4,0,0,0,0,0,0,0,0,0,0,0,5,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,8,7,0,0,0,6,0,6,0,
+0,0,0,0,0,0,0,0,5,0,0,0,0,0,5,0,0,0,0,11,0,0,0,0,0,0,0,10,5,9,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,23,7,0,0,0,0,0,7,0,0,10,6,18,0,0,0,
+0,0,0,0,8,7,0,6,0,0,0,0,0,0,8,5,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,
+0,0,0,0,0,6,0,0,0,4,12,7,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,13,5,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,0,0,0,
+11,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,
+0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,10,0,11,0,0,0,0,0,0,0,0,0,
+17,5,0,4,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,4,0,0,0,0,8,7,0,0,0,0,0,0,0,
+0,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,
+10,0,0,0,8,6,0,0,0,7,0,0,0,0,0,0,8,0,0,0,14,0,0,0,0,7,0,0,0,4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,9,4,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,
+10,0,0,0,16,5,0,0,0,0,0,0,8,0,0,4,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,10,0,0,0,
+0,0,0,0,0,5,0,0,0,0,12,5,0,7,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0,
+0,0,0,0,0,0,0,12,6,0,0,0,0,0,7,0,6,0,6,12,6,0,0,0,0,0,0,0,4,8,7,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,10,6,8,0,0,
+6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+16,0,8,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,23,5,0,0,0,7,0,6,0,
+0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,14,0,0,0,0,7,0,0,0,4,17,5,0,0,0,0,11,0,9,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,6,0,0,0,5,0,7,0,0,0,0,0,0,0,0,8,0,0,0,
+12,6,0,0,0,0,0,0,13,0,0,0,0,7,9,0,0,0,0,0,0,0,0,0,0,5,0,0,0,7,10,7,12,0,0,0,9,0,
+0,0,14,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,15,6,0,0,23,0,0,7,0,6,0,0,0,7,0,6,
+0,0,0,0,0,0,0,6,0,6,9,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,8,7,9,4,0,0,10,0,0,0,10,
+6,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,23,0,0,6,0,0,0,0,0,0,9,4,
+0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,9,6,0,0,0,0,8,6,0,0,0,0,0,0,0,0,12,0,0,
+0,0,0,8,0,0,6,11,6,0,0,8,7,8,5,0,0,0,0,0,5,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,
+10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,
+7,0,0,0,0,9,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,8,0,0,0,0,6,12,5,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,10,0,10,
+7,0,0,8,0,0,0,0,4,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0,
+0,0,4,0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,6,0,5,0,0,0,0,8,0,0,0,10,7,0,0,0,0,10,0,0,0,
+0,0,13,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,19,7,0,4,12,0,8,0,0,0,0,6,0,0,0,0,
+0,0,0,6,0,0,0,0,0,0,0,0,0,4,0,0,0,0,18,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,
+0,14,0,0,4,0,0,0,6,0,0,0,6,0,0,0,7,0,0,0,0,0,0,10,4,0,0,9,7,0,0,11,0,0,0,0,0,0,
+7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,4,0,0,12,0,0,0,
+0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,22,5,9,7,0,0,0,0,0,0,0,0,0,
+0,0,6,0,0,9,6,0,5,0,0,0,0,0,0,10,5,0,0,8,6,0,6,10,5,0,0,0,6,0,0,0,6,0,0,20,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,0,17,4,0,7,0,6,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,
+0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,
+0,0,7,0,0,8,6,12,0,0,7,18,7,0,0,8,4,0,0,0,0,9,6,0,0,0,0,0,0,0,0,13,0,0,6,0,0,0,
+0,0,0,0,0,0,0,10,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,0,
+0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,12,0,0,0,8,0,0,0,0,0,0,
+4,0,0,10,0,16,0,0,0,0,0,0,0,12,7,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,16,6,10,0,0,5,0,0,0,0,0,6,0,0,0,0,
+0,7,0,0,0,7,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,5,8,7,0,7,0,0,0,0,0,0,0,0,8,0,0,6,0,0,0,6,0,0,0,4,0,0,0,0,
+8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,8,0,0,0,
+9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,13,5,0,5,0,0,0,7,8,4,0,0,0,0,0,0,0,
+0,12,0,0,0,0,0,0,0,0,0,0,0,8,6,0,6,0,0,11,0,0,0,0,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0,
+0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,11,6,0,0,10,6,0,0,
+0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,
+0,0,0,6,0,0,0,7,0,0,9,0,8,7,11,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,9,6,10,5,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,10,7,0,0,0,0,0,0,11,0,9,6,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,5,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,15,5,12,5,
+0,0,0,0,0,0,12,7,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,12,6,0,
+0,0,0,24,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,10,4,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,9,0,11,0,0,0,0,0,0,0,0,0,0,6,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,
+0,0,8,0,0,0,0,7,0,0,0,0,0,0,10,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,0,
+0,0,0,0,0,14,7,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,0,0,6,0,0,0,6,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,7,20,7,11,4,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,7,9,6,0,0,12,7,0,0,0,0,0,0,10,0,12,0,
+0,0,0,0,0,4,9,6,13,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,5,0,0,0,0,0,0,8,0,0,0,0,0,0,
+0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,11,0,9,0,0,0,0,4,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,5,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,
+0,4,0,5,0,0,0,0,0,0,0,0,0,4,0,0,0,0,9,7,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,
+0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,
+0,0,0,0,8,7,0,0,0,0,0,0,12,0,0,6,0,0,0,0,0,0,0,6,8,4,0,0,10,7,0,0,10,0,0,0,0,0,
+0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,5,
+0,4,0,0,0,0,0,6,0,0,0,0,0,0,8,0,0,6,0,0,0,6,0,0,0,0,0,7,0,5,8,4,0,0,9,0,0,0,0,4,
+0,0,0,0,0,0,0,0,0,5,0,0,15,6,8,6,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,9,6,0,0,0,0,0,0,0,7,0,0,0,4,0,
+6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,9,5,0,6,12,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,0,12,7,0,0,0,0,
+0,0,0,0,0,5,0,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,11,4,0,0,0,0,0,0,0,0,0,0,10,
+7,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,7,8,7,9,6,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,5,12,0,
+10,5,12,6,0,0,0,7,0,0,0,0,0,0,0,5,0,0,0,5,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,
+11,7,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,0,6,0,7,0,0,0,0,8,0,8,5,0,6,0,0,0,6,0,0,0,
+0,0,0,0,6,0,6,0,6,9,0,0,5,17,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,7,0,0,
+0,0,0,7,0,0,0,0,16,5,0,0,0,0,0,0,0,4,0,0,0,5,11,5,0,7,0,0,0,4,8,7,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,12,0,0,0,
+0,0,12,0,0,0,0,0,0,0,0,4,10,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,0,0,4,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,20,5,0,0,
+10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,12,0,0,0,0,0,0,6,0,0,0,0,0,0,9,4,10,7,0,4,0,0,
+0,0,0,0,10,6,0,0,0,0,8,4,0,7,8,6,0,6,8,0,10,0,0,0,0,0,13,5,0,6,0,0,0,0,0,0,22,4,
+0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,10,
+5,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,10,4,0,0,10,7,0,0,0,0,0,5,0,
+5,8,0,0,0,0,6,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,4,0,0,0,0,0,6,0,0,
+0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0,
+4,0,0,0,4,10,0,0,6,13,7,8,0,0,0,0,0,0,7,0,0,12,7,0,0,0,0,0,0,10,5,0,0,0,0,0,6,0,
+0,0,0,0,0,0,0,0,0,13,7,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,6,0,6,
+0,0,0,0,0,0,0,0,12,0,8,4,0,0,0,0,0,4,0,4,0,0,0,0,0,0,0,5,0,0,0,0,12,5,0,0,0,7,0,
+0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,10,0,0,0,20,0,0,5,0,0,10,
+7,11,7,0,0,0,0,0,0,0,0,0,0,17,0,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,10,7,0,4,0,6,0,0,24,0,0,5,0,0,0,0,8,0,0,
+0,0,0,0,0,10,5,0,4,0,6,0,0,8,0,0,0,0,0,0,4,0,6,0,0,0,0,0,0,9,5,0,0,0,0,0,0,0,0,
+0,0,0,6,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,0,7,
+0,0,13,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,
+17,7,0,0,11,6,0,0,0,0,12,6,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0,10,0,0,4,8,6,0,0,0,
+0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,9,5,0,7,18,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,8,0,0,0,
+0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,
+0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,4,0,6,0,0,9,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,
+0,0,0,8,7,10,0,8,5,0,0,0,0,0,0,0,0,9,0,0,0,10,0,0,0,0,6,0,7,0,4,0,0,0,0,0,0,0,0,
+8,0,0,0,0,0,8,4,0,0,0,0,0,5,0,0,10,0,12,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,6,11,0,0,
+7,0,0,0,0,0,6,10,5,0,0,0,0,0,0,0,0,0,5,0,0,9,5,12,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,6,0,0,0,0,13,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,
+0,0,0,8,4,0,6,12,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,11,4,0,0,0,6,14,0,11,0,9,6,0,0,0,0,0,0,22,0,12,0,8,6,0,0,0,0,0,0,0,6,0,
+0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,
+10,7,0,0,0,0,0,0,0,0,9,0,0,0,0,4,0,0,0,0,0,0,0,0,0,5,11,0,0,0,0,0,0,0,8,6,0,0,9,
+7,0,0,12,4,0,0,0,0,0,0,12,6,0,6,0,7,0,0,8,5,0,0,0,0};
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }  /* extern "C" */
diff --git a/third_party/brotli/enc/dictionary_hash.h b/third_party/brotli/enc/dictionary_hash.h
index b3bb959..e553ea5 100644
--- a/third_party/brotli/enc/dictionary_hash.h
+++ b/third_party/brotli/enc/dictionary_hash.h
@@ -15,7 +15,8 @@
 extern "C" {
 #endif
 
-extern const uint16_t kStaticDictionaryHash[32768];
+extern const uint16_t kStaticDictionaryHashWords[32768];
+extern const uint8_t kStaticDictionaryHashLengths[32768];
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }  /* extern "C" */
diff --git a/third_party/brotli/enc/encode.c b/third_party/brotli/enc/encode.c
index 141e70aa..8d90937b 100644
--- a/third_party/brotli/enc/encode.c
+++ b/third_party/brotli/enc/encode.c
@@ -54,12 +54,19 @@
   BROTLI_STREAM_METADATA_BODY = 4
 } BrotliEncoderStreamState;
 
+typedef enum BrotliEncoderFlintState {
+  BROTLI_FLINT_NEEDS_2_BYTES = 2,
+  BROTLI_FLINT_NEEDS_1_BYTE = 1,
+  BROTLI_FLINT_WAITING_FOR_PROCESSING = 0,
+  BROTLI_FLINT_WAITING_FOR_FLUSHING = -1,
+  BROTLI_FLINT_DONE = -2
+} BrotliEncoderFlintState;
+
 typedef struct BrotliEncoderStateStruct {
   BrotliEncoderParams params;
 
   MemoryManager memory_manager_;
 
-  HasherHandle hasher_;
   uint64_t input_pos_;
   RingBuffer ringbuffer_;
   size_t cmd_alloc_size_;
@@ -73,10 +80,17 @@
   int saved_dist_cache_[4];
   uint16_t last_bytes_;
   uint8_t last_bytes_bits_;
+  /* "Flint" is a tiny uncompressed block emitted before the continuation
+     block to unwire literal context from previous data. Despite being int8_t,
+     field is actually BrotliEncoderFlintState enum. */
+  int8_t flint_;
   uint8_t prev_byte_;
   uint8_t prev_byte2_;
   size_t storage_size_;
   uint8_t* storage_;
+
+  Hasher hasher_;
+
   /* Hash table for FAST_ONE_PASS_COMPRESSION_QUALITY mode. */
   int small_table_[1 << 10];  /* 4KiB */
   int* large_table_;          /* Allocated only when needed */
@@ -114,8 +128,6 @@
   BROTLI_BOOL is_initialized_;
 } BrotliEncoderStateStruct;
 
-static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s);
-
 static size_t InputBlockSize(BrotliEncoderState* s) {
   return (size_t)1 << s->params.lgblock;
 }
@@ -174,6 +186,11 @@
       state->params.dist.num_direct_distance_codes = value;
       return BROTLI_TRUE;
 
+    case BROTLI_PARAM_STREAM_OFFSET:
+      if (value > (1u << 30)) return BROTLI_FALSE;
+      state->params.stream_offset = value;
+      return BROTLI_TRUE;
+
     default: return BROTLI_FALSE;
   }
 }
@@ -195,7 +212,7 @@
   if (s->storage_size_ < size) {
     BROTLI_FREE(m, s->storage_);
     s->storage_ = BROTLI_ALLOC(m, uint8_t, size);
-    if (BROTLI_IS_OOM(m)) return NULL;
+    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->storage_)) return NULL;
     s->storage_size_ = size;
   }
   return s->storage_;
@@ -234,7 +251,7 @@
       s->large_table_size_ = htsize;
       BROTLI_FREE(m, s->large_table_);
       s->large_table_ = BROTLI_ALLOC(m, int, htsize);
-      if (BROTLI_IS_OOM(m)) return 0;
+      if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->large_table_)) return 0;
     }
     table = s->large_table_;
   }
@@ -499,7 +516,7 @@
   /* TODO: find more precise minimal block overhead. */
   if (bytes <= 2) return BROTLI_FALSE;
   if (num_commands < (bytes >> 8) + 2) {
-    if (num_literals > 0.99 * (double)bytes) {
+    if ((double)num_literals > 0.99 * (double)bytes) {
       uint32_t literal_histo[256] = { 0 };
       static const uint32_t kSampleRate = 13;
       static const double kMinEntropy = 7.92;
@@ -617,11 +634,7 @@
       /* The number of distance symbols effectively used for distance
          histograms. It might be less than distance alphabet size
          for "Large Window Brotli" (32-bit). */
-      uint32_t num_effective_dist_codes = block_params.dist.alphabet_size;
-      if (num_effective_dist_codes > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) {
-        num_effective_dist_codes = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
-      }
-      BrotliOptimizeHistograms(num_effective_dist_codes, &mb);
+      BrotliOptimizeHistograms(block_params.dist.alphabet_size_limit, &mb);
     }
     BrotliStoreMetaBlock(m, data, wrapped_last_flush_pos, bytes, mask,
                          prev_byte, prev_byte2,
@@ -678,12 +691,23 @@
 
   s->last_bytes_bits_ = 0;
   s->last_bytes_ = 0;
+  s->flint_ = BROTLI_FLINT_DONE;
   s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX;
 
   SanitizeParams(&s->params);
   s->params.lgblock = ComputeLgBlock(&s->params);
   ChooseDistanceParams(&s->params);
 
+  if (s->params.stream_offset != 0) {
+    s->flint_ = BROTLI_FLINT_NEEDS_2_BYTES;
+    /* Poison the distance cache. -16 +- 3 is still less than zero (invalid). */
+    s->dist_cache_[0] = -16;
+    s->dist_cache_[1] = -16;
+    s->dist_cache_[2] = -16;
+    s->dist_cache_[3] = -16;
+    memcpy(s->saved_dist_cache_, s->dist_cache_, sizeof(s->saved_dist_cache_));
+  }
+
   RingBufferSetup(&s->params, &s->ringbuffer_);
 
   /* Initialize last byte with stream header. */
@@ -693,8 +717,14 @@
         s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
       lgwin = BROTLI_MAX(int, lgwin, 18);
     }
-    EncodeWindowBits(lgwin, s->params.large_window,
-                     &s->last_bytes_, &s->last_bytes_bits_);
+    if (s->params.stream_offset == 0) {
+      EncodeWindowBits(lgwin, s->params.large_window,
+                       &s->last_bytes_, &s->last_bytes_bits_);
+    } else {
+      /* Bigger values have the same effect, but could cause overflows. */
+      s->params.stream_offset = BROTLI_MIN(size_t,
+          s->params.stream_offset, BROTLI_MAX_BACKWARD_LIMIT(lgwin));
+    }
   }
 
   if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
@@ -712,13 +742,15 @@
   params->quality = BROTLI_DEFAULT_QUALITY;
   params->lgwin = BROTLI_DEFAULT_WINDOW;
   params->lgblock = 0;
+  params->stream_offset = 0;
   params->size_hint = 0;
   params->disable_literal_context_modeling = BROTLI_FALSE;
   BrotliInitEncoderDictionary(&params->dictionary);
   params->dist.distance_postfix_bits = 0;
   params->dist.num_direct_distance_codes = 0;
-  params->dist.alphabet_size =
+  params->dist.alphabet_size_max =
       BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_MAX_DISTANCE_BITS);
+  params->dist.alphabet_size_limit = params->dist.alphabet_size_max;
   params->dist.max_distance = BROTLI_MAX_DISTANCE;
 }
 
@@ -734,7 +766,7 @@
   s->prev_byte2_ = 0;
   s->storage_size_ = 0;
   s->storage_ = 0;
-  s->hasher_ = NULL;
+  HasherInit(&s->hasher_);
   s->large_table_ = NULL;
   s->large_table_size_ = 0;
   s->cmd_code_numbits_ = 0;
@@ -902,6 +934,7 @@
         (*bytes)--;
         (*wrapped_last_processed_pos)++;
       }
+    } else {
     }
     /* The copy length is at most the metablock size, and thus expressible. */
     GetLengthCode(last_command->insert_len_,
@@ -934,6 +967,7 @@
   uint32_t mask;
   MemoryManager* m = &s->memory_manager_;
   ContextType literal_context_mode;
+  ContextLut literal_context_lut;
 
   data = s->ringbuffer_.buffer_;
   mask = s->ringbuffer_.mask_;
@@ -951,7 +985,10 @@
         BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize);
     s->literal_buf_ =
         BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize);
-    if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) ||
+        BROTLI_IS_NULL(s->literal_buf_)) {
+      return BROTLI_FALSE;
+    }
   }
 
   if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
@@ -1009,7 +1046,7 @@
       newsize += (bytes / 4) + 16;
       s->cmd_alloc_size_ = newsize;
       new_commands = BROTLI_ALLOC(m, Command, newsize);
-      if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+      if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) return BROTLI_FALSE;
       if (s->commands_) {
         memcpy(new_commands, s->commands_, sizeof(Command) * s->num_commands_);
         BROTLI_FREE(m, s->commands_);
@@ -1024,6 +1061,7 @@
   literal_context_mode = ChooseContextMode(
       &s->params, data, WrapPosition(s->last_flush_pos_),
       mask, (size_t)(s->input_pos_ - s->last_flush_pos_));
+  literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
 
   if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
 
@@ -1034,20 +1072,23 @@
   if (s->params.quality == ZOPFLIFICATION_QUALITY) {
     BROTLI_DCHECK(s->params.hasher.type == 10);
     BrotliCreateZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
-        data, mask, &s->params, s->hasher_, s->dist_cache_,
+        data, mask, literal_context_lut, &s->params,
+        &s->hasher_, s->dist_cache_,
         &s->last_insert_len_, &s->commands_[s->num_commands_],
         &s->num_commands_, &s->num_literals_);
     if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
   } else if (s->params.quality == HQ_ZOPFLIFICATION_QUALITY) {
     BROTLI_DCHECK(s->params.hasher.type == 10);
     BrotliCreateHqZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
-        data, mask, &s->params, s->hasher_, s->dist_cache_,
+        data, mask, literal_context_lut, &s->params,
+        &s->hasher_, s->dist_cache_,
         &s->last_insert_len_, &s->commands_[s->num_commands_],
         &s->num_commands_, &s->num_literals_);
     if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
   } else {
     BrotliCreateBackwardReferences(bytes, wrapped_last_processed_pos,
-        data, mask, &s->params, s->hasher_, s->dist_cache_,
+        data, mask, literal_context_lut, &s->params,
+        &s->hasher_, s->dist_cache_,
         &s->last_insert_len_, &s->commands_[s->num_commands_],
         &s->num_commands_, &s->num_literals_);
   }
@@ -1072,7 +1113,7 @@
         s->num_commands_ < max_commands) {
       /* Merge with next input block. Everything will happen later. */
       if (UpdateLastProcessedPos(s)) {
-        HasherReset(s->hasher_);
+        HasherReset(&s->hasher_);
       }
       *out_size = 0;
       return BROTLI_TRUE;
@@ -1113,7 +1154,7 @@
     s->last_bytes_bits_ = storage_ix & 7u;
     s->last_flush_pos_ = s->input_pos_;
     if (UpdateLastProcessedPos(s)) {
-      HasherReset(s->hasher_);
+      HasherReset(&s->hasher_);
     }
     if (s->last_flush_pos_ > 0) {
       s->prev_byte_ = data[((uint32_t)s->last_flush_pos_ - 1) & mask];
@@ -1174,7 +1215,6 @@
   size_t total_out_size = 0;
   uint16_t last_bytes;
   uint8_t last_bytes_bits;
-  HasherHandle hasher = NULL;
 
   const size_t hasher_eff_size = BROTLI_MIN(size_t,
       input_size, BROTLI_MAX_BACKWARD_LIMIT(lgwin) + BROTLI_WINDOW_GAP);
@@ -1190,6 +1230,9 @@
   uint8_t prev_byte = 0;
   uint8_t prev_byte2 = 0;
 
+  Hasher hasher;
+  HasherInit(&hasher);
+
   BrotliEncoderInitParams(&params);
   params.quality = 10;
   params.lgwin = lgwin;
@@ -1226,6 +1269,7 @@
 
     ContextType literal_context_mode = ChooseContextMode(&params,
         input_buffer, metablock_start, mask, metablock_end - metablock_start);
+    ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
 
     size_t block_start;
     for (block_start = metablock_start; block_start < metablock_end; ) {
@@ -1234,12 +1278,12 @@
       ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, block_size + 1);
       size_t path_size;
       size_t new_cmd_alloc_size;
-      if (BROTLI_IS_OOM(m)) goto oom;
+      if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) goto oom;
       BrotliInitZopfliNodes(nodes, block_size + 1);
-      StitchToPreviousBlockH10(hasher, block_size, block_start,
+      StitchToPreviousBlockH10(&hasher.privat._H10, block_size, block_start,
                                input_buffer, mask);
       path_size = BrotliZopfliComputeShortestPath(m, block_size, block_start,
-          input_buffer, mask, &params, dist_cache, hasher,
+          input_buffer, mask, literal_context_lut, &params, dist_cache, &hasher,
           nodes);
       if (BROTLI_IS_OOM(m)) goto oom;
       /* We allocate a command buffer in the first iteration of this loop that
@@ -1254,7 +1298,7 @@
                                       num_commands + path_size + 1);
       if (cmd_alloc_size != new_cmd_alloc_size) {
         Command* new_commands = BROTLI_ALLOC(m, Command, new_cmd_alloc_size);
-        if (BROTLI_IS_OOM(m)) goto oom;
+        if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) goto oom;
         cmd_alloc_size = new_cmd_alloc_size;
         if (commands) {
           memcpy(new_commands, commands, sizeof(Command) * num_commands);
@@ -1286,7 +1330,7 @@
     if (metablock_size == 0) {
       /* Write the ISLAST and ISEMPTY bits. */
       storage = BROTLI_ALLOC(m, uint8_t, 16);
-      if (BROTLI_IS_OOM(m)) goto oom;
+      if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
       storage[0] = (uint8_t)last_bytes;
       storage[1] = (uint8_t)(last_bytes >> 8);
       BrotliWriteBits(2, 3, &storage_ix, storage);
@@ -1297,7 +1341,7 @@
          CreateBackwardReferences is now unused. */
       memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
       storage = BROTLI_ALLOC(m, uint8_t, metablock_size + 16);
-      if (BROTLI_IS_OOM(m)) goto oom;
+      if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
       storage[0] = (uint8_t)last_bytes;
       storage[1] = (uint8_t)(last_bytes >> 8);
       BrotliStoreUncompressedMetaBlock(is_last, input_buffer,
@@ -1318,14 +1362,10 @@
         /* The number of distance symbols effectively used for distance
            histograms. It might be less than distance alphabet size
            for "Large Window Brotli" (32-bit). */
-        uint32_t num_effective_dist_codes = block_params.dist.alphabet_size;
-        if (num_effective_dist_codes > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) {
-          num_effective_dist_codes = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
-        }
-        BrotliOptimizeHistograms(num_effective_dist_codes, &mb);
+        BrotliOptimizeHistograms(block_params.dist.alphabet_size_limit, &mb);
       }
       storage = BROTLI_ALLOC(m, uint8_t, 2 * metablock_size + 503);
-      if (BROTLI_IS_OOM(m)) goto oom;
+      if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
       storage[0] = (uint8_t)last_bytes;
       storage[1] = (uint8_t)(last_bytes >> 8);
       BrotliStoreMetaBlock(m, input_buffer, metablock_start, metablock_size,
@@ -1576,7 +1616,10 @@
           BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize);
       s->literal_buf_ =
           BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize);
-      if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+      if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) ||
+          BROTLI_IS_NULL(s->literal_buf_)) {
+        return BROTLI_FALSE;
+      }
     }
     if (s->command_buf_) {
       command_buf = s->command_buf_;
@@ -1584,7 +1627,10 @@
     } else {
       tmp_command_buf = BROTLI_ALLOC(m, uint32_t, buf_size);
       tmp_literal_buf = BROTLI_ALLOC(m, uint8_t, buf_size);
-      if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
+      if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp_command_buf) ||
+          BROTLI_IS_NULL(tmp_literal_buf)) {
+        return BROTLI_FALSE;
+      }
       command_buf = tmp_command_buf;
       literal_buf = tmp_literal_buf;
     }
@@ -1640,8 +1686,10 @@
             &storage_ix, storage);
         if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
       }
-      *next_in += block_size;
-      *available_in -= block_size;
+      if (block_size != 0) {
+        *next_in += block_size;
+        *available_in -= block_size;
+      }
       if (inplace) {
         size_t out_bytes = storage_ix >> 3;
         BROTLI_DCHECK(out_bytes <= *available_out);
@@ -1786,6 +1834,10 @@
   }
   while (BROTLI_TRUE) {
     size_t remaining_block_size = RemainingInputBlockSize(s);
+    /* Shorten input to flint size. */
+    if (s->flint_ >= 0 && remaining_block_size > (size_t)s->flint_) {
+      remaining_block_size = (size_t)s->flint_;
+    }
 
     if (remaining_block_size != 0 && *available_in != 0) {
       size_t copy_input_size =
@@ -1793,10 +1845,18 @@
       CopyInputToRingBuffer(s, copy_input_size, *next_in);
       *next_in += copy_input_size;
       *available_in -= copy_input_size;
+      if (s->flint_ > 0) s->flint_ = (int8_t)(s->flint_ - (int)copy_input_size);
       continue;
     }
 
     if (InjectFlushOrPushOutput(s, available_out, next_out, total_out)) {
+      /* Exit the "emit flint" workflow. */
+      if (s->flint_ == BROTLI_FLINT_WAITING_FOR_FLUSHING) {
+        CheckFlushComplete(s);
+        if (s->stream_state_ == BROTLI_STREAM_PROCESSING) {
+          s->flint_ = BROTLI_FLINT_DONE;
+        }
+      }
       continue;
     }
 
@@ -1810,6 +1870,11 @@
         BROTLI_BOOL force_flush = TO_BROTLI_BOOL(
             (*available_in == 0) && op == BROTLI_OPERATION_FLUSH);
         BROTLI_BOOL result;
+        /* Force emitting (uncompressed) piece containing flint. */
+        if (!is_last && s->flint_ == 0) {
+          s->flint_ = BROTLI_FLINT_WAITING_FOR_FLUSHING;
+          force_flush = BROTLI_TRUE;
+        }
         UpdateSizeHint(s, *available_in);
         result = EncodeData(s, is_last, force_flush,
             &s->available_out_, &s->next_out_);
diff --git a/third_party/brotli/enc/encoder_dict.c b/third_party/brotli/enc/encoder_dict.c
index 8b2f6ad..c9e963b8 100644
--- a/third_party/brotli/enc/encoder_dict.c
+++ b/third_party/brotli/enc/encoder_dict.c
@@ -17,14 +17,15 @@
 
 void BrotliInitEncoderDictionary(BrotliEncoderDictionary* dict) {
   dict->words = BrotliGetDictionary();
+  dict->num_transforms = (uint32_t)BrotliGetTransforms()->num_transforms;
 
-  dict->hash_table = kStaticDictionaryHash;
+  dict->hash_table_words = kStaticDictionaryHashWords;
+  dict->hash_table_lengths = kStaticDictionaryHashLengths;
   dict->buckets = kStaticDictionaryBuckets;
   dict->dict_words = kStaticDictionaryWords;
 
   dict->cutoffTransformsCount = kCutoffTransformsCount;
   dict->cutoffTransforms = kCutoffTransforms;
-
 }
 
 #if defined(__cplusplus) || defined(c_plusplus)
diff --git a/third_party/brotli/enc/encoder_dict.h b/third_party/brotli/enc/encoder_dict.h
index 3cb6b0ac..a1c329fb 100644
--- a/third_party/brotli/enc/encoder_dict.h
+++ b/third_party/brotli/enc/encoder_dict.h
@@ -19,13 +19,15 @@
 /* Dictionary data (words and transforms) for 1 possible context */
 typedef struct BrotliEncoderDictionary {
   const BrotliDictionary* words;
+  uint32_t num_transforms;
 
   /* cut off for fast encoder */
   uint32_t cutoffTransformsCount;
   uint64_t cutoffTransforms;
 
   /* from dictionary_hash.h, for fast encoder */
-  const uint16_t* hash_table;
+  const uint16_t* hash_table_words;
+  const uint8_t* hash_table_lengths;
 
   /* from static_dict_lut.h, for slow encoder */
   const uint16_t* buckets;
diff --git a/third_party/brotli/enc/entropy_encode.c b/third_party/brotli/enc/entropy_encode.c
index 97f9dfb8..b50ccb5d 100644
--- a/third_party/brotli/enc/entropy_encode.c
+++ b/third_party/brotli/enc/entropy_encode.c
@@ -18,6 +18,8 @@
 extern "C" {
 #endif
 
+const size_t kBrotliShellGaps[] = {132, 57, 23, 10, 4, 1};
+
 BROTLI_BOOL BrotliSetDepth(
     int p0, HuffmanTree* pool, uint8_t* depth, int max_depth) {
   int stack[16];
diff --git a/third_party/brotli/enc/entropy_encode.h b/third_party/brotli/enc/entropy_encode.h
index f23d9c37..9618e1d 100644
--- a/third_party/brotli/enc/entropy_encode.h
+++ b/third_party/brotli/enc/entropy_encode.h
@@ -76,12 +76,12 @@
                                                      size_t len,
                                                      uint16_t* bits);
 
+BROTLI_INTERNAL extern const size_t kBrotliShellGaps[6];
 /* Input size optimized Shell sort. */
 typedef BROTLI_BOOL (*HuffmanTreeComparator)(
     const HuffmanTree*, const HuffmanTree*);
 static BROTLI_INLINE void SortHuffmanTreeItems(HuffmanTree* items,
     const size_t n, HuffmanTreeComparator comparator) {
-  static const size_t gaps[] = {132, 57, 23, 10, 4, 1};
   if (n < 13) {
     /* Insertion sort. */
     size_t i;
@@ -101,7 +101,7 @@
     /* Shell sort. */
     int g = n < 57 ? 2 : 0;
     for (; g < 6; ++g) {
-      size_t gap = gaps[g];
+      size_t gap = kBrotliShellGaps[g];
       size_t i;
       for (i = gap; i < n; ++i) {
         size_t j = i;
diff --git a/third_party/brotli/enc/fast_log.c b/third_party/brotli/enc/fast_log.c
new file mode 100644
index 0000000..2319bae
--- /dev/null
+++ b/third_party/brotli/enc/fast_log.c
@@ -0,0 +1,105 @@
+/* Copyright 2013 Google Inc. All Rights Reserved.
+
+   Distributed under MIT license.
+   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#include "./fast_log.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* ", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */
+const double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE] = {
+  0.0000000000000000f, 0.0000000000000000f, 1.0000000000000000f,
+  1.5849625007211563f, 2.0000000000000000f, 2.3219280948873622f,
+  2.5849625007211561f, 2.8073549220576042f, 3.0000000000000000f,
+  3.1699250014423126f, 3.3219280948873626f, 3.4594316186372978f,
+  3.5849625007211565f, 3.7004397181410922f, 3.8073549220576037f,
+  3.9068905956085187f, 4.0000000000000000f, 4.0874628412503400f,
+  4.1699250014423122f, 4.2479275134435852f, 4.3219280948873626f,
+  4.3923174227787607f, 4.4594316186372973f, 4.5235619560570131f,
+  4.5849625007211570f, 4.6438561897747244f, 4.7004397181410926f,
+  4.7548875021634691f, 4.8073549220576037f, 4.8579809951275728f,
+  4.9068905956085187f, 4.9541963103868758f, 5.0000000000000000f,
+  5.0443941193584534f, 5.0874628412503400f, 5.1292830169449664f,
+  5.1699250014423122f, 5.2094533656289501f, 5.2479275134435852f,
+  5.2854022188622487f, 5.3219280948873626f, 5.3575520046180838f,
+  5.3923174227787607f, 5.4262647547020979f, 5.4594316186372973f,
+  5.4918530963296748f, 5.5235619560570131f, 5.5545888516776376f,
+  5.5849625007211570f, 5.6147098441152083f, 5.6438561897747244f,
+  5.6724253419714961f, 5.7004397181410926f, 5.7279204545631996f,
+  5.7548875021634691f, 5.7813597135246599f, 5.8073549220576046f,
+  5.8328900141647422f, 5.8579809951275719f, 5.8826430493618416f,
+  5.9068905956085187f, 5.9307373375628867f, 5.9541963103868758f,
+  5.9772799234999168f, 6.0000000000000000f, 6.0223678130284544f,
+  6.0443941193584534f, 6.0660891904577721f, 6.0874628412503400f,
+  6.1085244567781700f, 6.1292830169449672f, 6.1497471195046822f,
+  6.1699250014423122f, 6.1898245588800176f, 6.2094533656289510f,
+  6.2288186904958804f, 6.2479275134435861f, 6.2667865406949019f,
+  6.2854022188622487f, 6.3037807481771031f, 6.3219280948873617f,
+  6.3398500028846252f, 6.3575520046180847f, 6.3750394313469254f,
+  6.3923174227787598f, 6.4093909361377026f, 6.4262647547020979f,
+  6.4429434958487288f, 6.4594316186372982f, 6.4757334309663976f,
+  6.4918530963296748f, 6.5077946401986964f, 6.5235619560570131f,
+  6.5391588111080319f, 6.5545888516776376f, 6.5698556083309478f,
+  6.5849625007211561f, 6.5999128421871278f, 6.6147098441152092f,
+  6.6293566200796095f, 6.6438561897747253f, 6.6582114827517955f,
+  6.6724253419714952f, 6.6865005271832185f, 6.7004397181410917f,
+  6.7142455176661224f, 6.7279204545631988f, 6.7414669864011465f,
+  6.7548875021634691f, 6.7681843247769260f, 6.7813597135246599f,
+  6.7944158663501062f, 6.8073549220576037f, 6.8201789624151887f,
+  6.8328900141647422f, 6.8454900509443757f, 6.8579809951275719f,
+  6.8703647195834048f, 6.8826430493618416f, 6.8948177633079437f,
+  6.9068905956085187f, 6.9188632372745955f, 6.9307373375628867f,
+  6.9425145053392399f, 6.9541963103868758f, 6.9657842846620879f,
+  6.9772799234999168f, 6.9886846867721664f, 7.0000000000000000f,
+  7.0112272554232540f, 7.0223678130284544f, 7.0334230015374501f,
+  7.0443941193584534f, 7.0552824355011898f, 7.0660891904577721f,
+  7.0768155970508317f, 7.0874628412503400f, 7.0980320829605272f,
+  7.1085244567781700f, 7.1189410727235076f, 7.1292830169449664f,
+  7.1395513523987937f, 7.1497471195046822f, 7.1598713367783891f,
+  7.1699250014423130f, 7.1799090900149345f, 7.1898245588800176f,
+  7.1996723448363644f, 7.2094533656289492f, 7.2191685204621621f,
+  7.2288186904958804f, 7.2384047393250794f, 7.2479275134435861f,
+  7.2573878426926521f, 7.2667865406949019f, 7.2761244052742384f,
+  7.2854022188622487f, 7.2946207488916270f, 7.3037807481771031f,
+  7.3128829552843557f, 7.3219280948873617f, 7.3309168781146177f,
+  7.3398500028846243f, 7.3487281542310781f, 7.3575520046180847f,
+  7.3663222142458151f, 7.3750394313469254f, 7.3837042924740528f,
+  7.3923174227787607f, 7.4008794362821844f, 7.4093909361377026f,
+  7.4178525148858991f, 7.4262647547020979f, 7.4346282276367255f,
+  7.4429434958487288f, 7.4512111118323299f, 7.4594316186372973f,
+  7.4676055500829976f, 7.4757334309663976f, 7.4838157772642564f,
+  7.4918530963296748f, 7.4998458870832057f, 7.5077946401986964f,
+  7.5156998382840436f, 7.5235619560570131f, 7.5313814605163119f,
+  7.5391588111080319f, 7.5468944598876373f, 7.5545888516776376f,
+  7.5622424242210728f, 7.5698556083309478f, 7.5774288280357487f,
+  7.5849625007211561f, 7.5924570372680806f, 7.5999128421871278f,
+  7.6073303137496113f, 7.6147098441152075f, 7.6220518194563764f,
+  7.6293566200796095f, 7.6366246205436488f, 7.6438561897747244f,
+  7.6510516911789290f, 7.6582114827517955f, 7.6653359171851765f,
+  7.6724253419714952f, 7.6794800995054464f, 7.6865005271832185f,
+  7.6934869574993252f, 7.7004397181410926f, 7.7073591320808825f,
+  7.7142455176661224f, 7.7210991887071856f, 7.7279204545631996f,
+  7.7347096202258392f, 7.7414669864011465f, 7.7481928495894596f,
+  7.7548875021634691f, 7.7615512324444795f, 7.7681843247769260f,
+  7.7747870596011737f, 7.7813597135246608f, 7.7879025593914317f,
+  7.7944158663501062f, 7.8008998999203047f, 7.8073549220576037f,
+  7.8137811912170374f, 7.8201789624151887f, 7.8265484872909159f,
+  7.8328900141647422f, 7.8392037880969445f, 7.8454900509443757f,
+  7.8517490414160571f, 7.8579809951275719f, 7.8641861446542798f,
+  7.8703647195834048f, 7.8765169465650002f, 7.8826430493618425f,
+  7.8887432488982601f, 7.8948177633079446f, 7.9008668079807496f,
+  7.9068905956085187f, 7.9128893362299619f, 7.9188632372745955f,
+  7.9248125036057813f, 7.9307373375628867f, 7.9366379390025719f,
+  7.9425145053392399f, 7.9483672315846778f, 7.9541963103868758f,
+  7.9600019320680806f, 7.9657842846620870f, 7.9715435539507720f,
+  7.9772799234999168f, 7.9829935746943104f, 7.9886846867721664f,
+  7.9943534368588578f
+};
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}  /* extern "C" */
+#endif
diff --git a/third_party/brotli/enc/fast_log.h b/third_party/brotli/enc/fast_log.h
index cade1235..2094f13e 100644
--- a/third_party/brotli/enc/fast_log.h
+++ b/third_party/brotli/enc/fast_log.h
@@ -19,10 +19,8 @@
 #endif
 
 static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) {
-  /* TODO: generalize and move to platform.h */
-#if BROTLI_GNUC_HAS_BUILTIN(__builtin_clz, 3, 4, 0) || \
-    BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
-  return 31u ^ (uint32_t)__builtin_clz((uint32_t)n);
+#if defined(BROTLI_BSR32)
+  return BROTLI_BSR32((uint32_t)n);
 #else
   uint32_t result = 0;
   while (n >>= 1) result++;
@@ -30,110 +28,31 @@
 #endif
 }
 
-/* A lookup table for small values of log2(int) to be used in entropy
-   computation.
+#define BROTLI_LOG2_TABLE_SIZE 256
 
-   ", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */
-static const float kLog2Table[] = {
-  0.0000000000000000f, 0.0000000000000000f, 1.0000000000000000f,
-  1.5849625007211563f, 2.0000000000000000f, 2.3219280948873622f,
-  2.5849625007211561f, 2.8073549220576042f, 3.0000000000000000f,
-  3.1699250014423126f, 3.3219280948873626f, 3.4594316186372978f,
-  3.5849625007211565f, 3.7004397181410922f, 3.8073549220576037f,
-  3.9068905956085187f, 4.0000000000000000f, 4.0874628412503400f,
-  4.1699250014423122f, 4.2479275134435852f, 4.3219280948873626f,
-  4.3923174227787607f, 4.4594316186372973f, 4.5235619560570131f,
-  4.5849625007211570f, 4.6438561897747244f, 4.7004397181410926f,
-  4.7548875021634691f, 4.8073549220576037f, 4.8579809951275728f,
-  4.9068905956085187f, 4.9541963103868758f, 5.0000000000000000f,
-  5.0443941193584534f, 5.0874628412503400f, 5.1292830169449664f,
-  5.1699250014423122f, 5.2094533656289501f, 5.2479275134435852f,
-  5.2854022188622487f, 5.3219280948873626f, 5.3575520046180838f,
-  5.3923174227787607f, 5.4262647547020979f, 5.4594316186372973f,
-  5.4918530963296748f, 5.5235619560570131f, 5.5545888516776376f,
-  5.5849625007211570f, 5.6147098441152083f, 5.6438561897747244f,
-  5.6724253419714961f, 5.7004397181410926f, 5.7279204545631996f,
-  5.7548875021634691f, 5.7813597135246599f, 5.8073549220576046f,
-  5.8328900141647422f, 5.8579809951275719f, 5.8826430493618416f,
-  5.9068905956085187f, 5.9307373375628867f, 5.9541963103868758f,
-  5.9772799234999168f, 6.0000000000000000f, 6.0223678130284544f,
-  6.0443941193584534f, 6.0660891904577721f, 6.0874628412503400f,
-  6.1085244567781700f, 6.1292830169449672f, 6.1497471195046822f,
-  6.1699250014423122f, 6.1898245588800176f, 6.2094533656289510f,
-  6.2288186904958804f, 6.2479275134435861f, 6.2667865406949019f,
-  6.2854022188622487f, 6.3037807481771031f, 6.3219280948873617f,
-  6.3398500028846252f, 6.3575520046180847f, 6.3750394313469254f,
-  6.3923174227787598f, 6.4093909361377026f, 6.4262647547020979f,
-  6.4429434958487288f, 6.4594316186372982f, 6.4757334309663976f,
-  6.4918530963296748f, 6.5077946401986964f, 6.5235619560570131f,
-  6.5391588111080319f, 6.5545888516776376f, 6.5698556083309478f,
-  6.5849625007211561f, 6.5999128421871278f, 6.6147098441152092f,
-  6.6293566200796095f, 6.6438561897747253f, 6.6582114827517955f,
-  6.6724253419714952f, 6.6865005271832185f, 6.7004397181410917f,
-  6.7142455176661224f, 6.7279204545631988f, 6.7414669864011465f,
-  6.7548875021634691f, 6.7681843247769260f, 6.7813597135246599f,
-  6.7944158663501062f, 6.8073549220576037f, 6.8201789624151887f,
-  6.8328900141647422f, 6.8454900509443757f, 6.8579809951275719f,
-  6.8703647195834048f, 6.8826430493618416f, 6.8948177633079437f,
-  6.9068905956085187f, 6.9188632372745955f, 6.9307373375628867f,
-  6.9425145053392399f, 6.9541963103868758f, 6.9657842846620879f,
-  6.9772799234999168f, 6.9886846867721664f, 7.0000000000000000f,
-  7.0112272554232540f, 7.0223678130284544f, 7.0334230015374501f,
-  7.0443941193584534f, 7.0552824355011898f, 7.0660891904577721f,
-  7.0768155970508317f, 7.0874628412503400f, 7.0980320829605272f,
-  7.1085244567781700f, 7.1189410727235076f, 7.1292830169449664f,
-  7.1395513523987937f, 7.1497471195046822f, 7.1598713367783891f,
-  7.1699250014423130f, 7.1799090900149345f, 7.1898245588800176f,
-  7.1996723448363644f, 7.2094533656289492f, 7.2191685204621621f,
-  7.2288186904958804f, 7.2384047393250794f, 7.2479275134435861f,
-  7.2573878426926521f, 7.2667865406949019f, 7.2761244052742384f,
-  7.2854022188622487f, 7.2946207488916270f, 7.3037807481771031f,
-  7.3128829552843557f, 7.3219280948873617f, 7.3309168781146177f,
-  7.3398500028846243f, 7.3487281542310781f, 7.3575520046180847f,
-  7.3663222142458151f, 7.3750394313469254f, 7.3837042924740528f,
-  7.3923174227787607f, 7.4008794362821844f, 7.4093909361377026f,
-  7.4178525148858991f, 7.4262647547020979f, 7.4346282276367255f,
-  7.4429434958487288f, 7.4512111118323299f, 7.4594316186372973f,
-  7.4676055500829976f, 7.4757334309663976f, 7.4838157772642564f,
-  7.4918530963296748f, 7.4998458870832057f, 7.5077946401986964f,
-  7.5156998382840436f, 7.5235619560570131f, 7.5313814605163119f,
-  7.5391588111080319f, 7.5468944598876373f, 7.5545888516776376f,
-  7.5622424242210728f, 7.5698556083309478f, 7.5774288280357487f,
-  7.5849625007211561f, 7.5924570372680806f, 7.5999128421871278f,
-  7.6073303137496113f, 7.6147098441152075f, 7.6220518194563764f,
-  7.6293566200796095f, 7.6366246205436488f, 7.6438561897747244f,
-  7.6510516911789290f, 7.6582114827517955f, 7.6653359171851765f,
-  7.6724253419714952f, 7.6794800995054464f, 7.6865005271832185f,
-  7.6934869574993252f, 7.7004397181410926f, 7.7073591320808825f,
-  7.7142455176661224f, 7.7210991887071856f, 7.7279204545631996f,
-  7.7347096202258392f, 7.7414669864011465f, 7.7481928495894596f,
-  7.7548875021634691f, 7.7615512324444795f, 7.7681843247769260f,
-  7.7747870596011737f, 7.7813597135246608f, 7.7879025593914317f,
-  7.7944158663501062f, 7.8008998999203047f, 7.8073549220576037f,
-  7.8137811912170374f, 7.8201789624151887f, 7.8265484872909159f,
-  7.8328900141647422f, 7.8392037880969445f, 7.8454900509443757f,
-  7.8517490414160571f, 7.8579809951275719f, 7.8641861446542798f,
-  7.8703647195834048f, 7.8765169465650002f, 7.8826430493618425f,
-  7.8887432488982601f, 7.8948177633079446f, 7.9008668079807496f,
-  7.9068905956085187f, 7.9128893362299619f, 7.9188632372745955f,
-  7.9248125036057813f, 7.9307373375628867f, 7.9366379390025719f,
-  7.9425145053392399f, 7.9483672315846778f, 7.9541963103868758f,
-  7.9600019320680806f, 7.9657842846620870f, 7.9715435539507720f,
-  7.9772799234999168f, 7.9829935746943104f, 7.9886846867721664f,
-  7.9943534368588578f
-};
+/* A lookup table for small values of log2(int) to be used in entropy
+   computation. */
+BROTLI_INTERNAL extern const double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE];
+
+/* Visual Studio 2012 and Android API levels < 18 do not have the log2()
+ * function defined, so we use log() and a multiplication instead. */
+#if !defined(BROTLI_HAVE_LOG2)
+#if ((defined(_MSC_VER) && _MSC_VER <= 1700) || \
+     (defined(__ANDROID_API__) && __ANDROID_API__ < 18))
+#define BROTLI_HAVE_LOG2 0
+#else
+#define BROTLI_HAVE_LOG2 1
+#endif
+#endif
 
 #define LOG_2_INV 1.4426950408889634
 
 /* Faster logarithm for small integers, with the property of log2(0) == 0. */
 static BROTLI_INLINE double FastLog2(size_t v) {
-  if (v < sizeof(kLog2Table) / sizeof(kLog2Table[0])) {
-    return kLog2Table[v];
+  if (v < BROTLI_LOG2_TABLE_SIZE) {
+    return kBrotliLog2Table[v];
   }
-#if (defined(_MSC_VER) && _MSC_VER <= 1700) || \
-    (defined(__ANDROID_API__) && __ANDROID_API__ < 18)
-  /* Visual Studio 2012 and Android API levels < 18 do not have the log2()
-   * function defined, so we use log() and a multiplication instead. */
+#if !(BROTLI_HAVE_LOG2)
   return log((double)v) * LOG_2_INV;
 #else
   return log2((double)v);
diff --git a/third_party/brotli/enc/find_match_length.h b/third_party/brotli/enc/find_match_length.h
index bc428cff..f8853a70 100644
--- a/third_party/brotli/enc/find_match_length.h
+++ b/third_party/brotli/enc/find_match_length.h
@@ -17,8 +17,7 @@
 #endif
 
 /* Separate implementation for little-endian 64-bit targets, for speed. */
-#if defined(__GNUC__) && defined(_LP64) && defined(BROTLI_LITTLE_ENDIAN)
-
+#if defined(BROTLI_TZCNT64) && BROTLI_64_BITS && BROTLI_LITTLE_ENDIAN
 static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
                                                      const uint8_t* s2,
                                                      size_t limit) {
@@ -32,7 +31,7 @@
     } else {
       uint64_t x = BROTLI_UNALIGNED_LOAD64LE(s2) ^
           BROTLI_UNALIGNED_LOAD64LE(s1 + matched);
-      size_t matching_bits = (size_t)__builtin_ctzll(x);
+      size_t matching_bits = (size_t)BROTLI_TZCNT64(x);
       matched += matching_bits >> 3;
       return matched;
     }
diff --git a/third_party/brotli/enc/hash.h b/third_party/brotli/enc/hash.h
index 8c5a7bb..6362f69b 100644
--- a/third_party/brotli/enc/hash.h
+++ b/third_party/brotli/enc/hash.h
@@ -27,34 +27,19 @@
 extern "C" {
 #endif
 
-/* Pointer to hasher data.
- *
- * Excluding initialization and destruction, hasher can be passed as
- * HasherHandle by value.
- *
- * Typically hasher data consists of 3 sections:
- * * HasherCommon structure
- * * private structured hasher data, depending on hasher type
- * * private dynamic hasher data, depending on hasher type and parameters
- *
- * Using "define" instead of "typedef", because on MSVC __restrict does not work
- * on typedef pointer types. */
-#define HasherHandle uint8_t*
-
 typedef struct {
+  /* Dynamically allocated area; first member for quickest access. */
+  void* extra;
+
+  size_t dict_num_lookups;
+  size_t dict_num_matches;
+
   BrotliHasherParams params;
 
   /* False if hasher needs to be "prepared" before use. */
   BROTLI_BOOL is_prepared_;
-
-  size_t dict_num_lookups;
-  size_t dict_num_matches;
 } HasherCommon;
 
-static BROTLI_INLINE HasherCommon* GetHasherCommon(HasherHandle handle) {
-  return (HasherCommon*)handle;
-}
-
 #define score_t size_t
 
 static const uint32_t kCutoffTransformsCount = 10;
@@ -149,17 +134,13 @@
 }
 
 static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
-    const BrotliEncoderDictionary* dictionary, size_t item,
+    const BrotliEncoderDictionary* dictionary, size_t len, size_t word_idx,
     const uint8_t* data, size_t max_length, size_t max_backward,
     size_t max_distance, HasherSearchResult* out) {
-  size_t len;
-  size_t word_idx;
   size_t offset;
   size_t matchlen;
   size_t backward;
   score_t score;
-  len = item & 0x1F;
-  word_idx = item >> 5;
   offset = dictionary->words->offsets_by_length[len] + len * word_idx;
   if (len > max_length) {
     return BROTLI_FALSE;
@@ -193,25 +174,24 @@
 
 static BROTLI_INLINE void SearchInStaticDictionary(
     const BrotliEncoderDictionary* dictionary,
-    HasherHandle handle, const uint8_t* data, size_t max_length,
+    HasherCommon* common, const uint8_t* data, size_t max_length,
     size_t max_backward, size_t max_distance,
     HasherSearchResult* out, BROTLI_BOOL shallow) {
   size_t key;
   size_t i;
-  HasherCommon* self = GetHasherCommon(handle);
-  if (self->dict_num_matches < (self->dict_num_lookups >> 7)) {
+  if (common->dict_num_matches < (common->dict_num_lookups >> 7)) {
     return;
   }
   key = Hash14(data) << 1;
   for (i = 0; i < (shallow ? 1u : 2u); ++i, ++key) {
-    size_t item = dictionary->hash_table[key];
-    self->dict_num_lookups++;
-    if (item != 0) {
+    common->dict_num_lookups++;
+    if (dictionary->hash_table_lengths[key] != 0) {
       BROTLI_BOOL item_matches = TestStaticDictionaryItem(
-          dictionary, item, data,
+          dictionary, dictionary->hash_table_lengths[key],
+          dictionary->hash_table_words[key], data,
           max_length, max_backward, max_distance, out);
       if (item_matches) {
-        self->dict_num_matches++;
+        common->dict_num_matches++;
       }
     }
   }
@@ -260,37 +240,37 @@
 /* MAX_NUM_MATCHES == 64 + MAX_TREE_SEARCH_DEPTH */
 #define MAX_NUM_MATCHES_H10 128
 
-/* For BUCKET_SWEEP == 1, enabling the dictionary lookup makes compression
+/* For BUCKET_SWEEP_BITS == 0, enabling the dictionary lookup makes compression
    a little faster (0.5% - 1%) and it compresses 0.15% better on small text
    and HTML inputs. */
 
 #define HASHER() H2
 #define BUCKET_BITS 16
-#define BUCKET_SWEEP 1
+#define BUCKET_SWEEP_BITS 0
 #define HASH_LEN 5
 #define USE_DICTIONARY 1
 #include "./hash_longest_match_quickly_inc.h"  /* NOLINT(build/include) */
-#undef BUCKET_SWEEP
+#undef BUCKET_SWEEP_BITS
 #undef USE_DICTIONARY
 #undef HASHER
 
 #define HASHER() H3
-#define BUCKET_SWEEP 2
+#define BUCKET_SWEEP_BITS 1
 #define USE_DICTIONARY 0
 #include "./hash_longest_match_quickly_inc.h"  /* NOLINT(build/include) */
 #undef USE_DICTIONARY
-#undef BUCKET_SWEEP
+#undef BUCKET_SWEEP_BITS
 #undef BUCKET_BITS
 #undef HASHER
 
 #define HASHER() H4
 #define BUCKET_BITS 17
-#define BUCKET_SWEEP 4
+#define BUCKET_SWEEP_BITS 2
 #define USE_DICTIONARY 1
 #include "./hash_longest_match_quickly_inc.h"  /* NOLINT(build/include) */
 #undef USE_DICTIONARY
 #undef HASH_LEN
-#undef BUCKET_SWEEP
+#undef BUCKET_SWEEP_BITS
 #undef BUCKET_BITS
 #undef HASHER
 
@@ -334,13 +314,13 @@
 
 #define HASHER() H54
 #define BUCKET_BITS 20
-#define BUCKET_SWEEP 4
+#define BUCKET_SWEEP_BITS 2
 #define HASH_LEN 7
 #define USE_DICTIONARY 0
 #include "./hash_longest_match_quickly_inc.h"  /* NOLINT(build/include) */
 #undef USE_DICTIONARY
 #undef HASH_LEN
-#undef BUCKET_SWEEP
+#undef BUCKET_SWEEP_BITS
 #undef BUCKET_BITS
 #undef HASHER
 
@@ -393,97 +373,107 @@
 #undef CAT
 #undef EXPAND_CAT
 
-#define FOR_GENERIC_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)\
-                               H(35) H(55) H(65)
+#define FOR_SIMPLE_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)
+#define FOR_COMPOSITE_HASHERS(H) H(35) H(55) H(65)
+#define FOR_GENERIC_HASHERS(H) FOR_SIMPLE_HASHERS(H) FOR_COMPOSITE_HASHERS(H)
 #define FOR_ALL_HASHERS(H) FOR_GENERIC_HASHERS(H) H(10)
 
-static BROTLI_INLINE void DestroyHasher(
-    MemoryManager* m, HasherHandle* handle) {
-  if (*handle == NULL) return;
-  BROTLI_FREE(m, *handle);
+typedef struct {
+  HasherCommon common;
+
+  union {
+#define MEMBER_(N) \
+    H ## N _H ## N;
+    FOR_ALL_HASHERS(MEMBER_)
+#undef MEMBER_
+  } privat;
+} Hasher;
+
+/* MUST be invoked before any other method. */
+static BROTLI_INLINE void HasherInit(Hasher* hasher) {
+  hasher->common.extra = NULL;
 }
 
-static BROTLI_INLINE void HasherReset(HasherHandle handle) {
-  if (handle == NULL) return;
-  GetHasherCommon(handle)->is_prepared_ = BROTLI_FALSE;
+static BROTLI_INLINE void DestroyHasher(MemoryManager* m, Hasher* hasher) {
+  if (hasher->common.extra == NULL) return;
+  BROTLI_FREE(m, hasher->common.extra);
+}
+
+static BROTLI_INLINE void HasherReset(Hasher* hasher) {
+  hasher->common.is_prepared_ = BROTLI_FALSE;
 }
 
 static BROTLI_INLINE size_t HasherSize(const BrotliEncoderParams* params,
     BROTLI_BOOL one_shot, const size_t input_size) {
-  size_t result = sizeof(HasherCommon);
   switch (params->hasher.type) {
-#define SIZE_(N)                                                         \
-    case N:                                                              \
-      result += HashMemAllocInBytesH ## N(params, one_shot, input_size); \
-      break;
+#define SIZE_(N)                                                      \
+    case N:                                                           \
+      return HashMemAllocInBytesH ## N(params, one_shot, input_size);
     FOR_ALL_HASHERS(SIZE_)
 #undef SIZE_
     default:
       break;
   }
-  return result;
+  return 0;  /* Default case. */
 }
 
-static BROTLI_INLINE void HasherSetup(MemoryManager* m, HasherHandle* handle,
+static BROTLI_INLINE void HasherSetup(MemoryManager* m, Hasher* hasher,
     BrotliEncoderParams* params, const uint8_t* data, size_t position,
     size_t input_size, BROTLI_BOOL is_last) {
-  HasherHandle self = NULL;
-  HasherCommon* common = NULL;
   BROTLI_BOOL one_shot = (position == 0 && is_last);
-  if (*handle == NULL) {
+  if (hasher->common.extra == NULL) {
     size_t alloc_size;
     ChooseHasher(params, &params->hasher);
     alloc_size = HasherSize(params, one_shot, input_size);
-    self = BROTLI_ALLOC(m, uint8_t, alloc_size);
-    if (BROTLI_IS_OOM(m)) return;
-    *handle = self;
-    common = GetHasherCommon(self);
-    common->params = params->hasher;
-    switch (common->params.type) {
-#define INITIALIZE_(N)                     \
-      case N:                              \
-        InitializeH ## N(*handle, params); \
+    hasher->common.extra = BROTLI_ALLOC(m, uint8_t, alloc_size);
+    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(hasher->common.extra)) return;
+    hasher->common.params = params->hasher;
+    switch (hasher->common.params.type) {
+#define INITIALIZE_(N)                        \
+      case N:                                 \
+        InitializeH ## N(&hasher->common,     \
+            &hasher->privat._H ## N, params); \
         break;
       FOR_ALL_HASHERS(INITIALIZE_);
 #undef INITIALIZE_
       default:
         break;
     }
-    HasherReset(*handle);
+    HasherReset(hasher);
   }
 
-  self = *handle;
-  common = GetHasherCommon(self);
-  if (!common->is_prepared_) {
-    switch (common->params.type) {
-#define PREPARE_(N)                                      \
-      case N:                                            \
-        PrepareH ## N(self, one_shot, input_size, data); \
+  if (!hasher->common.is_prepared_) {
+    switch (hasher->common.params.type) {
+#define PREPARE_(N)                      \
+      case N:                            \
+        PrepareH ## N(                   \
+            &hasher->privat._H ## N,     \
+            one_shot, input_size, data); \
         break;
       FOR_ALL_HASHERS(PREPARE_)
 #undef PREPARE_
       default: break;
     }
     if (position == 0) {
-        common->dict_num_lookups = 0;
-        common->dict_num_matches = 0;
+      hasher->common.dict_num_lookups = 0;
+      hasher->common.dict_num_matches = 0;
     }
-    common->is_prepared_ = BROTLI_TRUE;
+    hasher->common.is_prepared_ = BROTLI_TRUE;
   }
 }
 
 static BROTLI_INLINE void InitOrStitchToPreviousBlock(
-    MemoryManager* m, HasherHandle* handle, const uint8_t* data, size_t mask,
+    MemoryManager* m, Hasher* hasher, const uint8_t* data, size_t mask,
     BrotliEncoderParams* params, size_t position, size_t input_size,
     BROTLI_BOOL is_last) {
-  HasherHandle self;
-  HasherSetup(m, handle, params, data, position, input_size, is_last);
+  HasherSetup(m, hasher, params, data, position, input_size, is_last);
   if (BROTLI_IS_OOM(m)) return;
-  self = *handle;
-  switch (GetHasherCommon(self)->params.type) {
-#define INIT_(N)                                                           \
-    case N:                                                                \
-      StitchToPreviousBlockH ## N(self, input_size, position, data, mask); \
+  switch (hasher->common.params.type) {
+#define INIT_(N)                             \
+    case N:                                  \
+      StitchToPreviousBlockH ## N(           \
+          &hasher->privat._H ## N,           \
+          input_size, position, data, mask); \
     break;
     FOR_ALL_HASHERS(INIT_)
 #undef INIT_
diff --git a/third_party/brotli/enc/hash_composite_inc.h b/third_party/brotli/enc/hash_composite_inc.h
index b266aa2f..cba156c0 100644
--- a/third_party/brotli/enc/hash_composite_inc.h
+++ b/third_party/brotli/enc/hash_composite_inc.h
@@ -28,20 +28,25 @@
 }
 
 typedef struct HashComposite {
-  HasherHandle ha;
-  HasherHandle hb;
+  HASHER_A ha;
+  HASHER_B hb;
+  HasherCommon hb_common;
+
+  /* Shortcuts. */
+  void* extra;
+  HasherCommon* common;
+
+  BROTLI_BOOL fresh;
   const BrotliEncoderParams* params;
 } HashComposite;
 
-static BROTLI_INLINE HashComposite* FN(Self)(HasherHandle handle) {
-  return (HashComposite*)&(GetHasherCommon(handle)[1]);
-}
+static void FN(Initialize)(HasherCommon* common,
+    HashComposite* BROTLI_RESTRICT self, const BrotliEncoderParams* params) {
+  self->common = common;
+  self->extra = common->extra;
 
-static void FN(Initialize)(
-    HasherHandle handle, const BrotliEncoderParams* params) {
-  HashComposite* self = FN(Self)(handle);
-  self->ha = 0;
-  self->hb = 0;
+  self->hb_common = *self->common;
+  self->fresh = BROTLI_TRUE;
   self->params = params;
   /* TODO: Initialize of the hashers is defered to Prepare (and params
      remembered here) because we don't get the one_shot and input_size params
@@ -49,87 +54,71 @@
      those params to all hashers FN(Initialize) */
 }
 
-static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
-    size_t input_size, const uint8_t* data) {
-  HashComposite* self = FN(Self)(handle);
-  if (!self->ha) {
-    HasherCommon* common_a;
-    HasherCommon* common_b;
+static void FN(Prepare)(
+    HashComposite* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
+    size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
+  if (self->fresh) {
+    self->fresh = BROTLI_FALSE;
+    self->hb_common.extra = (uint8_t*)self->extra +
+        FN_A(HashMemAllocInBytes)(self->params, one_shot, input_size);
 
-    self->ha = handle + sizeof(HasherCommon) + sizeof(HashComposite);
-    common_a = (HasherCommon*)self->ha;
-    common_a->params = self->params->hasher;
-    common_a->is_prepared_ = BROTLI_FALSE;
-    common_a->dict_num_lookups = 0;
-    common_a->dict_num_matches = 0;
-    FN_A(Initialize)(self->ha, self->params);
-
-    self->hb = self->ha + sizeof(HasherCommon) + FN_A(HashMemAllocInBytes)(
-        self->params, one_shot, input_size);
-    common_b = (HasherCommon*)self->hb;
-    common_b->params = self->params->hasher;
-    common_b->is_prepared_ = BROTLI_FALSE;
-    common_b->dict_num_lookups = 0;
-    common_b->dict_num_matches = 0;
-    FN_B(Initialize)(self->hb, self->params);
+    FN_A(Initialize)(self->common, &self->ha, self->params);
+    FN_B(Initialize)(&self->hb_common, &self->hb, self->params);
   }
-  FN_A(Prepare)(self->ha, one_shot, input_size, data);
-  FN_B(Prepare)(self->hb, one_shot, input_size, data);
+  FN_A(Prepare)(&self->ha, one_shot, input_size, data);
+  FN_B(Prepare)(&self->hb, one_shot, input_size, data);
 }
 
 static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
     const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
     size_t input_size) {
-  return sizeof(HashComposite) + 2 * sizeof(HasherCommon) +
-      FN_A(HashMemAllocInBytes)(params, one_shot, input_size) +
+  return FN_A(HashMemAllocInBytes)(params, one_shot, input_size) +
       FN_B(HashMemAllocInBytes)(params, one_shot, input_size);
 }
 
-static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle,
+static BROTLI_INLINE void FN(Store)(HashComposite* BROTLI_RESTRICT self,
     const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
-  HashComposite* self = FN(Self)(handle);
-  FN_A(Store)(self->ha, data, mask, ix);
-  FN_B(Store)(self->hb, data, mask, ix);
+  FN_A(Store)(&self->ha, data, mask, ix);
+  FN_B(Store)(&self->hb, data, mask, ix);
 }
 
-static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
-    const uint8_t* data, const size_t mask, const size_t ix_start,
+static BROTLI_INLINE void FN(StoreRange)(
+    HashComposite* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
+    const size_t mask, const size_t ix_start,
     const size_t ix_end) {
-  HashComposite* self = FN(Self)(handle);
-  FN_A(StoreRange)(self->ha, data, mask, ix_start, ix_end);
-  FN_B(StoreRange)(self->hb, data, mask, ix_start, ix_end);
+  FN_A(StoreRange)(&self->ha, data, mask, ix_start, ix_end);
+  FN_B(StoreRange)(&self->hb, data, mask, ix_start, ix_end);
 }
 
-static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
+static BROTLI_INLINE void FN(StitchToPreviousBlock)(
+    HashComposite* BROTLI_RESTRICT self,
     size_t num_bytes, size_t position, const uint8_t* ringbuffer,
     size_t ring_buffer_mask) {
-  HashComposite* self = FN(Self)(handle);
-  FN_A(StitchToPreviousBlock)(self->ha, num_bytes, position, ringbuffer,
-      ring_buffer_mask);
-  FN_B(StitchToPreviousBlock)(self->hb, num_bytes, position, ringbuffer,
-      ring_buffer_mask);
+  FN_A(StitchToPreviousBlock)(&self->ha, num_bytes, position,
+      ringbuffer, ring_buffer_mask);
+  FN_B(StitchToPreviousBlock)(&self->hb, num_bytes, position,
+      ringbuffer, ring_buffer_mask);
 }
 
 static BROTLI_INLINE void FN(PrepareDistanceCache)(
-    HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
-  HashComposite* self = FN(Self)(handle);
-  FN_A(PrepareDistanceCache)(self->ha, distance_cache);
-  FN_B(PrepareDistanceCache)(self->hb, distance_cache);
+    HashComposite* BROTLI_RESTRICT self, int* BROTLI_RESTRICT distance_cache) {
+  FN_A(PrepareDistanceCache)(&self->ha, distance_cache);
+  FN_B(PrepareDistanceCache)(&self->hb, distance_cache);
 }
 
-static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
+static BROTLI_INLINE void FN(FindLongestMatch)(
+    HashComposite* BROTLI_RESTRICT self,
     const BrotliEncoderDictionary* dictionary,
     const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
     const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
     const size_t max_length, const size_t max_backward,
-    const size_t gap, const size_t max_distance,
+    const size_t dictionary_distance, const size_t max_distance,
     HasherSearchResult* BROTLI_RESTRICT out) {
-  HashComposite* self = FN(Self)(handle);
-  FN_A(FindLongestMatch)(self->ha, dictionary, data, ring_buffer_mask,
-      distance_cache, cur_ix, max_length, max_backward, gap,
+  FN_A(FindLongestMatch)(&self->ha, dictionary, data, ring_buffer_mask,
+      distance_cache, cur_ix, max_length, max_backward, dictionary_distance,
       max_distance, out);
-  FN_B(FindLongestMatch)(self->hb, dictionary, data, ring_buffer_mask,
-      distance_cache, cur_ix, max_length, max_backward, gap,
+  FN_B(FindLongestMatch)(&self->hb, dictionary, data, ring_buffer_mask,
+      distance_cache, cur_ix, max_length, max_backward, dictionary_distance,
       max_distance, out);
 }
 
diff --git a/third_party/brotli/enc/hash_forgetful_chain_inc.h b/third_party/brotli/enc/hash_forgetful_chain_inc.h
index 41cb3ff..bfae6ba 100644
--- a/third_party/brotli/enc/hash_forgetful_chain_inc.h
+++ b/third_party/brotli/enc/hash_forgetful_chain_inc.h
@@ -28,7 +28,7 @@
 static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
 
 /* HashBytes is the function that chooses the bucket to place the address in.*/
-static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* data) {
+static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) {
   const uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
   /* The higher bits contain more mixture from the multiplication,
      so we take our results from there. */
@@ -45,28 +45,56 @@
 } FN(Bank);
 
 typedef struct HashForgetfulChain {
-  uint32_t addr[BUCKET_SIZE];
-  uint16_t head[BUCKET_SIZE];
-  /* Truncated hash used for quick rejection of "distance cache" candidates. */
-  uint8_t tiny_hash[65536];
-  FN(Bank) banks[NUM_BANKS];
-  uint16_t free_slot_idx[NUM_BANKS];
+  uint16_t free_slot_idx[NUM_BANKS];  /* Up to 1KiB. Move to dynamic? */
   size_t max_hops;
+
+  /* Shortcuts. */
+  void* extra;
+  HasherCommon* common;
+
+  /* --- Dynamic size members --- */
+
+  /* uint32_t addr[BUCKET_SIZE]; */
+
+  /* uint16_t head[BUCKET_SIZE]; */
+
+  /* Truncated hash used for quick rejection of "distance cache" candidates. */
+  /* uint8_t tiny_hash[65536];*/
+
+  /* FN(Bank) banks[NUM_BANKS]; */
 } HashForgetfulChain;
 
-static BROTLI_INLINE HashForgetfulChain* FN(Self)(HasherHandle handle) {
-  return (HashForgetfulChain*)&(GetHasherCommon(handle)[1]);
+static uint32_t* FN(Addr)(void* extra) {
+  return (uint32_t*)extra;
+}
+
+static uint16_t* FN(Head)(void* extra) {
+  return (uint16_t*)(&FN(Addr)(extra)[BUCKET_SIZE]);
+}
+
+static uint8_t* FN(TinyHash)(void* extra) {
+  return (uint8_t*)(&FN(Head)(extra)[BUCKET_SIZE]);
+}
+
+static FN(Bank)* FN(Banks)(void* extra) {
+  return (FN(Bank)*)(&FN(TinyHash)(extra)[65536]);
 }
 
 static void FN(Initialize)(
-    HasherHandle handle, const BrotliEncoderParams* params) {
-  FN(Self)(handle)->max_hops =
-      (params->quality > 6 ? 7u : 8u) << (params->quality - 4);
+    HasherCommon* common, HashForgetfulChain* BROTLI_RESTRICT self,
+    const BrotliEncoderParams* params) {
+  self->common = common;
+  self->extra = common->extra;
+
+  self->max_hops = (params->quality > 6 ? 7u : 8u) << (params->quality - 4);
 }
 
-static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
-    size_t input_size, const uint8_t* data) {
-  HashForgetfulChain* self = FN(Self)(handle);
+static void FN(Prepare)(
+    HashForgetfulChain* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
+    size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
+  uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
+  uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
+  uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra);
   /* Partial preparation is 100 times slower (per socket). */
   size_t partial_prepare_threshold = BUCKET_SIZE >> 6;
   if (one_shot && input_size <= partial_prepare_threshold) {
@@ -74,17 +102,17 @@
     for (i = 0; i < input_size; ++i) {
       size_t bucket = FN(HashBytes)(&data[i]);
       /* See InitEmpty comment. */
-      self->addr[bucket] = 0xCCCCCCCC;
-      self->head[bucket] = 0xCCCC;
+      addr[bucket] = 0xCCCCCCCC;
+      head[bucket] = 0xCCCC;
     }
   } else {
     /* Fill |addr| array with 0xCCCCCCCC value. Because of wrapping, position
        processed by hasher never reaches 3GB + 64M; this makes all new chains
        to be terminated after the first node. */
-    memset(self->addr, 0xCC, sizeof(self->addr));
-    memset(self->head, 0, sizeof(self->head));
+    memset(addr, 0xCC, sizeof(uint32_t) * BUCKET_SIZE);
+    memset(head, 0, sizeof(uint16_t) * BUCKET_SIZE);
   }
-  memset(self->tiny_hash, 0, sizeof(self->tiny_hash));
+  memset(tiny_hash, 0, sizeof(uint8_t) * 65536);
   memset(self->free_slot_idx, 0, sizeof(self->free_slot_idx));
 }
 
@@ -94,51 +122,58 @@
   BROTLI_UNUSED(params);
   BROTLI_UNUSED(one_shot);
   BROTLI_UNUSED(input_size);
-  return sizeof(HashForgetfulChain);
+  return sizeof(uint32_t) * BUCKET_SIZE + sizeof(uint16_t) * BUCKET_SIZE +
+         sizeof(uint8_t) * 65536 + sizeof(FN(Bank)) * NUM_BANKS;
 }
 
 /* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and prepend
    node to corresponding chain; also update tiny_hash for current position. */
-static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle,
+static BROTLI_INLINE void FN(Store)(HashForgetfulChain* BROTLI_RESTRICT self,
     const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
-  HashForgetfulChain* self = FN(Self)(handle);
+  uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
+  uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
+  uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra);
+  FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra);
   const size_t key = FN(HashBytes)(&data[ix & mask]);
   const size_t bank = key & (NUM_BANKS - 1);
   const size_t idx = self->free_slot_idx[bank]++ & (BANK_SIZE - 1);
-  size_t delta = ix - self->addr[key];
-  self->tiny_hash[(uint16_t)ix] = (uint8_t)key;
+  size_t delta = ix - addr[key];
+  tiny_hash[(uint16_t)ix] = (uint8_t)key;
   if (delta > 0xFFFF) delta = CAPPED_CHAINS ? 0 : 0xFFFF;
-  self->banks[bank].slots[idx].delta = (uint16_t)delta;
-  self->banks[bank].slots[idx].next = self->head[key];
-  self->addr[key] = (uint32_t)ix;
-  self->head[key] = (uint16_t)idx;
+  banks[bank].slots[idx].delta = (uint16_t)delta;
+  banks[bank].slots[idx].next = head[key];
+  addr[key] = (uint32_t)ix;
+  head[key] = (uint16_t)idx;
 }
 
-static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
-    const uint8_t* data, const size_t mask, const size_t ix_start,
-    const size_t ix_end) {
+static BROTLI_INLINE void FN(StoreRange)(
+    HashForgetfulChain* BROTLI_RESTRICT self,
+    const uint8_t* BROTLI_RESTRICT data, const size_t mask,
+    const size_t ix_start, const size_t ix_end) {
   size_t i;
   for (i = ix_start; i < ix_end; ++i) {
-    FN(Store)(handle, data, mask, i);
+    FN(Store)(self, data, mask, i);
   }
 }
 
-static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
+static BROTLI_INLINE void FN(StitchToPreviousBlock)(
+    HashForgetfulChain* BROTLI_RESTRICT self,
     size_t num_bytes, size_t position, const uint8_t* ringbuffer,
     size_t ring_buffer_mask) {
   if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
     /* Prepare the hashes for three last bytes of the last write.
        These could not be calculated before, since they require knowledge
        of both the previous and the current block. */
-    FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 3);
-    FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 2);
-    FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 1);
+    FN(Store)(self, ringbuffer, ring_buffer_mask, position - 3);
+    FN(Store)(self, ringbuffer, ring_buffer_mask, position - 2);
+    FN(Store)(self, ringbuffer, ring_buffer_mask, position - 1);
   }
 }
 
 static BROTLI_INLINE void FN(PrepareDistanceCache)(
-    HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
-  BROTLI_UNUSED(handle);
+    HashForgetfulChain* BROTLI_RESTRICT self,
+    int* BROTLI_RESTRICT distance_cache) {
+  BROTLI_UNUSED(self);
   PrepareDistanceCache(distance_cache, NUM_LAST_DISTANCES_TO_CHECK);
 }
 
@@ -153,14 +188,18 @@
    Does not look for matches further away than max_backward.
    Writes the best match into |out|.
    |out|->score is updated only if a better match is found. */
-static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
+static BROTLI_INLINE void FN(FindLongestMatch)(
+    HashForgetfulChain* BROTLI_RESTRICT self,
     const BrotliEncoderDictionary* dictionary,
     const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
     const int* BROTLI_RESTRICT distance_cache,
     const size_t cur_ix, const size_t max_length, const size_t max_backward,
-    const size_t gap, const size_t max_distance,
+    const size_t dictionary_distance, const size_t max_distance,
     HasherSearchResult* BROTLI_RESTRICT out) {
-  HashForgetfulChain* self = FN(Self)(handle);
+  uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
+  uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
+  uint8_t* BROTLI_RESTRICT tiny_hashes = FN(TinyHash)(self->extra);
+  FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra);
   const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
   /* Don't accept a short copy from far away. */
   score_t min_score = out->score;
@@ -176,7 +215,7 @@
     const size_t backward = (size_t)distance_cache[i];
     size_t prev_ix = (cur_ix - backward);
     /* For distance code 0 we want to consider 2-byte matches. */
-    if (i > 0 && self->tiny_hash[(uint16_t)prev_ix] != tiny_hash) continue;
+    if (i > 0 && tiny_hashes[(uint16_t)prev_ix] != tiny_hash) continue;
     if (prev_ix >= cur_ix || backward > max_backward) {
       continue;
     }
@@ -204,16 +243,16 @@
     const size_t bank = key & (NUM_BANKS - 1);
     size_t backward = 0;
     size_t hops = self->max_hops;
-    size_t delta = cur_ix - self->addr[key];
-    size_t slot = self->head[key];
+    size_t delta = cur_ix - addr[key];
+    size_t slot = head[key];
     while (hops--) {
       size_t prev_ix;
       size_t last = slot;
       backward += delta;
       if (backward > max_backward || (CAPPED_CHAINS && !delta)) break;
       prev_ix = (cur_ix - backward) & ring_buffer_mask;
-      slot = self->banks[bank].slots[last].next;
-      delta = self->banks[bank].slots[last].delta;
+      slot = banks[bank].slots[last].next;
+      delta = banks[bank].slots[last].delta;
       if (cur_ix_masked + best_len > ring_buffer_mask ||
           prev_ix + best_len > ring_buffer_mask ||
           data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
@@ -238,11 +277,11 @@
         }
       }
     }
-    FN(Store)(handle, data, ring_buffer_mask, cur_ix);
+    FN(Store)(self, data, ring_buffer_mask, cur_ix);
   }
   if (out->score == min_score) {
     SearchInStaticDictionary(dictionary,
-        handle, &data[cur_ix_masked], max_length, max_backward + gap,
+        self->common, &data[cur_ix_masked], max_length, dictionary_distance,
         max_distance, out, BROTLI_FALSE);
   }
 }
diff --git a/third_party/brotli/enc/hash_longest_match64_inc.h b/third_party/brotli/enc/hash_longest_match64_inc.h
index cb953a64..956fb30 100644
--- a/third_party/brotli/enc/hash_longest_match64_inc.h
+++ b/third_party/brotli/enc/hash_longest_match64_inc.h
@@ -20,7 +20,7 @@
 static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
 
 /* HashBytes is the function that chooses the bucket to place the address in. */
-static BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t* data,
+static BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data,
                                             const uint64_t mask,
                                             const int shift) {
   const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(data) & mask) * kHashMul64Long;
@@ -42,43 +42,43 @@
   /* Mask for accessing entries in a block (in a ring-buffer manner). */
   uint32_t block_mask_;
 
+  int block_bits_;
+  int num_last_distances_to_check_;
+
+  /* Shortcuts. */
+  HasherCommon* common_;
+
   /* --- Dynamic size members --- */
 
   /* Number of entries in a particular bucket. */
-  /* uint16_t num[bucket_size]; */
+  uint16_t* num_;  /* uint16_t[bucket_size]; */
 
   /* Buckets containing block_size_ of backward references. */
-  /* uint32_t* buckets[bucket_size * block_size]; */
+  uint32_t* buckets_;  /* uint32_t[bucket_size * block_size]; */
 } HashLongestMatch;
 
-static BROTLI_INLINE HashLongestMatch* FN(Self)(HasherHandle handle) {
-  return (HashLongestMatch*)&(GetHasherCommon(handle)[1]);
-}
-
-static BROTLI_INLINE uint16_t* FN(Num)(HashLongestMatch* self) {
-  return (uint16_t*)(&self[1]);
-}
-
-static BROTLI_INLINE uint32_t* FN(Buckets)(HashLongestMatch* self) {
-  return (uint32_t*)(&FN(Num)(self)[self->bucket_size_]);
-}
-
 static void FN(Initialize)(
-    HasherHandle handle, const BrotliEncoderParams* params) {
-  HasherCommon* common = GetHasherCommon(handle);
-  HashLongestMatch* self = FN(Self)(handle);
+    HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
+    const BrotliEncoderParams* params) {
+  self->common_ = common;
+
   BROTLI_UNUSED(params);
   self->hash_shift_ = 64 - common->params.bucket_bits;
   self->hash_mask_ = (~((uint64_t)0U)) >> (64 - 8 * common->params.hash_len);
   self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
+  self->block_bits_ = common->params.block_bits;
   self->block_size_ = (size_t)1 << common->params.block_bits;
   self->block_mask_ = (uint32_t)(self->block_size_ - 1);
+  self->num_last_distances_to_check_ =
+      common->params.num_last_distances_to_check;
+  self->num_ = (uint16_t*)common->extra;
+  self->buckets_ = (uint32_t*)&self->num_[self->bucket_size_];
 }
 
-static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
-    size_t input_size, const uint8_t* data) {
-  HashLongestMatch* self = FN(Self)(handle);
-  uint16_t* num = FN(Num)(self);
+static void FN(Prepare)(
+    HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
+    size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
+  uint16_t* BROTLI_RESTRICT num = self->num_;
   /* Partial preparation is 100 times slower (per socket). */
   size_t partial_prepare_threshold = self->bucket_size_ >> 6;
   if (one_shot && input_size <= partial_prepare_threshold) {
@@ -100,50 +100,52 @@
   size_t block_size = (size_t)1 << params->hasher.block_bits;
   BROTLI_UNUSED(one_shot);
   BROTLI_UNUSED(input_size);
-  return sizeof(HashLongestMatch) + bucket_size * (2 + 4 * block_size);
+  return sizeof(uint16_t) * bucket_size +
+         sizeof(uint32_t) * bucket_size * block_size;
 }
 
 /* Look at 4 bytes at &data[ix & mask].
    Compute a hash from these, and store the value of ix at that position. */
-static BROTLI_INLINE void FN(Store)(HasherHandle handle, const uint8_t* data,
+static BROTLI_INLINE void FN(Store)(
+    HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
     const size_t mask, const size_t ix) {
-  HashLongestMatch* self = FN(Self)(handle);
-  uint16_t* num = FN(Num)(self);
+  uint16_t* BROTLI_RESTRICT num = self->num_;
+  uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
   const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_mask_,
                                      self->hash_shift_);
   const size_t minor_ix = num[key] & self->block_mask_;
-  const size_t offset =
-      minor_ix + (key << GetHasherCommon(handle)->params.block_bits);
-  FN(Buckets)(self)[offset] = (uint32_t)ix;
+  const size_t offset = minor_ix + (key << self->block_bits_);
   ++num[key];
+  buckets[offset] = (uint32_t)ix;
 }
 
-static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
-    const uint8_t* data, const size_t mask, const size_t ix_start,
-    const size_t ix_end) {
+static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
+    const uint8_t* BROTLI_RESTRICT data, const size_t mask,
+    const size_t ix_start, const size_t ix_end) {
   size_t i;
   for (i = ix_start; i < ix_end; ++i) {
-    FN(Store)(handle, data, mask, i);
+    FN(Store)(self, data, mask, i);
   }
 }
 
-static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
+static BROTLI_INLINE void FN(StitchToPreviousBlock)(
+    HashLongestMatch* BROTLI_RESTRICT self,
     size_t num_bytes, size_t position, const uint8_t* ringbuffer,
     size_t ringbuffer_mask) {
   if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
     /* Prepare the hashes for three last bytes of the last write.
        These could not be calculated before, since they require knowledge
        of both the previous and the current block. */
-    FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3);
-    FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2);
-    FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1);
+    FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
+    FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
+    FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
   }
 }
 
 static BROTLI_INLINE void FN(PrepareDistanceCache)(
-    HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
-  PrepareDistanceCache(distance_cache,
-      GetHasherCommon(handle)->params.num_last_distances_to_check);
+    HashLongestMatch* BROTLI_RESTRICT self,
+    int* BROTLI_RESTRICT distance_cache) {
+  PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
 }
 
 /* Find a longest backward match of &data[cur_ix] up to the length of
@@ -157,17 +159,16 @@
    Does not look for matches further away than max_backward.
    Writes the best match into |out|.
    |out|->score is updated only if a better match is found. */
-static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
+static BROTLI_INLINE void FN(FindLongestMatch)(
+    HashLongestMatch* BROTLI_RESTRICT self,
     const BrotliEncoderDictionary* dictionary,
     const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
     const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
     const size_t max_length, const size_t max_backward,
-    const size_t gap, const size_t max_distance,
+    const size_t dictionary_distance, const size_t max_distance,
     HasherSearchResult* BROTLI_RESTRICT out) {
-  HasherCommon* common = GetHasherCommon(handle);
-  HashLongestMatch* self = FN(Self)(handle);
-  uint16_t* num = FN(Num)(self);
-  uint32_t* buckets = FN(Buckets)(self);
+  uint16_t* BROTLI_RESTRICT num = self->num_;
+  uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
   const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
   /* Don't accept a short copy from far away. */
   score_t min_score = out->score;
@@ -177,7 +178,7 @@
   out->len = 0;
   out->len_code_delta = 0;
   /* Try last distance first. */
-  for (i = 0; i < (size_t)common->params.num_last_distances_to_check; ++i) {
+  for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
     const size_t backward = (size_t)distance_cache[i];
     size_t prev_ix = (size_t)(cur_ix - backward);
     if (prev_ix >= cur_ix) {
@@ -218,8 +219,7 @@
   {
     const uint32_t key = FN(HashBytes)(
         &data[cur_ix_masked], self->hash_mask_, self->hash_shift_);
-    uint32_t* BROTLI_RESTRICT bucket =
-        &buckets[key << common->params.block_bits];
+    uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
     const size_t down =
         (num[key] > self->block_size_) ?
         (num[key] - self->block_size_) : 0u;
@@ -259,7 +259,7 @@
   }
   if (min_score == out->score) {
     SearchInStaticDictionary(dictionary,
-        handle, &data[cur_ix_masked], max_length, max_backward + gap,
+        self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
         max_distance, out, BROTLI_FALSE);
   }
 }
diff --git a/third_party/brotli/enc/hash_longest_match_inc.h b/third_party/brotli/enc/hash_longest_match_inc.h
index 457f5a9e..27f4463 100644
--- a/third_party/brotli/enc/hash_longest_match_inc.h
+++ b/third_party/brotli/enc/hash_longest_match_inc.h
@@ -20,7 +20,8 @@
 static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
 
 /* HashBytes is the function that chooses the bucket to place the address in. */
-static uint32_t FN(HashBytes)(const uint8_t* data, const int shift) {
+static uint32_t FN(HashBytes)(
+    const uint8_t* BROTLI_RESTRICT data, const int shift) {
   uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
   /* The higher bits contain more mixture from the multiplication,
      so we take our results from there. */
@@ -38,42 +39,46 @@
   /* Mask for accessing entries in a block (in a ring-buffer manner). */
   uint32_t block_mask_;
 
+  int block_bits_;
+  int num_last_distances_to_check_;
+
+  /* Shortcuts. */
+  HasherCommon* common_;
+
   /* --- Dynamic size members --- */
 
   /* Number of entries in a particular bucket. */
-  /* uint16_t num[bucket_size]; */
+  uint16_t* num_;  /* uint16_t[bucket_size]; */
 
   /* Buckets containing block_size_ of backward references. */
-  /* uint32_t* buckets[bucket_size * block_size]; */
+  uint32_t* buckets_;  /* uint32_t[bucket_size * block_size]; */
 } HashLongestMatch;
 
-static BROTLI_INLINE HashLongestMatch* FN(Self)(HasherHandle handle) {
-  return (HashLongestMatch*)&(GetHasherCommon(handle)[1]);
-}
-
-static BROTLI_INLINE uint16_t* FN(Num)(HashLongestMatch* self) {
-  return (uint16_t*)(&self[1]);
-}
-
-static BROTLI_INLINE uint32_t* FN(Buckets)(HashLongestMatch* self) {
-  return (uint32_t*)(&FN(Num)(self)[self->bucket_size_]);
+static BROTLI_INLINE uint16_t* FN(Num)(void* extra) {
+  return (uint16_t*)extra;
 }
 
 static void FN(Initialize)(
-    HasherHandle handle, const BrotliEncoderParams* params) {
-  HasherCommon* common = GetHasherCommon(handle);
-  HashLongestMatch* self = FN(Self)(handle);
+    HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
+    const BrotliEncoderParams* params) {
+  self->common_ = common;
+
   BROTLI_UNUSED(params);
   self->hash_shift_ = 32 - common->params.bucket_bits;
   self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
   self->block_size_ = (size_t)1 << common->params.block_bits;
   self->block_mask_ = (uint32_t)(self->block_size_ - 1);
+  self->num_ = (uint16_t*)common->extra;
+  self->buckets_ = (uint32_t*)(&self->num_[self->bucket_size_]);
+  self->block_bits_ = common->params.block_bits;
+  self->num_last_distances_to_check_ =
+      common->params.num_last_distances_to_check;
 }
 
-static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
-    size_t input_size, const uint8_t* data) {
-  HashLongestMatch* self = FN(Self)(handle);
-  uint16_t* num = FN(Num)(self);
+static void FN(Prepare)(
+    HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
+    size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
+  uint16_t* BROTLI_RESTRICT num = self->num_;
   /* Partial preparation is 100 times slower (per socket). */
   size_t partial_prepare_threshold = self->bucket_size_ >> 6;
   if (one_shot && input_size <= partial_prepare_threshold) {
@@ -94,49 +99,49 @@
   size_t block_size = (size_t)1 << params->hasher.block_bits;
   BROTLI_UNUSED(one_shot);
   BROTLI_UNUSED(input_size);
-  return sizeof(HashLongestMatch) + bucket_size * (2 + 4 * block_size);
+  return sizeof(uint16_t) * bucket_size +
+         sizeof(uint32_t) * bucket_size * block_size;
 }
 
 /* Look at 4 bytes at &data[ix & mask].
    Compute a hash from these, and store the value of ix at that position. */
-static BROTLI_INLINE void FN(Store)(HasherHandle handle, const uint8_t* data,
+static BROTLI_INLINE void FN(Store)(
+    HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
     const size_t mask, const size_t ix) {
-  HashLongestMatch* self = FN(Self)(handle);
-  uint16_t* num = FN(Num)(self);
   const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_shift_);
-  const size_t minor_ix = num[key] & self->block_mask_;
-  const size_t offset =
-      minor_ix + (key << GetHasherCommon(handle)->params.block_bits);
-  FN(Buckets)(self)[offset] = (uint32_t)ix;
-  ++num[key];
+  const size_t minor_ix = self->num_[key] & self->block_mask_;
+  const size_t offset = minor_ix + (key << self->block_bits_);
+  self->buckets_[offset] = (uint32_t)ix;
+  ++self->num_[key];
 }
 
-static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
-    const uint8_t* data, const size_t mask, const size_t ix_start,
-    const size_t ix_end) {
+static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
+    const uint8_t* BROTLI_RESTRICT data, const size_t mask,
+    const size_t ix_start, const size_t ix_end) {
   size_t i;
   for (i = ix_start; i < ix_end; ++i) {
-    FN(Store)(handle, data, mask, i);
+    FN(Store)(self, data, mask, i);
   }
 }
 
-static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
+static BROTLI_INLINE void FN(StitchToPreviousBlock)(
+    HashLongestMatch* BROTLI_RESTRICT self,
     size_t num_bytes, size_t position, const uint8_t* ringbuffer,
     size_t ringbuffer_mask) {
   if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
     /* Prepare the hashes for three last bytes of the last write.
        These could not be calculated before, since they require knowledge
        of both the previous and the current block. */
-    FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3);
-    FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2);
-    FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1);
+    FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
+    FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
+    FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
   }
 }
 
 static BROTLI_INLINE void FN(PrepareDistanceCache)(
-    HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
-  PrepareDistanceCache(distance_cache,
-      GetHasherCommon(handle)->params.num_last_distances_to_check);
+    HashLongestMatch* BROTLI_RESTRICT self,
+    int* BROTLI_RESTRICT distance_cache) {
+  PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
 }
 
 /* Find a longest backward match of &data[cur_ix] up to the length of
@@ -150,17 +155,16 @@
    Does not look for matches further away than max_backward.
    Writes the best match into |out|.
    |out|->score is updated only if a better match is found. */
-static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
+static BROTLI_INLINE void FN(FindLongestMatch)(
+    HashLongestMatch* BROTLI_RESTRICT self,
     const BrotliEncoderDictionary* dictionary,
     const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
     const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
     const size_t max_length, const size_t max_backward,
-    const size_t gap, const size_t max_distance,
+    const size_t dictionary_distance, const size_t max_distance,
     HasherSearchResult* BROTLI_RESTRICT out) {
-  HasherCommon* common = GetHasherCommon(handle);
-  HashLongestMatch* self = FN(Self)(handle);
-  uint16_t* num = FN(Num)(self);
-  uint32_t* buckets = FN(Buckets)(self);
+  uint16_t* BROTLI_RESTRICT num = self->num_;
+  uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
   const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
   /* Don't accept a short copy from far away. */
   score_t min_score = out->score;
@@ -170,7 +174,7 @@
   out->len = 0;
   out->len_code_delta = 0;
   /* Try last distance first. */
-  for (i = 0; i < (size_t)common->params.num_last_distances_to_check; ++i) {
+  for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
     const size_t backward = (size_t)distance_cache[i];
     size_t prev_ix = (size_t)(cur_ix - backward);
     if (prev_ix >= cur_ix) {
@@ -211,8 +215,7 @@
   {
     const uint32_t key =
         FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_);
-    uint32_t* BROTLI_RESTRICT bucket =
-        &buckets[key << common->params.block_bits];
+    uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
     const size_t down =
         (num[key] > self->block_size_) ? (num[key] - self->block_size_) : 0u;
     for (i = num[key]; i > down;) {
@@ -251,7 +254,7 @@
   }
   if (min_score == out->score) {
     SearchInStaticDictionary(dictionary,
-        handle, &data[cur_ix_masked], max_length, max_backward + gap,
+        self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
         max_distance, out, BROTLI_FALSE);
   }
 }
diff --git a/third_party/brotli/enc/hash_longest_match_quickly_inc.h b/third_party/brotli/enc/hash_longest_match_quickly_inc.h
index a7b9639f..e5ba840 100644
--- a/third_party/brotli/enc/hash_longest_match_quickly_inc.h
+++ b/third_party/brotli/enc/hash_longest_match_quickly_inc.h
@@ -5,15 +5,16 @@
    See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
 */
 
-/* template parameters: FN, BUCKET_BITS, BUCKET_SWEEP, HASH_LEN,
+/* template parameters: FN, BUCKET_BITS, BUCKET_SWEEP_BITS, HASH_LEN,
                         USE_DICTIONARY
  */
 
 #define HashLongestMatchQuickly HASHER()
 
 #define BUCKET_SIZE (1 << BUCKET_BITS)
-
-#define HASH_MAP_SIZE (4 << BUCKET_BITS)
+#define BUCKET_MASK (BUCKET_SIZE - 1)
+#define BUCKET_SWEEP (1 << BUCKET_SWEEP_BITS)
+#define BUCKET_SWEEP_MASK ((BUCKET_SWEEP - 1) << 3)
 
 static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
 static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
@@ -32,39 +33,50 @@
 /* A (forgetful) hash table to the data seen by the compressor, to
    help create backward references to previous data.
 
-   This is a hash map of fixed size (BUCKET_SIZE). Starting from the
-   given index, BUCKET_SWEEP buckets are used to store values of a key. */
+   This is a hash map of fixed size (BUCKET_SIZE). */
 typedef struct HashLongestMatchQuickly {
-  uint32_t buckets_[BUCKET_SIZE + BUCKET_SWEEP];
+  /* Shortcuts. */
+  HasherCommon* common;
+
+  /* --- Dynamic size members --- */
+
+  uint32_t* buckets_;  /* uint32_t[BUCKET_SIZE]; */
 } HashLongestMatchQuickly;
 
-static BROTLI_INLINE HashLongestMatchQuickly* FN(Self)(HasherHandle handle) {
-  return (HashLongestMatchQuickly*)&(GetHasherCommon(handle)[1]);
-}
-
 static void FN(Initialize)(
-    HasherHandle handle, const BrotliEncoderParams* params) {
-  BROTLI_UNUSED(handle);
+    HasherCommon* common, HashLongestMatchQuickly* BROTLI_RESTRICT self,
+    const BrotliEncoderParams* params) {
+  self->common = common;
+
   BROTLI_UNUSED(params);
+  self->buckets_ = (uint32_t*)common->extra;
 }
 
-static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
-    size_t input_size, const uint8_t* data) {
-  HashLongestMatchQuickly* self = FN(Self)(handle);
+static void FN(Prepare)(
+    HashLongestMatchQuickly* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
+    size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
+  uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
   /* Partial preparation is 100 times slower (per socket). */
-  size_t partial_prepare_threshold = HASH_MAP_SIZE >> 7;
+  size_t partial_prepare_threshold = BUCKET_SIZE >> 5;
   if (one_shot && input_size <= partial_prepare_threshold) {
     size_t i;
     for (i = 0; i < input_size; ++i) {
       const uint32_t key = FN(HashBytes)(&data[i]);
-      memset(&self->buckets_[key], 0, BUCKET_SWEEP * sizeof(self->buckets_[0]));
+      if (BUCKET_SWEEP == 1) {
+        buckets[key] = 0;
+      } else {
+        uint32_t j;
+        for (j = 0; j < BUCKET_SWEEP; ++j) {
+          buckets[(key + (j << 3)) & BUCKET_MASK] = 0;
+        }
+      }
     }
   } else {
     /* It is not strictly necessary to fill this buffer here, but
        not filling will make the results of the compression stochastic
        (but correct). This is because random data would cause the
        system to find accidentally good backward references here and there. */
-    memset(&self->buckets_[0], 0, sizeof(self->buckets_));
+    memset(buckets, 0, sizeof(uint32_t) * BUCKET_SIZE);
   }
 }
 
@@ -74,45 +86,53 @@
   BROTLI_UNUSED(params);
   BROTLI_UNUSED(one_shot);
   BROTLI_UNUSED(input_size);
-  return sizeof(HashLongestMatchQuickly);
+  return sizeof(uint32_t) * BUCKET_SIZE;
 }
 
 /* Look at 5 bytes at &data[ix & mask].
    Compute a hash from these, and store the value somewhere within
    [ix .. ix+3]. */
-static BROTLI_INLINE void FN(Store)(HasherHandle handle,
-    const uint8_t* data, const size_t mask, const size_t ix) {
+static BROTLI_INLINE void FN(Store)(
+    HashLongestMatchQuickly* BROTLI_RESTRICT self,
+    const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
   const uint32_t key = FN(HashBytes)(&data[ix & mask]);
-  /* Wiggle the value with the bucket sweep range. */
-  const uint32_t off = (ix >> 3) % BUCKET_SWEEP;
-  FN(Self)(handle)->buckets_[key + off] = (uint32_t)ix;
+  if (BUCKET_SWEEP == 1) {
+    self->buckets_[key] = (uint32_t)ix;
+  } else {
+    /* Wiggle the value with the bucket sweep range. */
+    const uint32_t off = ix & BUCKET_SWEEP_MASK;
+    self->buckets_[(key + off) & BUCKET_MASK] = (uint32_t)ix;
+  }
 }
 
-static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
-    const uint8_t* data, const size_t mask, const size_t ix_start,
-    const size_t ix_end) {
+static BROTLI_INLINE void FN(StoreRange)(
+    HashLongestMatchQuickly* BROTLI_RESTRICT self,
+    const uint8_t* BROTLI_RESTRICT data, const size_t mask,
+    const size_t ix_start, const size_t ix_end) {
   size_t i;
   for (i = ix_start; i < ix_end; ++i) {
-    FN(Store)(handle, data, mask, i);
+    FN(Store)(self, data, mask, i);
   }
 }
 
 static BROTLI_INLINE void FN(StitchToPreviousBlock)(
-    HasherHandle handle, size_t num_bytes, size_t position,
+    HashLongestMatchQuickly* BROTLI_RESTRICT self,
+    size_t num_bytes, size_t position,
     const uint8_t* ringbuffer, size_t ringbuffer_mask) {
   if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
     /* Prepare the hashes for three last bytes of the last write.
        These could not be calculated before, since they require knowledge
        of both the previous and the current block. */
-    FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3);
-    FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2);
-    FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1);
+    FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
+    FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
+    FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
   }
 }
 
 static BROTLI_INLINE void FN(PrepareDistanceCache)(
-    HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
-  BROTLI_UNUSED(handle);
+    HashLongestMatchQuickly* BROTLI_RESTRICT self,
+    int* BROTLI_RESTRICT distance_cache) {
+  BROTLI_UNUSED(self);
   BROTLI_UNUSED(distance_cache);
 }
 
@@ -125,17 +145,19 @@
    Writes the best match into |out|.
    |out|->score is updated only if a better match is found. */
 static BROTLI_INLINE void FN(FindLongestMatch)(
-    HasherHandle handle, const BrotliEncoderDictionary* dictionary,
+    HashLongestMatchQuickly* BROTLI_RESTRICT self,
+    const BrotliEncoderDictionary* dictionary,
     const uint8_t* BROTLI_RESTRICT data,
     const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache,
     const size_t cur_ix, const size_t max_length, const size_t max_backward,
-    const size_t gap, const size_t max_distance,
+    const size_t dictionary_distance, const size_t max_distance,
     HasherSearchResult* BROTLI_RESTRICT out) {
-  HashLongestMatchQuickly* self = FN(Self)(handle);
+  uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
   const size_t best_len_in = out->len;
   const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
-  const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]);
   int compare_char = data[cur_ix_masked + best_len_in];
+  size_t key = FN(HashBytes)(&data[cur_ix_masked]);
+  size_t key_out;
   score_t min_score = out->score;
   score_t best_score = out->score;
   size_t best_len = best_len_in;
@@ -145,21 +167,21 @@
   if (prev_ix < cur_ix) {
     prev_ix &= (uint32_t)ring_buffer_mask;
     if (compare_char == data[prev_ix + best_len]) {
-      size_t len = FindMatchLengthWithLimit(&data[prev_ix],
-                                            &data[cur_ix_masked],
-                                            max_length);
+      const size_t len = FindMatchLengthWithLimit(
+          &data[prev_ix], &data[cur_ix_masked], max_length);
       if (len >= 4) {
         const score_t score = BackwardReferenceScoreUsingLastDistance(len);
         if (best_score < score) {
-          best_score = score;
-          best_len = len;
           out->len = len;
           out->distance = cached_backward;
-          out->score = best_score;
-          compare_char = data[cur_ix_masked + best_len];
+          out->score = score;
           if (BUCKET_SWEEP == 1) {
-            self->buckets_[key] = (uint32_t)cur_ix;
+            buckets[key] = (uint32_t)cur_ix;
             return;
+          } else {
+            best_len = len;
+            best_score = score;
+            compare_char = data[cur_ix_masked + len];
           }
         }
       }
@@ -169,8 +191,8 @@
     size_t backward;
     size_t len;
     /* Only one to look for, don't bother to prepare for a loop. */
-    prev_ix = self->buckets_[key];
-    self->buckets_[key] = (uint32_t)cur_ix;
+    prev_ix = buckets[key];
+    buckets[key] = (uint32_t)cur_ix;
     backward = cur_ix - prev_ix;
     prev_ix &= (uint32_t)ring_buffer_mask;
     if (compare_char != data[prev_ix + best_len_in]) {
@@ -192,12 +214,17 @@
       }
     }
   } else {
-    uint32_t* bucket = self->buckets_ + key;
-    int i;
-    prev_ix = *bucket++;
-    for (i = 0; i < BUCKET_SWEEP; ++i, prev_ix = *bucket++) {
-      const size_t backward = cur_ix - prev_ix;
+    size_t keys[BUCKET_SWEEP];
+    size_t i;
+    for (i = 0; i < BUCKET_SWEEP; ++i) {
+      keys[i] = (key + (i << 3)) & BUCKET_MASK;
+    }
+    key_out = keys[(cur_ix & BUCKET_SWEEP_MASK) >> 3];
+    for (i = 0; i < BUCKET_SWEEP; ++i) {
       size_t len;
+      size_t backward;
+      prev_ix = buckets[keys[i]];
+      backward = cur_ix - prev_ix;
       prev_ix &= (uint32_t)ring_buffer_mask;
       if (compare_char != data[prev_ix + best_len]) {
         continue;
@@ -211,25 +238,29 @@
       if (len >= 4) {
         const score_t score = BackwardReferenceScore(len, backward);
         if (best_score < score) {
-          best_score = score;
           best_len = len;
-          out->len = best_len;
-          out->distance = backward;
+          out->len = len;
+          compare_char = data[cur_ix_masked + len];
+          best_score = score;
           out->score = score;
-          compare_char = data[cur_ix_masked + best_len];
+          out->distance = backward;
         }
       }
     }
   }
   if (USE_DICTIONARY && min_score == out->score) {
     SearchInStaticDictionary(dictionary,
-        handle, &data[cur_ix_masked], max_length, max_backward + gap,
+        self->common, &data[cur_ix_masked], max_length, dictionary_distance,
         max_distance, out, BROTLI_TRUE);
   }
-  self->buckets_[key + ((cur_ix >> 3) % BUCKET_SWEEP)] = (uint32_t)cur_ix;
+  if (BUCKET_SWEEP != 1) {
+    buckets[key_out] = (uint32_t)cur_ix;
+  }
 }
 
-#undef HASH_MAP_SIZE
+#undef BUCKET_SWEEP_MASK
+#undef BUCKET_SWEEP
+#undef BUCKET_MASK
 #undef BUCKET_SIZE
 
 #undef HashLongestMatchQuickly
diff --git a/third_party/brotli/enc/hash_rolling_inc.h b/third_party/brotli/enc/hash_rolling_inc.h
index 17f8a408..586ae73 100644
--- a/third_party/brotli/enc/hash_rolling_inc.h
+++ b/third_party/brotli/enc/hash_rolling_inc.h
@@ -51,13 +51,9 @@
   uint32_t factor_remove;
 } HashRolling;
 
-static BROTLI_INLINE HashRolling* FN(Self)(HasherHandle handle) {
-  return (HashRolling*)&(GetHasherCommon(handle)[1]);
-}
-
 static void FN(Initialize)(
-    HasherHandle handle, const BrotliEncoderParams* params) {
-  HashRolling* self = FN(Self)(handle);
+    HasherCommon* common, HashRolling* BROTLI_RESTRICT self,
+    const BrotliEncoderParams* params) {
   size_t i;
   self->state = 0;
   self->next_ix = 0;
@@ -71,7 +67,7 @@
     self->factor_remove *= self->factor;
   }
 
-  self->table = (uint32_t*)((HasherHandle)self + sizeof(HashRolling));
+  self->table = (uint32_t*)common->extra;
   for (i = 0; i < NUMBUCKETS; i++) {
     self->table[i] = FN(kInvalidPos);
   }
@@ -79,9 +75,8 @@
   BROTLI_UNUSED(params);
 }
 
-static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
-    size_t input_size, const uint8_t* data) {
-  HashRolling* self = FN(Self)(handle);
+static void FN(Prepare)(HashRolling* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
+    size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
   size_t i;
   /* Too small size, cannot use this hasher. */
   if (input_size < CHUNKLEN) return;
@@ -96,36 +91,36 @@
 static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
     const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
     size_t input_size) {
-  return sizeof(HashRolling) + NUMBUCKETS * sizeof(uint32_t);
+  return NUMBUCKETS * sizeof(uint32_t);
   BROTLI_UNUSED(params);
   BROTLI_UNUSED(one_shot);
   BROTLI_UNUSED(input_size);
 }
 
-static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle,
+static BROTLI_INLINE void FN(Store)(HashRolling* BROTLI_RESTRICT self,
     const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
-  BROTLI_UNUSED(handle);
+  BROTLI_UNUSED(self);
   BROTLI_UNUSED(data);
   BROTLI_UNUSED(mask);
   BROTLI_UNUSED(ix);
 }
 
-static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
-    const uint8_t* data, const size_t mask, const size_t ix_start,
-    const size_t ix_end) {
-  BROTLI_UNUSED(handle);
+static BROTLI_INLINE void FN(StoreRange)(HashRolling* BROTLI_RESTRICT self,
+    const uint8_t* BROTLI_RESTRICT data, const size_t mask,
+    const size_t ix_start, const size_t ix_end) {
+  BROTLI_UNUSED(self);
   BROTLI_UNUSED(data);
   BROTLI_UNUSED(mask);
   BROTLI_UNUSED(ix_start);
   BROTLI_UNUSED(ix_end);
 }
 
-static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
+static BROTLI_INLINE void FN(StitchToPreviousBlock)(
+    HashRolling* BROTLI_RESTRICT self,
     size_t num_bytes, size_t position, const uint8_t* ringbuffer,
     size_t ring_buffer_mask) {
   /* In this case we must re-initialize the hasher from scratch from the
      current position. */
-  HashRolling* self = FN(Self)(handle);
   size_t position_masked;
   size_t available = num_bytes;
   if ((position & (JUMP - 1)) != 0) {
@@ -139,28 +134,29 @@
     available = ring_buffer_mask - position_masked;
   }
 
-  FN(Prepare)(handle, BROTLI_FALSE, available,
+  FN(Prepare)(self, BROTLI_FALSE, available,
       ringbuffer + (position & ring_buffer_mask));
   self->next_ix = position;
   BROTLI_UNUSED(num_bytes);
 }
 
 static BROTLI_INLINE void FN(PrepareDistanceCache)(
-    HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
-  BROTLI_UNUSED(handle);
+    HashRolling* BROTLI_RESTRICT self,
+    int* BROTLI_RESTRICT distance_cache) {
+  BROTLI_UNUSED(self);
   BROTLI_UNUSED(distance_cache);
 }
 
-static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
+static BROTLI_INLINE void FN(FindLongestMatch)(
+    HashRolling* BROTLI_RESTRICT self,
     const BrotliEncoderDictionary* dictionary,
     const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
     const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
     const size_t max_length, const size_t max_backward,
-    const size_t gap, const size_t max_distance,
+    const size_t dictionary_distance, const size_t max_distance,
     HasherSearchResult* BROTLI_RESTRICT out) {
-  HashRolling* self = FN(Self)(handle);
   const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
-  size_t pos = self->next_ix;
+  size_t pos;
 
   if ((cur_ix & (JUMP - 1)) != 0) return;
 
@@ -209,7 +205,7 @@
      backup-hasher, the main hasher already searches in it. */
   BROTLI_UNUSED(dictionary);
   BROTLI_UNUSED(distance_cache);
-  BROTLI_UNUSED(gap);
+  BROTLI_UNUSED(dictionary_distance);
   BROTLI_UNUSED(max_distance);
 }
 
diff --git a/third_party/brotli/enc/hash_to_binary_tree_inc.h b/third_party/brotli/enc/hash_to_binary_tree_inc.h
index 7fb0356f..9880e0ae 100644
--- a/third_party/brotli/enc/hash_to_binary_tree_inc.h
+++ b/third_party/brotli/enc/hash_to_binary_tree_inc.h
@@ -24,7 +24,7 @@
   return MAX_TREE_COMP_LENGTH;
 }
 
-static uint32_t FN(HashBytes)(const uint8_t* data) {
+static uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) {
   uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
   /* The higher bits contain more mixture from the multiplication,
      so we take our results from there. */
@@ -38,7 +38,7 @@
   /* Hash table that maps the 4-byte hashes of the sequence to the last
      position where this hash was found, which is the root of the binary
      tree of sequences that share this hash bucket. */
-  uint32_t buckets_[BUCKET_SIZE];
+  uint32_t* buckets_;  /* uint32_t[BUCKET_SIZE]; */
 
   /* A position used to mark a non-existent sequence, i.e. a tree is empty if
      its root is at invalid_pos_ and a node is a leaf if both its children
@@ -51,34 +51,30 @@
      corresponding to a hash is a sequence starting at buckets_[hash] and
      the left and right children of a sequence starting at pos are
      forest_[2 * pos] and forest_[2 * pos + 1]. */
-  /* uint32_t forest[2 * num_nodes] */
+  uint32_t* forest_;  /* uint32_t[2 * num_nodes] */
 } HashToBinaryTree;
 
-static BROTLI_INLINE HashToBinaryTree* FN(Self)(HasherHandle handle) {
-  return (HashToBinaryTree*)&(GetHasherCommon(handle)[1]);
-}
-
-static BROTLI_INLINE uint32_t* FN(Forest)(HashToBinaryTree* self) {
-  return (uint32_t*)(&self[1]);
-}
-
 static void FN(Initialize)(
-    HasherHandle handle, const BrotliEncoderParams* params) {
-  HashToBinaryTree* self = FN(Self)(handle);
+    HasherCommon* common, HashToBinaryTree* BROTLI_RESTRICT self,
+    const BrotliEncoderParams* params) {
+  self->buckets_ = (uint32_t*)common->extra;
+  self->forest_ = &self->buckets_[BUCKET_SIZE];
+
   self->window_mask_ = (1u << params->lgwin) - 1u;
   self->invalid_pos_ = (uint32_t)(0 - self->window_mask_);
 }
 
-static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
-    size_t input_size, const uint8_t* data) {
-  HashToBinaryTree* self = FN(Self)(handle);
+static void FN(Prepare)
+    (HashToBinaryTree* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
+    size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
   uint32_t invalid_pos = self->invalid_pos_;
   uint32_t i;
+  uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
   BROTLI_UNUSED(data);
   BROTLI_UNUSED(one_shot);
   BROTLI_UNUSED(input_size);
   for (i = 0; i < BUCKET_SIZE; i++) {
-    self->buckets_[i] = invalid_pos;
+    buckets[i] = invalid_pos;
   }
 }
 
@@ -89,15 +85,17 @@
   if (one_shot && input_size < num_nodes) {
     num_nodes = input_size;
   }
-  return sizeof(HashToBinaryTree) + 2 * sizeof(uint32_t) * num_nodes;
+  return sizeof(uint32_t) * BUCKET_SIZE + 2 * sizeof(uint32_t) * num_nodes;
 }
 
-static BROTLI_INLINE size_t FN(LeftChildIndex)(HashToBinaryTree* self,
+static BROTLI_INLINE size_t FN(LeftChildIndex)(
+    HashToBinaryTree* BROTLI_RESTRICT self,
     const size_t pos) {
   return 2 * (pos & self->window_mask_);
 }
 
-static BROTLI_INLINE size_t FN(RightChildIndex)(HashToBinaryTree* self,
+static BROTLI_INLINE size_t FN(RightChildIndex)(
+    HashToBinaryTree* BROTLI_RESTRICT self,
     const size_t pos) {
   return 2 * (pos & self->window_mask_) + 1;
 }
@@ -113,7 +111,7 @@
 
    This function must be called with increasing cur_ix positions. */
 static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
-    HashToBinaryTree* self, const uint8_t* const BROTLI_RESTRICT data,
+    HashToBinaryTree* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
     const size_t cur_ix, const size_t ring_buffer_mask, const size_t max_length,
     const size_t max_backward, size_t* const BROTLI_RESTRICT best_len,
     BackwardMatch* BROTLI_RESTRICT matches) {
@@ -123,8 +121,9 @@
   const BROTLI_BOOL should_reroot_tree =
       TO_BROTLI_BOOL(max_length >= MAX_TREE_COMP_LENGTH);
   const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]);
-  uint32_t* forest = FN(Forest)(self);
-  size_t prev_ix = self->buckets_[key];
+  uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
+  uint32_t* BROTLI_RESTRICT forest = self->forest_;
+  size_t prev_ix = buckets[key];
   /* The forest index of the rightmost node of the left subtree of the new
      root, updated as we traverse and re-root the tree of the hash bucket. */
   size_t node_left = FN(LeftChildIndex)(self, cur_ix);
@@ -139,7 +138,7 @@
   size_t best_len_right = 0;
   size_t depth_remaining;
   if (should_reroot_tree) {
-    self->buckets_[key] = (uint32_t)cur_ix;
+    buckets[key] = (uint32_t)cur_ix;
   }
   for (depth_remaining = MAX_TREE_SEARCH_DEPTH; ; --depth_remaining) {
     const size_t backward = cur_ix - prev_ix;
@@ -199,11 +198,13 @@
    matches in matches[0] to matches[*num_matches - 1]. The matches will be
    sorted by strictly increasing length and (non-strictly) increasing
    distance. */
-static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle,
-    const BrotliEncoderDictionary* dictionary, const uint8_t* data,
+static BROTLI_INLINE size_t FN(FindAllMatches)(
+    HashToBinaryTree* BROTLI_RESTRICT self,
+    const BrotliEncoderDictionary* dictionary,
+    const uint8_t* BROTLI_RESTRICT data,
     const size_t ring_buffer_mask, const size_t cur_ix,
     const size_t max_length, const size_t max_backward,
-    const size_t gap, const BrotliEncoderParams* params,
+    const size_t dictionary_distance, const BrotliEncoderParams* params,
     BackwardMatch* matches) {
   BackwardMatch* const orig_matches = matches;
   const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
@@ -236,7 +237,7 @@
     }
   }
   if (best_len < max_length) {
-    matches = FN(StoreAndFindMatches)(FN(Self)(handle), data, cur_ix,
+    matches = FN(StoreAndFindMatches)(self, data, cur_ix,
         ring_buffer_mask, max_length, max_backward, &best_len, matches);
   }
   for (i = 0; i <= BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN; ++i) {
@@ -252,7 +253,7 @@
       for (l = minlen; l <= maxlen; ++l) {
         uint32_t dict_id = dict_matches[l];
         if (dict_id < kInvalidMatch) {
-          size_t distance = max_backward + gap + (dict_id >> 5) + 1;
+          size_t distance = dictionary_distance + (dict_id >> 5) + 1;
           if (distance <= params->dist.max_distance) {
             InitDictionaryBackwardMatch(matches++, distance, l, dict_id & 31);
           }
@@ -266,18 +267,18 @@
 /* Stores the hash of the next 4 bytes and re-roots the binary tree at the
    current sequence, without returning any matches.
    REQUIRES: ix + MAX_TREE_COMP_LENGTH <= end-of-current-block */
-static BROTLI_INLINE void FN(Store)(HasherHandle handle, const uint8_t* data,
+static BROTLI_INLINE void FN(Store)(HashToBinaryTree* BROTLI_RESTRICT self,
+    const uint8_t* BROTLI_RESTRICT data,
     const size_t mask, const size_t ix) {
-  HashToBinaryTree* self = FN(Self)(handle);
   /* Maximum distance is window size - 16, see section 9.1. of the spec. */
   const size_t max_backward = self->window_mask_ - BROTLI_WINDOW_GAP + 1;
   FN(StoreAndFindMatches)(self, data, ix, mask, MAX_TREE_COMP_LENGTH,
       max_backward, NULL, NULL);
 }
 
-static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
-    const uint8_t* data, const size_t mask, const size_t ix_start,
-    const size_t ix_end) {
+static BROTLI_INLINE void FN(StoreRange)(HashToBinaryTree* BROTLI_RESTRICT self,
+    const uint8_t* BROTLI_RESTRICT data, const size_t mask,
+    const size_t ix_start, const size_t ix_end) {
   size_t i = ix_start;
   size_t j = ix_start;
   if (ix_start + 63 <= ix_end) {
@@ -285,18 +286,18 @@
   }
   if (ix_start + 512 <= i) {
     for (; j < i; j += 8) {
-      FN(Store)(handle, data, mask, j);
+      FN(Store)(self, data, mask, j);
     }
   }
   for (; i < ix_end; ++i) {
-    FN(Store)(handle, data, mask, i);
+    FN(Store)(self, data, mask, i);
   }
 }
 
-static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
+static BROTLI_INLINE void FN(StitchToPreviousBlock)(
+    HashToBinaryTree* BROTLI_RESTRICT self,
     size_t num_bytes, size_t position, const uint8_t* ringbuffer,
     size_t ringbuffer_mask) {
-  HashToBinaryTree* self = FN(Self)(handle);
   if (num_bytes >= FN(HashTypeLength)() - 1 &&
       position >= MAX_TREE_COMP_LENGTH) {
     /* Store the last `MAX_TREE_COMP_LENGTH - 1` positions in the hasher.
diff --git a/third_party/brotli/enc/memory.h b/third_party/brotli/enc/memory.h
index ab928d0..832e7b2 100644
--- a/third_party/brotli/enc/memory.h
+++ b/third_party/brotli/enc/memory.h
@@ -56,6 +56,18 @@
 #define BROTLI_IS_OOM(M) (!!(M)->is_oom)
 #endif  /* BROTLI_ENCODER_EXIT_ON_OOM */
 
+/*
+BROTLI_IS_NULL is a fake check, BROTLI_IS_OOM does the heavy lifting.
+The only purpose of it is to explain static analyzers the state of things.
+NB: use ONLY together with BROTLI_IS_OOM
+    AND ONLY for allocations in the current scope.
+ */
+#if defined(__clang_analyzer__) && !defined(BROTLI_ENCODER_EXIT_ON_OOM)
+#define BROTLI_IS_NULL(A) ((A) == nullptr)
+#else  /* defined(__clang_analyzer__) */
+#define BROTLI_IS_NULL(A) (!!0)
+#endif  /* defined(__clang_analyzer__) */
+
 BROTLI_INTERNAL void BrotliWipeOutMemoryManager(MemoryManager* m);
 
 /*
@@ -66,18 +78,18 @@
 C: capacity
 R: requested size
 */
-#define BROTLI_ENSURE_CAPACITY(M, T, A, C, R) {  \
-  if (C < (R)) {                                 \
-    size_t _new_size = (C == 0) ? (R) : C;       \
-    T* new_array;                                \
-    while (_new_size < (R)) _new_size *= 2;      \
-    new_array = BROTLI_ALLOC((M), T, _new_size); \
-    if (!BROTLI_IS_OOM(M) && C != 0)             \
-      memcpy(new_array, A, C * sizeof(T));       \
-    BROTLI_FREE((M), A);                         \
-    A = new_array;                               \
-    C = _new_size;                               \
-  }                                              \
+#define BROTLI_ENSURE_CAPACITY(M, T, A, C, R) {                    \
+  if (C < (R)) {                                                   \
+    size_t _new_size = (C == 0) ? (R) : C;                         \
+    T* new_array;                                                  \
+    while (_new_size < (R)) _new_size *= 2;                        \
+    new_array = BROTLI_ALLOC((M), T, _new_size);                   \
+    if (!BROTLI_IS_OOM(M) && !BROTLI_IS_NULL(new_array) && C != 0) \
+      memcpy(new_array, A, C * sizeof(T));                         \
+    BROTLI_FREE((M), A);                                           \
+    A = new_array;                                                 \
+    C = _new_size;                                                 \
+  }                                                                \
 }
 
 /*
diff --git a/third_party/brotli/enc/metablock.c b/third_party/brotli/enc/metablock.c
index 4e80044..5aa4d4f 100644
--- a/third_party/brotli/enc/metablock.c
+++ b/third_party/brotli/enc/metablock.c
@@ -28,34 +28,30 @@
 void BrotliInitDistanceParams(BrotliEncoderParams* params,
     uint32_t npostfix, uint32_t ndirect) {
   BrotliDistanceParams* dist_params = &params->dist;
-  uint32_t alphabet_size, max_distance;
+  uint32_t alphabet_size_max;
+  uint32_t alphabet_size_limit;
+  uint32_t max_distance;
 
   dist_params->distance_postfix_bits = npostfix;
   dist_params->num_direct_distance_codes = ndirect;
 
-  alphabet_size = BROTLI_DISTANCE_ALPHABET_SIZE(
+  alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
       npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
+  alphabet_size_limit = alphabet_size_max;
   max_distance = ndirect + (1U << (BROTLI_MAX_DISTANCE_BITS + npostfix + 2)) -
       (1U << (npostfix + 2));
 
   if (params->large_window) {
-    static const uint32_t bound[BROTLI_MAX_NPOSTFIX + 1] = {0, 4, 12, 28};
-    uint32_t postfix = 1U << npostfix;
-    alphabet_size = BROTLI_DISTANCE_ALPHABET_SIZE(
+    BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit(
+        BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect);
+    alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
         npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
-    /* The maximum distance is set so that no distance symbol used can encode
-       a distance larger than BROTLI_MAX_ALLOWED_DISTANCE with all
-       its extra bits set. */
-    if (ndirect < bound[npostfix]) {
-      max_distance = BROTLI_MAX_ALLOWED_DISTANCE - (bound[npostfix] - ndirect);
-    } else if (ndirect >= bound[npostfix] + postfix) {
-      max_distance = (3U << 29) - 4 + (ndirect - bound[npostfix]);
-    } else {
-      max_distance = BROTLI_MAX_ALLOWED_DISTANCE;
-    }
+    alphabet_size_limit = limit.max_alphabet_size;
+    max_distance = limit.max_distance;
   }
 
-  dist_params->alphabet_size = alphabet_size;
+  dist_params->alphabet_size_max = alphabet_size_max;
+  dist_params->alphabet_size_limit = alphabet_size_limit;
   dist_params->max_distance = max_distance;
 }
 
@@ -200,7 +196,7 @@
     literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS;
     literal_context_modes =
         BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types);
-    if (BROTLI_IS_OOM(m)) return;
+    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_context_modes)) return;
     for (i = 0; i < mb->literal_split.num_types; ++i) {
       literal_context_modes[i] = literal_context_mode;
     }
@@ -210,21 +206,21 @@
       mb->literal_split.num_types * literal_context_multiplier;
   literal_histograms =
       BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size);
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_histograms)) return;
   ClearHistogramsLiteral(literal_histograms, literal_histograms_size);
 
   distance_histograms_size =
       mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
   distance_histograms =
       BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size);
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_histograms)) return;
   ClearHistogramsDistance(distance_histograms, distance_histograms_size);
 
   BROTLI_DCHECK(mb->command_histograms == 0);
   mb->command_histograms_size = mb->command_split.num_types;
   mb->command_histograms =
       BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size);
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->command_histograms)) return;
   ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size);
 
   BrotliBuildHistogramsWithContext(cmds, num_commands,
@@ -238,13 +234,13 @@
       mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
   mb->literal_context_map =
       BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
 
   BROTLI_DCHECK(mb->literal_histograms == 0);
   mb->literal_histograms_size = mb->literal_context_map_size;
   mb->literal_histograms =
       BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size);
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_histograms)) return;
 
   BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size,
       kMaxNumberOfHistograms, mb->literal_histograms,
@@ -269,13 +265,13 @@
       mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
   mb->distance_context_map =
       BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size);
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_context_map)) return;
 
   BROTLI_DCHECK(mb->distance_histograms == 0);
   mb->distance_histograms_size = mb->distance_context_map_size;
   mb->distance_histograms =
       BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size);
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_histograms)) return;
 
   BrotliClusterHistogramsDistance(m, distance_histograms,
                                   mb->distance_context_map_size,
@@ -373,7 +369,7 @@
   *histograms_size = max_num_types * num_contexts;
   *histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size);
   self->histograms_ = *histograms;
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
   /* Clear only current histogram. */
   ClearHistogramsLiteral(&self->histograms_[0], num_contexts);
   self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
@@ -423,7 +419,7 @@
     double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS];
     double diff[2] = { 0.0 };
     size_t i;
-    if (BROTLI_IS_OOM(m)) return;
+    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(combined_histo)) return;
     for (i = 0; i < num_contexts; ++i) {
       size_t curr_histo_ix = self->curr_histogram_ix_ + i;
       size_t j;
@@ -527,7 +523,7 @@
       mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
   mb->literal_context_map =
       BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
 
   for (i = 0; i < mb->literal_split.num_types; ++i) {
     uint32_t offset = (uint32_t)(i * num_contexts);
diff --git a/third_party/brotli/enc/metablock_inc.h b/third_party/brotli/enc/metablock_inc.h
index dcc9d3c4..ed507ef5 100644
--- a/third_party/brotli/enc/metablock_inc.h
+++ b/third_party/brotli/enc/metablock_inc.h
@@ -71,7 +71,7 @@
   *histograms_size = max_num_types;
   *histograms = BROTLI_ALLOC(m, HistogramType, *histograms_size);
   self->histograms_ = *histograms;
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
   /* Clear only current histogram. */
   FN(HistogramClear)(&self->histograms_[0]);
   self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
diff --git a/third_party/brotli/enc/params.h b/third_party/brotli/enc/params.h
index 6ecf1d3..54a7f00 100644
--- a/third_party/brotli/enc/params.h
+++ b/third_party/brotli/enc/params.h
@@ -23,7 +23,8 @@
 typedef struct BrotliDistanceParams {
   uint32_t distance_postfix_bits;
   uint32_t num_direct_distance_codes;
-  uint32_t alphabet_size;
+  uint32_t alphabet_size_max;
+  uint32_t alphabet_size_limit;
   size_t max_distance;
 } BrotliDistanceParams;
 
@@ -33,6 +34,7 @@
   int quality;
   int lgwin;
   int lgblock;
+  size_t stream_offset;
   size_t size_hint;
   BROTLI_BOOL disable_literal_context_modeling;
   BROTLI_BOOL large_window;
diff --git a/third_party/brotli/enc/ringbuffer.h b/third_party/brotli/enc/ringbuffer.h
index 86079a8..8dce148 100644
--- a/third_party/brotli/enc/ringbuffer.h
+++ b/third_party/brotli/enc/ringbuffer.h
@@ -75,7 +75,7 @@
   uint8_t* new_data = BROTLI_ALLOC(
       m, uint8_t, 2 + buflen + kSlackForEightByteHashingEverywhere);
   size_t i;
-  if (BROTLI_IS_OOM(m)) return;
+  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_data)) return;
   if (rb->data_) {
     memcpy(new_data, rb->data_,
         2 + rb->cur_size_ + kSlackForEightByteHashingEverywhere);
@@ -125,6 +125,9 @@
        later when we copy the last two bytes to the first two positions. */
     rb->buffer_[rb->size_ - 2] = 0;
     rb->buffer_[rb->size_ - 1] = 0;
+    /* Initialize tail; might be touched by "best_len++" optimization when
+       ring buffer is "full". */
+    rb->buffer_[rb->size_] = 241;
   }
   {
     const size_t masked_pos = rb->pos_ & rb->mask_;
diff --git a/third_party/brotli/enc/utf8_util.c b/third_party/brotli/enc/utf8_util.c
index 04a7805..e802b6a 100644
--- a/third_party/brotli/enc/utf8_util.c
+++ b/third_party/brotli/enc/utf8_util.c
@@ -77,7 +77,7 @@
     i += bytes_read;
     if (symbol < 0x110000) size_utf8 += bytes_read;
   }
-  return TO_BROTLI_BOOL(size_utf8 > min_fraction * (double)length);
+  return TO_BROTLI_BOOL((double)size_utf8 > min_fraction * (double)length);
 }
 
 #if defined(__cplusplus) || defined(c_plusplus)
diff --git a/third_party/brotli/enc/write_bits.h b/third_party/brotli/enc/write_bits.h
index 36515a68..f6f88b4 100644
--- a/third_party/brotli/enc/write_bits.h
+++ b/third_party/brotli/enc/write_bits.h
@@ -16,8 +16,6 @@
 extern "C" {
 #endif
 
-/*#define BIT_WRITER_DEBUG */
-
 /* This function writes bits into bytes in increasing addresses, and within
    a byte least-significant-bit first.
 
@@ -28,7 +26,7 @@
 
    0000 0RRR    0000 0000    0000 0000
 
-   Now, we could write 5 or less bits in MSB by just sifting by 3
+   Now, we could write 5 or less bits in MSB by just shifting by 3
    and OR'ing to BYTE-0.
 
    For n bits, we take the last 5 bits, OR that with high bits in BYTE-0,
@@ -37,37 +35,41 @@
                                           uint64_t bits,
                                           size_t* BROTLI_RESTRICT pos,
                                           uint8_t* BROTLI_RESTRICT array) {
+  BROTLI_LOG(("WriteBits  %2d  0x%08x%08x  %10d\n", (int)n_bits,
+      (uint32_t)(bits >> 32), (uint32_t)(bits & 0xFFFFFFFF),
+      (int)*pos));
+  BROTLI_DCHECK((bits >> n_bits) == 0);
+  BROTLI_DCHECK(n_bits <= 56);
 #if defined(BROTLI_LITTLE_ENDIAN)
   /* This branch of the code can write up to 56 bits at a time,
      7 bits are lost by being perhaps already in *p and at least
      1 bit is needed to initialize the bit-stream ahead (i.e. if 7
      bits are in *p and we write 57 bits, then the next write will
      access a byte that was never initialized). */
-  uint8_t* p = &array[*pos >> 3];
-  uint64_t v = (uint64_t)(*p);  /* Zero-extend 8 to 64 bits. */
-  BROTLI_LOG(("WriteBits  %2d  0x%08x%08x  %10d\n", (int)n_bits,
-      (uint32_t)(bits >> 32), (uint32_t)(bits & 0xFFFFFFFF),
-      (int)*pos));
-  BROTLI_DCHECK((bits >> n_bits) == 0);
-  BROTLI_DCHECK(n_bits <= 56);
-  v |= bits << (*pos & 7);
-  BROTLI_UNALIGNED_STORE64LE(p, v);  /* Set some bits. */
-  *pos += n_bits;
+  {
+    uint8_t* p = &array[*pos >> 3];
+    uint64_t v = (uint64_t)(*p);  /* Zero-extend 8 to 64 bits. */
+    v |= bits << (*pos & 7);
+    BROTLI_UNALIGNED_STORE64LE(p, v);  /* Set some bits. */
+    *pos += n_bits;
+  }
 #else
   /* implicit & 0xFF is assumed for uint8_t arithmetics */
-  uint8_t* array_pos = &array[*pos >> 3];
-  const size_t bits_reserved_in_first_byte = (*pos & 7);
-  size_t bits_left_to_write;
-  bits <<= bits_reserved_in_first_byte;
-  *array_pos++ |= (uint8_t)bits;
-  for (bits_left_to_write = n_bits + bits_reserved_in_first_byte;
-       bits_left_to_write >= 9;
-       bits_left_to_write -= 8) {
-    bits >>= 8;
-    *array_pos++ = (uint8_t)bits;
+  {
+    uint8_t* array_pos = &array[*pos >> 3];
+    const size_t bits_reserved_in_first_byte = (*pos & 7);
+    size_t bits_left_to_write;
+    bits <<= bits_reserved_in_first_byte;
+    *array_pos++ |= (uint8_t)bits;
+    for (bits_left_to_write = n_bits + bits_reserved_in_first_byte;
+         bits_left_to_write >= 9;
+         bits_left_to_write -= 8) {
+      bits >>= 8;
+      *array_pos++ = (uint8_t)bits;
+    }
+    *array_pos = 0;
+    *pos += n_bits;
   }
-  *array_pos = 0;
-  *pos += n_bits;
 #endif
 }
 
diff --git a/third_party/brotli/fuzz/decode_fuzzer.c b/third_party/brotli/fuzz/decode_fuzzer.c
new file mode 100644
index 0000000..46144e0
--- /dev/null
+++ b/third_party/brotli/fuzz/decode_fuzzer.c
@@ -0,0 +1,58 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <brotli/decode.h>
+
+// Entry point for LibFuzzer.
+int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  size_t addend = 0;
+  if (size > 0)
+    addend = data[size - 1] & 7;
+  const uint8_t* next_in = data;
+
+  const int kBufferSize = 1024;
+  uint8_t* buffer = (uint8_t*) malloc(kBufferSize);
+  if (!buffer) {
+    // OOM is out-of-scope here.
+    return 0;
+  }
+  /* The biggest "magic number" in brotli is 16MiB - 16, so no need to check
+     the cases with much longer output. */
+  const size_t total_out_limit = (addend == 0) ? (1 << 26) : (1 << 24);
+  size_t total_out = 0;
+
+  BrotliDecoderState* state = BrotliDecoderCreateInstance(0, 0, 0);
+
+  if (addend == 0)
+    addend = size;
+  /* Test both fast (addend == size) and slow (addend <= 7) decoding paths. */
+  for (size_t i = 0; i < size;) {
+    size_t next_i = i + addend;
+    if (next_i > size)
+      next_i = size;
+    size_t avail_in = next_i - i;
+    i = next_i;
+    BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
+    while (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
+      size_t avail_out = kBufferSize;
+      uint8_t* next_out = buffer;
+      result = BrotliDecoderDecompressStream(
+          state, &avail_in, &next_in, &avail_out, &next_out, &total_out);
+      if (total_out > total_out_limit)
+        break;
+    }
+    if (total_out > total_out_limit)
+      break;
+    if (result != BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT)
+      break;
+  }
+
+  BrotliDecoderDestroyInstance(state);
+  free(buffer);
+  return 0;
+}
diff --git a/third_party/brotli/include/brotli/encode.h b/third_party/brotli/include/brotli/encode.h
index 0ced7e5..b2774cb 100644
--- a/third_party/brotli/include/brotli/encode.h
+++ b/third_party/brotli/include/brotli/encode.h
@@ -201,7 +201,23 @@
    *
    * Range is from 0 to (15 << NPOSTFIX) in steps of (1 << NPOSTFIX).
    */
-  BROTLI_PARAM_NDIRECT = 8
+  BROTLI_PARAM_NDIRECT = 8,
+  /**
+   * Number of bytes of input stream already processed by a different instance.
+   *
+   * @note It is important to configure all the encoder instances with same
+   *       parameters (except this one) in order to allow all the encoded parts
+   *       obey the same restrictions implied by header.
+   *
+   * If offset is not 0, then stream header is omitted.
+   * In any case output start is byte aligned, so for proper streams stitching
+   * "predecessor" stream must be flushed.
+   *
+   * Range is not artificially limited, but all the values greater or equal to
+   * maximal window size have the same effect. Values greater than 2**30 are not
+   * allowed.
+   */
+  BROTLI_PARAM_STREAM_OFFSET = 9
 } BrotliEncoderParameter;
 
 /**
@@ -274,6 +290,11 @@
  * @note If ::BrotliEncoderMaxCompressedSize(@p input_size) returns non-zero
  *       value, then output is guaranteed to be no longer than that.
  *
+ * @note If @p lgwin is greater than ::BROTLI_MAX_WINDOW_BITS then resulting
+ *       stream might be incompatible with RFC 7932; to decode such streams,
+ *       decoder should be configured with
+ *       ::BROTLI_DECODER_PARAM_LARGE_WINDOW = @c 1
+ *
  * @param quality quality parameter value, e.g. ::BROTLI_DEFAULT_QUALITY
  * @param lgwin lgwin parameter value, e.g. ::BROTLI_DEFAULT_WINDOW
  * @param mode mode parameter value, e.g. ::BROTLI_DEFAULT_MODE
diff --git a/third_party/brotli/include/brotli/port.h b/third_party/brotli/include/brotli/port.h
index 20dc2314..825237a 100644
--- a/third_party/brotli/include/brotli/port.h
+++ b/third_party/brotli/include/brotli/port.h
@@ -218,6 +218,20 @@
   BROTLI_GNUC_VERSION_CHECK(major, minor, patch)
 #endif
 
+#if defined(__has_feature)
+#define BROTLI_HAS_FEATURE(feature) __has_feature(feature)
+#else
+#define BROTLI_HAS_FEATURE(feature) (0)
+#endif
+
+#if defined(ADDRESS_SANITIZER) || BROTLI_HAS_FEATURE(address_sanitizer) || \
+    defined(THREAD_SANITIZER) || BROTLI_HAS_FEATURE(thread_sanitizer) ||   \
+    defined(MEMORY_SANITIZER) || BROTLI_HAS_FEATURE(memory_sanitizer)
+#define BROTLI_SANITIZED 1
+#else
+#define BROTLI_SANITIZED 0
+#endif
+
 #if defined(_WIN32) || defined(__CYGWIN__)
 #define BROTLI_PUBLIC
 #elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) ||                         \
diff --git a/third_party/brotli/tools/brotli.c b/third_party/brotli/tools/brotli.c
index ce05b64..7c678d3 100644
--- a/third_party/brotli/tools/brotli.c
+++ b/third_party/brotli/tools/brotli.c
@@ -6,6 +6,11 @@
 
 /* Command line interface for Brotli library. */
 
+/* Mute strerror/strcpy warnings. */
+#if !defined(_CRT_SECURE_NO_WARNINGS)
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
@@ -86,10 +91,10 @@
   /* Parameters */
   int quality;
   int lgwin;
+  int verbosity;
   BROTLI_BOOL force_overwrite;
   BROTLI_BOOL junk_source;
   BROTLI_BOOL copy_stat;
-  BROTLI_BOOL verbose;
   BROTLI_BOOL write_to_stdout;
   BROTLI_BOOL test_integrity;
   BROTLI_BOOL decompress;
@@ -121,6 +126,12 @@
   const uint8_t* next_in;
   size_t available_out;
   uint8_t* next_out;
+
+  /* Reporting */
+  /* size_t would be large enough,
+     until 4GiB+ files are compressed / decompressed on 32-bit CPUs. */
+  size_t total_in;
+  size_t total_out;
 } Context;
 
 /* Parse up to 5 decimal digits. */
@@ -257,7 +268,7 @@
           return COMMAND_HELP;
         } else if (c == 'j' || c == 'k') {
           if (keep_set) {
-            fprintf(stderr, "argument --rm / -j or --keep / -n already set\n");
+            fprintf(stderr, "argument --rm / -j or --keep / -k already set\n");
             return COMMAND_INVALID;
           }
           keep_set = BROTLI_TRUE;
@@ -279,11 +290,11 @@
           command = COMMAND_TEST_INTEGRITY;
           continue;
         } else if (c == 'v') {
-          if (params->verbose) {
+          if (params->verbosity > 0) {
             fprintf(stderr, "argument --verbose / -v already set\n");
             return COMMAND_INVALID;
           }
-          params->verbose = BROTLI_TRUE;
+          params->verbosity = 1;
           continue;
         } else if (c == 'V') {
           /* Don't parse further. */
@@ -382,7 +393,7 @@
         return COMMAND_HELP;
       } else if (strcmp("keep", arg) == 0) {
         if (keep_set) {
-          fprintf(stderr, "argument --rm / -j or --keep / -n already set\n");
+          fprintf(stderr, "argument --rm / -j or --keep / -k already set\n");
           return COMMAND_INVALID;
         }
         keep_set = BROTLI_TRUE;
@@ -395,7 +406,7 @@
         params->copy_stat = BROTLI_FALSE;
       } else if (strcmp("rm", arg) == 0) {
         if (keep_set) {
-          fprintf(stderr, "argument --rm / -j or --keep / -n already set\n");
+          fprintf(stderr, "argument --rm / -j or --keep / -k already set\n");
           return COMMAND_INVALID;
         }
         keep_set = BROTLI_TRUE;
@@ -415,11 +426,11 @@
         command_set = BROTLI_TRUE;
         command = COMMAND_TEST_INTEGRITY;
       } else if (strcmp("verbose", arg) == 0) {
-        if (params->verbose) {
+        if (params->verbosity > 0) {
           fprintf(stderr, "argument --verbose / -v already set\n");
           return COMMAND_INVALID;
         }
-        params->verbose = BROTLI_TRUE;
+        params->verbosity = 1;
       } else if (strcmp("version", arg) == 0) {
         /* Don't parse further. */
         return COMMAND_VERSION;
@@ -550,11 +561,17 @@
 "  -t, --test                  test compressed file integrity\n"
 "  -v, --verbose               verbose mode\n");
   fprintf(media,
-"  -w NUM, --lgwin=NUM         set LZ77 window size (0, %d-%d)\n",
+"  -w NUM, --lgwin=NUM         set LZ77 window size (0, %d-%d)\n"
+"                              window size = 2**NUM - 16\n"
+"                              0 lets compressor choose the optimal value\n",
           BROTLI_MIN_WINDOW_BITS, BROTLI_MAX_WINDOW_BITS);
   fprintf(media,
-"                              window size = 2**NUM - 16\n"
-"                              0 lets compressor choose the optimal value\n");
+"  --large_window=NUM          use incompatible large-window brotli\n"
+"                              bitstream with window size (0, %d-%d)\n"
+"                              WARNING: this format is not compatible\n"
+"                              with brotli RFC 7932 and may not be\n"
+"                              decodable with regular brotli decoders\n",
+          BROTLI_MIN_WINDOW_BITS, BROTLI_LARGE_MAX_WINDOW_BITS);
   fprintf(media,
 "  -S SUF, --suffix=SUF        output file suffix (default:'%s')\n",
           DEFAULT_SUFFIX);
@@ -787,8 +804,12 @@
   context->next_in = NULL;
   context->available_out = kFileBufferSize;
   context->next_out = context->output;
+  context->total_in = 0;
+  context->total_out = 0;
 }
 
+/* This method might give the false-negative result.
+   However, after an empty / incomplete read it should tell the truth. */
 static BROTLI_BOOL HasMoreInput(Context* context) {
   return feof(context->fin) ? BROTLI_FALSE : BROTLI_TRUE;
 }
@@ -796,6 +817,7 @@
 static BROTLI_BOOL ProvideInput(Context* context) {
   context->available_in =
       fread(context->input, 1, kFileBufferSize, context->fin);
+  context->total_in += context->available_in;
   context->next_in = context->input;
   if (ferror(context->fin)) {
     fprintf(stderr, "failed to read input [%s]: %s\n",
@@ -808,6 +830,7 @@
 /* Internal: should be used only in Provide-/Flush-Output. */
 static BROTLI_BOOL WriteOutput(Context* context) {
   size_t out_size = (size_t)(context->next_out - context->output);
+  context->total_out += out_size;
   if (out_size == 0) return BROTLI_TRUE;
   if (context->test_integrity) return BROTLI_TRUE;
 
@@ -833,6 +856,25 @@
   return BROTLI_TRUE;
 }
 
+static void PrintBytes(size_t value) {
+  if (value < 1024) {
+    fprintf(stderr, "%d B", (int)value);
+  } else if (value < 1048576) {
+    fprintf(stderr, "%0.3f KiB", (double)value / 1024.0);
+  } else if (value < 1073741824) {
+    fprintf(stderr, "%0.3f MiB", (double)value / 1048576.0);
+  } else {
+    fprintf(stderr, "%0.3f GiB", (double)value / 1073741824.0);
+  }
+}
+
+static void PrintFileProcessingProgress(Context* context) {
+  fprintf(stderr, "[%s]: ", PrintablePath(context->current_input_path));
+  PrintBytes(context->total_in);
+  fprintf(stderr, " -> ");
+  PrintBytes(context->total_out);
+}
+
 static BROTLI_BOOL DecompressFile(Context* context, BrotliDecoderState* s) {
   BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
   InitializeBuffers(context);
@@ -848,11 +890,18 @@
       if (!ProvideOutput(context)) return BROTLI_FALSE;
     } else if (result == BROTLI_DECODER_RESULT_SUCCESS) {
       if (!FlushOutput(context)) return BROTLI_FALSE;
-      if (context->available_in != 0 || HasMoreInput(context)) {
+      int has_more_input =
+          (context->available_in != 0) || (fgetc(context->fin) != EOF);
+      if (has_more_input) {
         fprintf(stderr, "corrupt input [%s]\n",
                 PrintablePath(context->current_input_path));
         return BROTLI_FALSE;
       }
+      if (context->verbosity > 0) {
+        fprintf(stderr, "Decompressed ");
+        PrintFileProcessingProgress(context);
+        fprintf(stderr, "\n");
+      }
       return BROTLI_TRUE;
     } else {
       fprintf(stderr, "corrupt input [%s]\n",
@@ -915,7 +964,13 @@
     }
 
     if (BrotliEncoderIsFinished(s)) {
-      return FlushOutput(context);
+      if (!FlushOutput(context)) return BROTLI_FALSE;
+      if (context->verbosity > 0) {
+        fprintf(stderr, "Compressed ");
+        PrintFileProcessingProgress(context);
+        fprintf(stderr, "\n");
+      }
+      return BROTLI_TRUE;
     }
   }
 }
@@ -979,11 +1034,11 @@
 
   context.quality = 11;
   context.lgwin = -1;
+  context.verbosity = 0;
   context.force_overwrite = BROTLI_FALSE;
   context.junk_source = BROTLI_FALSE;
   context.copy_stat = BROTLI_TRUE;
   context.test_integrity = BROTLI_FALSE;
-  context.verbose = BROTLI_FALSE;
   context.write_to_stdout = BROTLI_FALSE;
   context.decompress = BROTLI_FALSE;
   context.large_window = BROTLI_FALSE;
diff --git a/third_party/feed_library/DIR_METADATA b/third_party/feed_library/DIR_METADATA
new file mode 100644
index 0000000..caf2b284
--- /dev/null
+++ b/third_party/feed_library/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>ContentSuggestions>Feed"
+}
diff --git a/third_party/feed_library/OWNERS b/third_party/feed_library/OWNERS
index 7f83c34..3287a69 100644
--- a/third_party/feed_library/OWNERS
+++ b/third_party/feed_library/OWNERS
@@ -1,4 +1,3 @@
 file://components/feed/OWNERS
 
-# Team: feed@chromium.org
-# COMPONENT: UI>Browser>ContentSuggestions>Feed
+# Team: feed@chromium.org
\ No newline at end of file
diff --git a/third_party/fft2d/DIR_METADATA b/third_party/fft2d/DIR_METADATA
new file mode 100644
index 0000000..f21921424
--- /dev/null
+++ b/third_party/fft2d/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>OptimizationGuide"
+}
diff --git a/third_party/fft2d/OWNERS b/third_party/fft2d/OWNERS
index f14a8b97..d9918ce6 100644
--- a/third_party/fft2d/OWNERS
+++ b/third_party/fft2d/OWNERS
@@ -1,4 +1,3 @@
 mcrouse@chromium.org
 sophiechang@chromium.org
-tbansal@chromium.org
-# COMPONENT: Internals>OptimizationGuide
+tbansal@chromium.org
\ No newline at end of file
diff --git a/third_party/flatbuffers/DIR_METADATA b/third_party/flatbuffers/DIR_METADATA
new file mode 100644
index 0000000..637eb4dc
--- /dev/null
+++ b/third_party/flatbuffers/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Platform>Extensions>API"
+}
diff --git a/third_party/flatbuffers/OWNERS b/third_party/flatbuffers/OWNERS
index bca4bf3eb..08ce2ad 100644
--- a/third_party/flatbuffers/OWNERS
+++ b/third_party/flatbuffers/OWNERS
@@ -1,4 +1,3 @@
 battre@chromium.org
 csharrison@chromium.org
-engedy@chromium.org
-# COMPONENT: Platform>Extensions>API
+engedy@chromium.org
\ No newline at end of file
diff --git a/third_party/fontconfig/DIR_METADATA b/third_party/fontconfig/DIR_METADATA
new file mode 100644
index 0000000..594a7d65
--- /dev/null
+++ b/third_party/fontconfig/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Fonts"
+}
diff --git a/third_party/fontconfig/OWNERS b/third_party/fontconfig/OWNERS
index 280b07e..91e296f 100644
--- a/third_party/fontconfig/OWNERS
+++ b/third_party/fontconfig/OWNERS
@@ -1,4 +1,3 @@
 spang@chromium.org
 dnicoara@chromium.org
-thomasanderson@chromium.org
-# COMPONENT: Blink>Fonts
+thomasanderson@chromium.org
\ No newline at end of file
diff --git a/third_party/fp16/DIR_METADATA b/third_party/fp16/DIR_METADATA
new file mode 100644
index 0000000..f21921424
--- /dev/null
+++ b/third_party/fp16/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>OptimizationGuide"
+}
diff --git a/third_party/fp16/OWNERS b/third_party/fp16/OWNERS
index f14a8b97..d9918ce6 100644
--- a/third_party/fp16/OWNERS
+++ b/third_party/fp16/OWNERS
@@ -1,4 +1,3 @@
 mcrouse@chromium.org
 sophiechang@chromium.org
-tbansal@chromium.org
-# COMPONENT: Internals>OptimizationGuide
+tbansal@chromium.org
\ No newline at end of file
diff --git a/third_party/freetype-testing/DIR_METADATA b/third_party/freetype-testing/DIR_METADATA
new file mode 100644
index 0000000..594a7d65
--- /dev/null
+++ b/third_party/freetype-testing/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Fonts"
+}
diff --git a/third_party/freetype-testing/OWNERS b/third_party/freetype-testing/OWNERS
index 6046627..75d0b05 100644
--- a/third_party/freetype-testing/OWNERS
+++ b/third_party/freetype-testing/OWNERS
@@ -1,3 +1,2 @@
 bungeman@chromium.org
-drott@chromium.org
-# COMPONENT: Blink>Fonts
+drott@chromium.org
\ No newline at end of file
diff --git a/third_party/freetype/DIR_METADATA b/third_party/freetype/DIR_METADATA
new file mode 100644
index 0000000..594a7d65
--- /dev/null
+++ b/third_party/freetype/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Fonts"
+}
diff --git a/third_party/freetype/OWNERS b/third_party/freetype/OWNERS
index 6046627..75d0b05 100644
--- a/third_party/freetype/OWNERS
+++ b/third_party/freetype/OWNERS
@@ -1,3 +1,2 @@
 bungeman@chromium.org
-drott@chromium.org
-# COMPONENT: Blink>Fonts
+drott@chromium.org
\ No newline at end of file
diff --git a/third_party/fuchsia-sdk/DIR_METADATA b/third_party/fuchsia-sdk/DIR_METADATA
new file mode 100644
index 0000000..d537e1b
--- /dev/null
+++ b/third_party/fuchsia-sdk/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Fuchsia"
+}
+team_email: "cr-fuchsia@chromium.org"
+os: FUCHSIA
diff --git a/third_party/fuchsia-sdk/OWNERS b/third_party/fuchsia-sdk/OWNERS
index c1b5845..3ebcc42 100644
--- a/third_party/fuchsia-sdk/OWNERS
+++ b/third_party/fuchsia-sdk/OWNERS
@@ -1,4 +1 @@
-file://build/fuchsia/OWNERS
-# COMPONENT: Fuchsia
-# OS: Fuchsia
-# TEAM: cr-fuchsia@chromium.org
+file://build/fuchsia/OWNERS
\ No newline at end of file
diff --git a/third_party/gemmlowp/DIR_METADATA b/third_party/gemmlowp/DIR_METADATA
new file mode 100644
index 0000000..f21921424
--- /dev/null
+++ b/third_party/gemmlowp/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>OptimizationGuide"
+}
diff --git a/third_party/gemmlowp/OWNERS b/third_party/gemmlowp/OWNERS
index f14a8b97..d9918ce6 100644
--- a/third_party/gemmlowp/OWNERS
+++ b/third_party/gemmlowp/OWNERS
@@ -1,4 +1,3 @@
 mcrouse@chromium.org
 sophiechang@chromium.org
-tbansal@chromium.org
-# COMPONENT: Internals>OptimizationGuide
+tbansal@chromium.org
\ No newline at end of file
diff --git a/third_party/glfw/DIR_METADATA b/third_party/glfw/DIR_METADATA
new file mode 100644
index 0000000..348e542
--- /dev/null
+++ b/third_party/glfw/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>GPU>Internals"
+}
+team_email: "graphics-dev@chromium.org"
diff --git a/third_party/glfw/OWNERS b/third_party/glfw/OWNERS
index 424db9fd..77a75dd 100644
--- a/third_party/glfw/OWNERS
+++ b/third_party/glfw/OWNERS
@@ -1,5 +1,2 @@
 cwallez@chromium.org
 kainino@chromium.org
-
-# COMPONENT: Internals>GPU>Internals
-# TEAM: graphics-dev@chromium.org
diff --git a/third_party/glslang/DIR_METADATA b/third_party/glslang/DIR_METADATA
new file mode 100644
index 0000000..348e542
--- /dev/null
+++ b/third_party/glslang/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>GPU>Internals"
+}
+team_email: "graphics-dev@chromium.org"
diff --git a/third_party/glslang/OWNERS b/third_party/glslang/OWNERS
index fc1c398..ed07d05f 100644
--- a/third_party/glslang/OWNERS
+++ b/third_party/glslang/OWNERS
@@ -1,5 +1,2 @@
 dsinclair@chromium.org
 vmiura@chromium.org
-
-# COMPONENT: Internals>GPU>Internals
-# TEAM: graphics-dev@chromium.org
diff --git a/third_party/google-truth/DIR_METADATA b/third_party/google-truth/DIR_METADATA
new file mode 100644
index 0000000..5abea21
--- /dev/null
+++ b/third_party/google-truth/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Test>Android"
+}
diff --git a/third_party/google-truth/OWNERS b/third_party/google-truth/OWNERS
index 9a85d89..bf7cd4e 100644
--- a/third_party/google-truth/OWNERS
+++ b/third_party/google-truth/OWNERS
@@ -1,3 +1 @@
 fgorski@chromium.org
-
-# COMPONENT: Test>Android
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index c982b9ab..b26dbb6 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -879,6 +879,13 @@
       'win64-chrome-stable': 'official_goma_x64',
     },
 
+    'tryserver.chrome.pgo': {
+      'linux-pgo-trunk': 'official_goma_linux_pgo',
+      'mac-pgo-trunk': 'official_goma_mac_pgo',
+      'win32-pgo-trunk': 'official_goma_x86_pgo',
+      'win64-pgo-trunk': 'official_goma_x64_pgo',
+    },
+
     'tryserver.chromium.chromiumos': {
       # TODO(crbug.com/913750): Enable DCHECKS on the two amd64-generic bots
       # and two kevin bots when the PFQ has it enabled.
@@ -956,6 +963,7 @@
       'linux-clang-tidy-dbg': 'debug_bot',
       'linux-clang-tidy-rel': 'release_trybot',
       'linux-dcheck-off-rel': 'release_trybot_dcheck_off',
+      'linux-example-builder': 'release_trybot',
       'linux-inverse-fieldtrials-fyi-rel': 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange_invert_fieldtrials',
       'linux-gcc-rel': 'release_bot_x86_minimal_symbols_no_clang_cxx11',
       'linux-lacros-fyi-rel': 'lacros_on_linux_release_trybot',
diff --git a/tools/mb/mb_config_expectations/tryserver.chrome.pgo.json b/tools/mb/mb_config_expectations/tryserver.chrome.pgo.json
new file mode 100644
index 0000000..9b0c2c0
--- /dev/null
+++ b/tools/mb/mb_config_expectations/tryserver.chrome.pgo.json
@@ -0,0 +1,53 @@
+{
+  "linux-pgo-trunk": {
+    "gn_args": {
+      "chrome_pgo_phase": 1,
+      "is_chrome_branded": true,
+      "is_component_build": false,
+      "is_official_build": true,
+      "strip_absolute_paths_from_debug_symbols": true,
+      "symbol_level": 0,
+      "use_goma": true
+    }
+  },
+  "mac-pgo-trunk": {
+    "gn_args": {
+      "chrome_pgo_phase": 1,
+      "enable_keystone_registration_framework": false,
+      "enable_widevine_cdm_host_verification": false,
+      "ignore_missing_widevine_signing_cert": true,
+      "is_chrome_branded": true,
+      "is_component_build": false,
+      "is_official_build": true,
+      "strip_absolute_paths_from_debug_symbols": true,
+      "symbol_level": 0,
+      "use_goma": true
+    }
+  },
+  "win32-pgo-trunk": {
+    "gn_args": {
+      "chrome_pgo_phase": 1,
+      "enable_resource_allowlist_generation": false,
+      "is_chrome_branded": true,
+      "is_component_build": false,
+      "is_official_build": true,
+      "strip_absolute_paths_from_debug_symbols": true,
+      "symbol_level": 0,
+      "target_cpu": "x86",
+      "use_goma": true
+    }
+  },
+  "win64-pgo-trunk": {
+    "gn_args": {
+      "chrome_pgo_phase": 1,
+      "enable_resource_allowlist_generation": false,
+      "is_chrome_branded": true,
+      "is_component_build": false,
+      "is_official_build": true,
+      "strip_absolute_paths_from_debug_symbols": true,
+      "symbol_level": 0,
+      "target_cpu": "x64",
+      "use_goma": true
+    }
+  }
+}
\ No newline at end of file
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
index 7a728626..cd414fb 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
@@ -406,6 +406,15 @@
       "use_goma": true
     }
   },
+  "linux-example-builder": {
+    "gn_args": {
+      "dcheck_always_on": true,
+      "is_component_build": false,
+      "is_debug": false,
+      "symbol_level": 1,
+      "use_goma": true
+    }
+  },
   "linux-gcc-rel": {
     "gn_args": {
       "is_clang": false,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 7aa7361..d810b8e 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -23131,6 +23131,7 @@
   <int value="18" label="GestureTapUnconfirmed"/>
   <int value="19" label="GestureTwoFingerTap"/>
   <int value="20" label="FirstGestureScrollUpdate"/>
+  <int value="21" label="MouseDragged"/>
 </enum>
 
 <enum name="EventLatencyScrollInputType">
@@ -30150,10 +30151,10 @@
   <int value="3470" label="OBSOLETE_ElementAttachInternalsBeforeConstructor"/>
   <int value="3471" label="SMILElementHasRepeatNEventListener"/>
   <int value="3472" label="WebTransport"/>
-  <int value="3473" label="WebkitPrerenderStartEventFired"/>
-  <int value="3474" label="WebkitPrerenderStopEventFired"/>
-  <int value="3475" label="WebkitPrerenderLoadEventFired"/>
-  <int value="3476" label="WebkitPrerenderDOMContentLoadedEventFired"/>
+  <int value="3473" label="OBSOLETE_WebkitPrerenderStartEventFired"/>
+  <int value="3474" label="OBSOLETE_WebkitPrerenderStopEventFired"/>
+  <int value="3475" label="OBSOLETE_WebkitPrerenderLoadEventFired"/>
+  <int value="3476" label="OBSOLETE_WebkitPrerenderDOMContentLoadedEventFired"/>
   <int value="3477" label="IdleDetectionPermissionRequested"/>
   <int value="3478" label="IdentifiabilityStudyReserved3478"/>
   <int value="3479" label="SpeechSynthesis_GetVoices_Method"/>
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
index 2fdfa7d..ea1d9d9 100644
--- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -6038,6 +6038,7 @@
   <affected-histogram name="EventLatency.GestureTwoFingerTap"/>
   <affected-histogram name="EventLatency.KeyPressed"/>
   <affected-histogram name="EventLatency.KeyReleased"/>
+  <affected-histogram name="EventLatency.MouseDragged"/>
   <affected-histogram name="EventLatency.MousePressed"/>
   <affected-histogram name="EventLatency.MouseReleased"/>
   <affected-histogram name="EventLatency.MouseWheel"/>
@@ -6143,6 +6144,8 @@
       label="Event latency for key-pressed event."/>
   <suffix base="true" name="KeyReleased"
       label="Event latency for key-released event."/>
+  <suffix base="true" name="MouseDragged"
+      label="Event latency for mouse-dragged event."/>
   <suffix base="true" name="MousePressed"
       label="Event latency for mouse-pressed event."/>
   <suffix base="true" name="MouseReleased"
diff --git a/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml b/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml
index 04a8fd450..bf8bec7 100644
--- a/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml
@@ -248,6 +248,17 @@
   </summary>
 </histogram>
 
+<histogram name="MultiDevice.SecureChannel.Nearby.SendMessageResult"
+    enum="BooleanSuccess" expires_after="2021-11-30">
+  <owner>khorimoto@chromium.org</owner>
+  <owner>better-together-dev@google.com</owner>
+  <summary>
+    Measures the success rate of sending a SecureChannel message via the Nearby
+    Connections library. Emitted when the Nearby Connections library sends a
+    message.
+  </summary>
+</histogram>
+
 <histogram name="MultiDevice.Setup.HostStatus"
     enum="MultiDevice_Setup_HostStatus" expires_after="2021-04-04">
   <owner>vecore@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml
index 1b38e87..06b3dc03 100644
--- a/tools/metrics/histograms/histograms_xml/others/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -18219,6 +18219,17 @@
   </summary>
 </histogram>
 
+<histogram name="XR.ARCore.DepthBufferSizeInPixels" units="pixels"
+    expires_after="2021-12-01">
+  <owner>bialpio@chromium.org</owner>
+  <owner>xr-dev@chromium.org</owner>
+  <summary>
+    Recorded on every frame for as long as depth data is requested in an XR
+    session backed by ARCore device. Measures the number of pixels (width *
+    height) in the depth buffer obtained from ARCore.
+  </summary>
+</histogram>
+
 <histogram name="XR.RuntimeUsed" enum="XRDeviceId" expires_after="2021-07-01">
   <owner>alcooper@chromium.org</owner>
   <owner>mlamouri@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/sync/histograms.xml b/tools/metrics/histograms/histograms_xml/sync/histograms.xml
index 8483493..13588bad 100644
--- a/tools/metrics/histograms/histograms_xml/sync/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/sync/histograms.xml
@@ -286,7 +286,7 @@
 </histogram>
 
 <histogram name="Sync.CustomEncryption" enum="SyncCustomEncryptionEvent"
-    expires_after="2021-01-03">
+    expires_after="2022-01-03">
   <owner>mastiz@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/translate/histograms.xml b/tools/metrics/histograms/histograms_xml/translate/histograms.xml
index d5bdd6d..108d3cb 100644
--- a/tools/metrics/histograms/histograms_xml/translate/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/translate/histograms.xml
@@ -911,12 +911,14 @@
 </histogram>
 
 <histogram name="Translate.TranslateTabIntentResult"
-    enum="TranslateTabIntentResult" expires_after="M89">
+    enum="TranslateTabIntentResult" expires_after="M91">
   <owner>jds@chromium.org</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
     Android: Records the result of processing a TRANSLATE_TAB intent. See
     TranslateTabIntentResult in enums.xml for possible values.
+
+    This is recorded once for each TRANSLATE_TAB intent received.
   </summary>
 </histogram>
 
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index a365e988..fcea712 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -2,15 +2,15 @@
     "trace_processor_shell": {
         "win": {
             "hash": "83905a5068c26daa567cf81ef4c21963f7584593",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/877fbcb6917926dfd7e80e9de84baa303b2df995/trace_processor_shell.exe"
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/0fdb2247e82e7f60e5391c674ce7267019a5692d/trace_processor_shell.exe"
         },
         "mac": {
-            "hash": "50d02eb2ca79777ef1a5250242d821413d57e41f",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/a45552c0f29dc62ed601a22b258b27ed2838bc57/trace_processor_shell"
+            "hash": "dea74574858697c140bf60eb4552976175677b31",
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/0fdb2247e82e7f60e5391c674ce7267019a5692d/trace_processor_shell"
         },
         "linux": {
             "hash": "d258d32b58428c1acaf19c46e51e820b092227a4",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/8ddf5ae4b8a57c7acc28dad9f2e3857c1d3b7bc0/trace_processor_shell"
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/0fdb2247e82e7f60e5391c674ce7267019a5692d/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index c71e212..a88dda8 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -307,6 +307,7 @@
 crbug.com/1112337 [ android ] system_health.common_mobile/browse:news:cricbuzz:2019 [ Skip ]
 crbug.com/1113921 [ android-go ] system_health.common_mobile/load:tools:dropbox:2019 [ Skip ]
 crbug.com/1139057 [ mobile ] system_health.common_mobile/browse:social:facebook:2019 [ Skip ]
+crbug.com/1154719 [ android-go ] system_health.common_mobile/browse:chrome:omnibox:2019 [ Skip ]
 
 # Benchmark: system_health.memory_desktop
 crbug.com/984599 [ linux ] system_health.memory_desktop/long_running:tools:gmail-foreground [ Skip ]
@@ -398,6 +399,7 @@
 crbug.com/1112337 [ android ] system_health.memory_mobile/browse:news:cricbuzz:2019 [ Skip ]
 crbug.com/1113921 [ android-go ] system_health.memory_mobile/load:tools:dropbox:2019 [ Skip ]
 crbug.com/1139057 [ mobile ] system_health.memory_mobile/browse:social:facebook:2019 [ Skip ]
+crbug.com/1154719 [ android-go ] system_health.memory_mobile/browse:chrome:omnibox:2019 [ Skip ]
 
 # Benchmark: tab_switching.typical_25
 crbug.com/747026 [ mac ] tab_switching.typical_25/multitab:misc:typical24 [ Skip ]
@@ -455,6 +457,7 @@
 crbug.com/1112337 [ android ] v8.browsing_mobile/browse:news:cricbuzz:2019 [ Skip ]
 crbug.com/1139057 [ mobile ] v8.browsing_mobile/browse:social:facebook:2019 [ Skip ]
 crbug.com/1143740 [ android-pixel-2 android-webview ] v8.browsing_mobile/browse:media:imgur:2019 [ Skip ]
+crbug.com/1154719 [ android-go ] v8.browsing_mobile/browse:chrome:omnibox:2019 [ Skip ]
 
 # Benchmark: v8.browsing_mobile-future
 crbug.com/1036141 [ android-webview ] v8.browsing_mobile-future/browse:shopping:lazada:2019 [ Skip ]
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 327a5b9..09e921f 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -800,11 +800,7 @@
       "ime/chromeos/mock_input_method_manager.cc",
       "ime/chromeos/mock_input_method_manager.h",
     ]
-    deps += [
-      # Generates a header used by mock_component_extension_ime_manager_delegate.cc
-      "//chromeos/ime:gencode",
-      "//ui/base/ime/chromeos",
-    ]
+    deps += [ "//ui/base/ime/chromeos" ]
   }
 }
 
diff --git a/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.cc b/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.cc
index 8232642..caa0e85 100644
--- a/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.cc
+++ b/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.cc
@@ -3,20 +3,13 @@
 // found in the LICENSE file.
 
 #include "ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.h"
-#include "chromeos/ime/input_methods.h"
 #include "ui/base/ime/chromeos/component_extension_ime_manager.h"
 
 namespace chromeos {
 namespace input_method {
 
 MockComponentExtensionIMEManagerDelegate::
-    MockComponentExtensionIMEManagerDelegate() {
-  for (const auto& input_method : input_method::kInputMethods) {
-    if (input_method.is_login_keyboard) {
-      login_layout_set_.insert(input_method.xkb_layout_id);
-    }
-  }
-}
+    MockComponentExtensionIMEManagerDelegate() = default;
 
 MockComponentExtensionIMEManagerDelegate::
     ~MockComponentExtensionIMEManagerDelegate() = default;
diff --git a/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.h b/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.h
index 757c1d6..35dcf7c3 100644
--- a/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.h
+++ b/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.h
@@ -30,6 +30,9 @@
   void set_ime_list(const std::vector<ComponentExtensionIME>& ime_list) {
     ime_list_ = ime_list;
   }
+  void set_login_layout_set(const std::set<std::string>& login_layout_set) {
+    login_layout_set_ = login_layout_set;
+  }
 
  private:
   std::set<std::string> login_layout_set_;
diff --git a/ui/base/x/x11_drag_context.cc b/ui/base/x/x11_drag_context.cc
index d07e44d..32cbb35a 100644
--- a/ui/base/x/x11_drag_context.cc
+++ b/ui/base/x/x11_drag_context.cc
@@ -42,12 +42,12 @@
 
 XDragContext::XDragContext(x11::Window local_window,
                            const x11::ClientMessageEvent& event,
-                           XDragDropClient* source_client,
                            const SelectionFormatMap& data)
     : local_window_(local_window),
-      source_window_(static_cast<x11::Window>(event.data.data32[0])),
-      source_client_(source_client) {
-  if (!source_client_) {
+      source_window_(static_cast<x11::Window>(event.data.data32[0])) {
+  XDragDropClient* source_client =
+      XDragDropClient::GetForWindow(source_window_);
+  if (!source_client) {
     bool get_types_from_property = ((event.data.data32[1] & 1) != 0);
 
     if (get_types_from_property) {
@@ -160,7 +160,9 @@
 }
 
 void XDragContext::ReadActions() {
-  if (!source_client_) {
+  XDragDropClient* source_client =
+      XDragDropClient::GetForWindow(source_window_);
+  if (!source_client) {
     std::vector<x11::Atom> atom_array;
     if (!GetAtomArrayProperty(source_window_, kXdndActionList, &atom_array))
       actions_.clear();
@@ -170,7 +172,7 @@
     // We have a property notify set up for other windows in case they change
     // their action list. Thankfully, the views interface is static and you
     // can't change the action list after you enter StartDragAndDrop().
-    actions_ = source_client_->GetOfferedDragOperations();
+    actions_ = source_client->GetOfferedDragOperations();
   }
 }
 
diff --git a/ui/base/x/x11_drag_context.h b/ui/base/x/x11_drag_context.h
index 909fc35..5e9a2ca 100644
--- a/ui/base/x/x11_drag_context.h
+++ b/ui/base/x/x11_drag_context.h
@@ -23,7 +23,6 @@
  public:
   XDragContext(x11::Window local_window,
                const x11::ClientMessageEvent& event,
-               XDragDropClient* source_client,
                const SelectionFormatMap& data);
   ~XDragContext();
 
@@ -31,7 +30,6 @@
   XDragContext& operator=(const XDragContext&) = delete;
 
   x11::Window source_window() const { return source_window_; }
-  XDragDropClient* source_client() { return source_client_; }
   const SelectionFormatMap& fetched_targets() const { return fetched_targets_; }
 
   // When we receive an XdndPosition message, we need to have all the data
@@ -73,10 +71,6 @@
   // The x11::Window of the window that initiated the drag.
   x11::Window source_window_;
 
-  // The DesktopDragDropClientAuraX11 for |source_window_| if |source_window_|
-  // belongs to a Chrome window.
-  XDragDropClient* source_client_;
-
   // The client we inform once we're done with requesting data.
   XDragDropClient* drag_drop_client_ = nullptr;
 
diff --git a/ui/base/x/x11_drag_drop_client.cc b/ui/base/x/x11_drag_drop_client.cc
index 51ff062..2fa606f9 100644
--- a/ui/base/x/x11_drag_drop_client.cc
+++ b/ui/base/x/x11_drag_drop_client.cc
@@ -310,11 +310,11 @@
       GetForWindow(static_cast<x11::Window>(event.data.data32[0]));
   DCHECK(!source_client || source_client->source_provider_);
   target_current_context_ = std::make_unique<XDragContext>(
-      xwindow_, event, source_client,
+      xwindow_, event,
       (source_client ? source_client->source_provider_->GetFormatMap()
                      : SelectionFormatMap()));
 
-  if (!target_current_context()->source_client()) {
+  if (!source_client) {
     // The window doesn't have a DesktopDragDropClientAuraX11, which means it's
     // created by some other process.  Listen for messages on it.
     delegate_->OnBeginForeignDrag(
@@ -485,7 +485,9 @@
 void XDragDropClient::ResetDragContext() {
   if (!target_current_context())
     return;
-  if (!target_current_context()->source_client())
+  XDragDropClient* source_client =
+      GetForWindow(target_current_context()->source_window());
+  if (!source_client)
     delegate_->OnEndForeignDrag();
 
   target_current_context_.reset();
diff --git a/ui/base/x/x11_drag_drop_client.h b/ui/base/x/x11_drag_drop_client.h
index ecc58ef..e32e731 100644
--- a/ui/base/x/x11_drag_drop_client.h
+++ b/ui/base/x/x11_drag_drop_client.h
@@ -77,6 +77,11 @@
   XDragDropClient(const XDragDropClient&) = delete;
   XDragDropClient& operator=(const XDragDropClient&) = delete;
 
+  // We maintain a mapping of live XDragDropClient objects to their X11 windows,
+  // so that we'd able to short circuit sending X11 messages to windows in our
+  // process.
+  static XDragDropClient* GetForWindow(x11::Window window);
+
   x11::Window xwindow() const { return xwindow_; }
   XDragContext* target_current_context() {
     return target_current_context_.get();
@@ -194,11 +199,6 @@
   void SendXdndLeave(x11::Window dest_window);
   void SendXdndDrop(x11::Window dest_window);
 
-  // We maintain a mapping of live XDragDropClient objects to their X11 windows,
-  // so that we'd able to short circuit sending X11 messages to windows in our
-  // process.
-  static XDragDropClient* GetForWindow(x11::Window window);
-
   void EndMoveLoop();
 
   Delegate* const delegate_;
diff --git a/ui/compositor/BUILD.gn b/ui/compositor/BUILD.gn
index 9383a56..bc03547 100644
--- a/ui/compositor/BUILD.gn
+++ b/ui/compositor/BUILD.gn
@@ -69,6 +69,8 @@
     "throughput_tracker.cc",
     "throughput_tracker.h",
     "throughput_tracker_host.h",
+    "total_animation_throughput_reporter.cc",
+    "total_animation_throughput_reporter.h",
     "transform_animation_curve_adapter.cc",
     "transform_animation_curve_adapter.h",
     "transform_recorder.cc",
@@ -238,6 +240,7 @@
     "layer_owner_unittest.cc",
     "layer_unittest.cc",
     "run_all_unittests.cc",
+    "total_animation_throughput_reporter_unittest.cc",
     "transform_animation_curve_adapter_unittest.cc",
   ]
 
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index 07c2a39..d0ffe90 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -576,13 +576,23 @@
 }
 
 void Compositor::AddAnimationObserver(CompositorAnimationObserver* observer) {
+  if (!animation_observer_list_.has_observers()) {
+    for (auto& obs : observer_list_)
+      obs.OnFirstAnimationStarted(this);
+  }
   animation_observer_list_.AddObserver(observer);
   host_->SetNeedsAnimate();
 }
 
 void Compositor::RemoveAnimationObserver(
     CompositorAnimationObserver* observer) {
+  if (!animation_observer_list_.HasObserver(observer))
+    return;
   animation_observer_list_.RemoveObserver(observer);
+  if (!animation_observer_list_.has_observers()) {
+    for (auto& obs : observer_list_)
+      obs.OnLastAnimationEnded(this);
+  }
 }
 
 bool Compositor::HasAnimationObserver(
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index bb08a017..f9bf9e1 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -409,6 +409,7 @@
 
  private:
   friend class base::RefCounted<Compositor>;
+  friend class TotalAnimationThroughputReporter;
 
   // Called when collected metrics for the tracker of |tracker_id| is ready.
   void ReportMetricsForTracker(
diff --git a/ui/compositor/compositor_observer.h b/ui/compositor/compositor_observer.h
index 32c6e49..a14b75b5 100644
--- a/ui/compositor/compositor_observer.h
+++ b/ui/compositor/compositor_observer.h
@@ -60,6 +60,9 @@
   virtual void OnDidPresentCompositorFrame(
       uint32_t frame_token,
       const gfx::PresentationFeedback& feedback) {}
+
+  virtual void OnFirstAnimationStarted(Compositor* compositor) {}
+  virtual void OnLastAnimationEnded(Compositor* compositor) {}
 };
 
 }  // namespace ui
diff --git a/ui/compositor/total_animation_throughput_reporter.cc b/ui/compositor/total_animation_throughput_reporter.cc
new file mode 100644
index 0000000..2d85c436
--- /dev/null
+++ b/ui/compositor/total_animation_throughput_reporter.cc
@@ -0,0 +1,91 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/compositor/total_animation_throughput_reporter.h"
+
+#include "base/logging.h"
+#include "ui/compositor/compositor.h"
+
+namespace ui {
+
+TotalAnimationThroughputReporter::TotalAnimationThroughputReporter(
+    ui::Compositor* compositor,
+    ReportOnceCallback once_callback,
+    bool should_delete)
+    : TotalAnimationThroughputReporter(compositor,
+                                       ReportRepeatingCallback(),
+                                       std::move(once_callback),
+                                       should_delete) {}
+
+TotalAnimationThroughputReporter::TotalAnimationThroughputReporter(
+    ui::Compositor* compositor,
+    ReportRepeatingCallback repeating_callback)
+    : TotalAnimationThroughputReporter(compositor,
+                                       repeating_callback,
+                                       ReportOnceCallback(),
+                                       /*should_delete=*/false) {}
+
+TotalAnimationThroughputReporter::~TotalAnimationThroughputReporter() {
+  if (throughput_tracker_)
+    throughput_tracker_->Cancel();
+  if (compositor_)
+    compositor_->RemoveObserver(this);
+}
+
+void TotalAnimationThroughputReporter::OnFirstAnimationStarted(
+    ui::Compositor* compositor) {
+  throughput_tracker_ = compositor->RequestNewThroughputTracker();
+  throughput_tracker_->Start(base::BindRepeating(
+      &TotalAnimationThroughputReporter::Report, ptr_factory_.GetWeakPtr()));
+}
+
+void TotalAnimationThroughputReporter::OnLastAnimationEnded(
+    ui::Compositor* compositor) {
+  throughput_tracker_->Stop();
+  throughput_tracker_.reset();
+}
+
+void TotalAnimationThroughputReporter::OnCompositingShuttingDown(
+    ui::Compositor* compositor) {
+  if (throughput_tracker_) {
+    throughput_tracker_->Cancel();
+    throughput_tracker_.reset();
+  }
+  compositor->RemoveObserver(this);
+  compositor_ = nullptr;
+  if (should_delete_)
+    delete this;
+}
+
+TotalAnimationThroughputReporter::TotalAnimationThroughputReporter(
+    ui::Compositor* compositor,
+    ReportRepeatingCallback repeating_callback,
+    ReportOnceCallback once_callback,
+    bool should_delete)
+    : compositor_(compositor),
+      report_repeating_callback_(repeating_callback),
+      report_once_callback_(std::move(once_callback)),
+      should_delete_(should_delete) {
+  DCHECK_NE(report_repeating_callback_.is_null(),
+            report_once_callback_.is_null());
+
+  compositor_->AddObserver(this);
+  if (compositor->animation_observer_list_.has_observers())
+    OnFirstAnimationStarted(compositor_);
+}
+
+void TotalAnimationThroughputReporter::Report(
+    const cc::FrameSequenceMetrics::CustomReportData& data) {
+  if (!report_once_callback_.is_null()) {
+    compositor_->RemoveObserver(this);
+    std::move(report_once_callback_).Run(data);
+    if (should_delete_)
+      delete this;
+    return;
+  }
+  if (!report_repeating_callback_.is_null())
+    report_repeating_callback_.Run(data);
+}
+
+}  // namespace ui
diff --git a/ui/compositor/total_animation_throughput_reporter.h b/ui/compositor/total_animation_throughput_reporter.h
new file mode 100644
index 0000000..6edc347
--- /dev/null
+++ b/ui/compositor/total_animation_throughput_reporter.h
@@ -0,0 +1,89 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_COMPOSITOR_TOTAL_ANIMATION_THROUGHPUT_REPORTER_H_
+#define UI_COMPOSITOR_TOTAL_ANIMATION_THROUGHPUT_REPORTER_H_
+
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "cc/metrics/frame_sequence_metrics.h"
+#include "ui/compositor/compositor_export.h"
+#include "ui/compositor/compositor_observer.h"
+#include "ui/compositor/throughput_tracker.h"
+
+namespace ui {
+
+// Reports cc::FrameSequenceMetrics::ThroughputData between the first animation
+// start and the last animation ends on a compositor.
+//
+// Please see AnimationThroughputReporter for the definition of the throughput
+// and jack metrics.
+//
+// See also docs/speed/graphics_metrics_definitions.md.
+//
+// cc::FrameSequenceMetrics::CustomReportData contains the numbers of produced
+// frames, expected frames and jank count.
+//
+// The tracking starts when the first animation observer is added to the
+// compositor, then stopped when the last animation observer is removed.  The
+// report callback is invoked on the next begin frame if there is enough data.
+// Since this observes multiple animations, aborting one of animations will
+// not cancel the tracking, and the data will be reported as normal.
+class COMPOSITOR_EXPORT TotalAnimationThroughputReporter
+    : public CompositorObserver {
+ public:
+  using ReportOnceCallback = base::OnceCallback<void(
+      const cc::FrameSequenceMetrics::CustomReportData& data)>;
+  using ReportRepeatingCallback = base::RepeatingCallback<void(
+      const cc::FrameSequenceMetrics::CustomReportData& data)>;
+
+  // Create a TotalAnimationThroughputReporter that observes
+  // the total animation throughput just once. If |should_delete|
+  // is true, then the object will be deleted after callback is
+  // invoked.
+  TotalAnimationThroughputReporter(Compositor* compositor,
+                                   ReportOnceCallback callback,
+                                   bool should_delete);
+
+  // Create a persistent TotalAnimationThroughputReporter, which
+  // will call the callback every time the last animation is finished.
+  TotalAnimationThroughputReporter(Compositor* compositor,
+                                   ReportRepeatingCallback callback);
+
+  TotalAnimationThroughputReporter(const TotalAnimationThroughputReporter&) =
+      delete;
+  TotalAnimationThroughputReporter& operator=(
+      const TotalAnimationThroughputReporter&) = delete;
+  ~TotalAnimationThroughputReporter() override;
+
+  // CompositorObserver:
+  void OnFirstAnimationStarted(Compositor* compositor) override;
+  void OnLastAnimationEnded(Compositor* compositor) override;
+  void OnCompositingShuttingDown(Compositor* compositor) override;
+
+  bool IsMeasuringForTesting() const { return bool{throughput_tracker_}; }
+
+ private:
+  TotalAnimationThroughputReporter(Compositor* compositor,
+                                   ReportRepeatingCallback repeating_callback,
+                                   ReportOnceCallback once_callback,
+                                   bool should_delete);
+
+  void Report(const cc::FrameSequenceMetrics::CustomReportData& data);
+
+  Compositor* compositor_;
+  ReportRepeatingCallback report_repeating_callback_;
+  ReportOnceCallback report_once_callback_;
+  bool should_delete_ = false;
+  base::Optional<ThroughputTracker> throughput_tracker_;
+
+  base::WeakPtrFactory<TotalAnimationThroughputReporter> ptr_factory_{this};
+};
+
+}  // namespace ui
+
+#endif  // UI_COMPOSITOR_TOTAL_ANIMATION_THROUGHPUT_REPORTER_H_
diff --git a/ui/compositor/total_animation_throughput_reporter_unittest.cc b/ui/compositor/total_animation_throughput_reporter_unittest.cc
new file mode 100644
index 0000000..9b61549
--- /dev/null
+++ b/ui/compositor/total_animation_throughput_reporter_unittest.cc
@@ -0,0 +1,380 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/compositor/total_animation_throughput_reporter.h"
+
+#include <memory>
+
+#include "base/run_loop.h"
+#include "base/test/bind.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "cc/metrics/frame_sequence_metrics.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animation_sequence.h"
+#include "ui/compositor/layer_animator.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/compositor/test/animation_throughput_reporter_test_base.h"
+#include "ui/gfx/geometry/rect.h"
+
+#if defined(OS_WIN)
+// TestCompositor doesn't work with MOCK_TIME on Windows. crbug.com/1152103
+#define MAYBE_SingleAnimation DISABLED_SingleAnimation
+#define MAYBE_StopAnimation DISABLED_StopAnimation
+#define MAYBE_MultipleAnimations DISABLED_MultipleAnimations
+#define MAYBE_MultipleAnimationsOnSingleLayer \
+  DISABLED_MultipleAnimationsOnSingleLayer
+#define MAYBE_AddAnimationWhileAnimating DISABLED_AddAnimationWhileAnimating
+#define MAYBE_RemoveWhileAnimating DISABLED_RemoveWhileAnimating
+#define MAYBE_StartWhileAnimating DISABLED_StartWhileAnimating
+#define MAYBE_PersistedAnimation DISABLED_PersistedAnimation
+#define MAYBE_OnceReporter DISABLED_OnceReporter
+#define MAYBE_OnceReporterShouldDelete DISABLED_OnceReporterShouldDelete
+#else
+#define MAYBE_SingleAnimation SingleAnimation
+#define MAYBE_StopAnimation StopAnimation
+#define MAYBE_MultipleAnimations MultipleAnimations
+#define MAYBE_MultipleAnimationsOnSingleLayer MultipleAnimationsOnSingleLayer
+#define MAYBE_AddAnimationWhileAnimating AddAnimationWhileAnimating
+#define MAYBE_RemoveWhileAnimating RemoveWhileAnimating
+#define MAYBE_StartWhileAnimating StartWhileAnimating
+#define MAYBE_PersistedAnimation PersistedAnimation
+#define MAYBE_OnceReporter OnceReporter
+#define MAYBE_OnceReporterShouldDelete OnceReporterShouldDelete
+#endif
+
+namespace ui {
+namespace {
+
+class TestReporter : public TotalAnimationThroughputReporter {
+ public:
+  explicit TestReporter(ui::Compositor* compositor)
+      : ui::TotalAnimationThroughputReporter(
+            compositor,
+            base::BindRepeating(&TestReporter::Reported,
+                                base::Unretained(this))) {}
+  TestReporter(ui::Compositor* compositor, bool should_delete)
+      : ui::TotalAnimationThroughputReporter(
+            compositor,
+            base::BindOnce(&TestReporter::Reported, base::Unretained(this)),
+            should_delete) {}
+
+  TestReporter(const TestReporter&) = delete;
+  TestReporter& operator=(const TestReporter&) = delete;
+  ~TestReporter() override = default;
+
+  bool reported() const { return reported_; }
+
+  void reset() { reported_ = false; }
+
+ private:
+  void Reported(const cc::FrameSequenceMetrics::CustomReportData&) {
+    reported_ = true;
+  }
+
+  bool reported_ = false;
+};
+
+}  // namespace
+
+using TotalAnimationThroughputReporterTest =
+    AnimationThroughputReporterTestBase;
+
+TEST_F(TotalAnimationThroughputReporterTest, MAYBE_SingleAnimation) {
+  Layer layer;
+  layer.SetOpacity(0.5f);
+  root_layer()->Add(&layer);
+
+  TestReporter reporter(compositor());
+  {
+    LayerAnimator* animator = layer.GetAnimator();
+
+    ScopedLayerAnimationSettings settings(animator);
+    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
+    layer.SetOpacity(1.0f);
+  }
+  Advance(base::TimeDelta::FromMilliseconds(32));
+  EXPECT_FALSE(reporter.reported());
+  Advance(base::TimeDelta::FromMilliseconds(32));
+  EXPECT_TRUE(reporter.reported());
+}
+
+// Tests the stopping last animation will trigger the animation.
+TEST_F(TotalAnimationThroughputReporterTest, MAYBE_StopAnimation) {
+  Layer layer;
+  layer.SetOpacity(0.5f);
+  root_layer()->Add(&layer);
+
+  TestReporter reporter(compositor());
+  {
+    LayerAnimator* animator = layer.GetAnimator();
+
+    ScopedLayerAnimationSettings settings(animator);
+    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
+    layer.SetOpacity(1.0f);
+  }
+
+  Advance(base::TimeDelta::FromMilliseconds(16));
+  EXPECT_FALSE(reporter.reported());
+  layer.GetAnimator()->StopAnimating();
+  Advance(base::TimeDelta::FromMilliseconds(16));
+  EXPECT_TRUE(reporter.reported());
+}
+
+// Tests the longest animation will trigger the report.
+TEST_F(TotalAnimationThroughputReporterTest, MAYBE_MultipleAnimations) {
+  Layer layer1;
+  layer1.SetOpacity(0.5f);
+  root_layer()->Add(&layer1);
+
+  TestReporter reporter(compositor());
+  {
+    LayerAnimator* animator = layer1.GetAnimator();
+
+    ScopedLayerAnimationSettings settings(animator);
+    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
+    layer1.SetOpacity(1.0f);
+  }
+  Layer layer2;
+  layer2.SetOpacity(0.5f);
+  root_layer()->Add(&layer2);
+
+  {
+    LayerAnimator* animator = layer2.GetAnimator();
+
+    ScopedLayerAnimationSettings settings(animator);
+    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(96));
+    layer2.SetOpacity(1.0f);
+  }
+
+  Advance(base::TimeDelta::FromMilliseconds(32));
+  EXPECT_FALSE(reporter.reported());
+  Advance(base::TimeDelta::FromMilliseconds(32));
+  EXPECT_FALSE(reporter.reported());
+  Advance(base::TimeDelta::FromMilliseconds(200));
+  EXPECT_TRUE(reporter.reported());
+}
+
+// Tests the longest animation on a single layer will triger the report.
+TEST_F(TotalAnimationThroughputReporterTest,
+       MAYBE_MultipleAnimationsOnSingleLayer) {
+  Layer layer;
+  layer.SetOpacity(0.5f);
+  layer.SetLayerBrightness(0.5f);
+  root_layer()->Add(&layer);
+
+  TestReporter reporter(compositor());
+  {
+    LayerAnimator* animator = layer.GetAnimator();
+
+    ScopedLayerAnimationSettings settings(animator);
+    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
+    layer.SetOpacity(1.0f);
+  }
+  {
+    LayerAnimator* animator = layer.GetAnimator();
+
+    ScopedLayerAnimationSettings settings(animator);
+    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(96));
+    layer.SetLayerBrightness(1.0f);
+  }
+
+  Advance(base::TimeDelta::FromMilliseconds(64));
+  EXPECT_FALSE(reporter.reported());
+  Advance(base::TimeDelta::FromMilliseconds(48));
+  EXPECT_TRUE(reporter.reported());
+}
+
+// Tests adding new animation will extends the duration.
+TEST_F(TotalAnimationThroughputReporterTest, MAYBE_AddAnimationWhileAnimating) {
+  Layer layer1;
+  layer1.SetOpacity(0.5f);
+  root_layer()->Add(&layer1);
+
+  TestReporter reporter(compositor());
+  {
+    LayerAnimator* animator = layer1.GetAnimator();
+
+    ScopedLayerAnimationSettings settings(animator);
+    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
+    layer1.SetOpacity(1.0f);
+  }
+
+  Advance(base::TimeDelta::FromMilliseconds(32));
+  EXPECT_FALSE(reporter.reported());
+
+  // Add new animation while animating.
+  Layer layer2;
+  layer2.SetOpacity(0.5f);
+  root_layer()->Add(&layer2);
+
+  {
+    LayerAnimator* animator = layer2.GetAnimator();
+
+    ScopedLayerAnimationSettings settings(animator);
+    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
+    layer2.SetOpacity(1.0f);
+  }
+
+  // The animation time is extended.
+  Advance(base::TimeDelta::FromMilliseconds(32));
+  EXPECT_FALSE(reporter.reported());
+
+  Advance(base::TimeDelta::FromMilliseconds(32));
+  EXPECT_TRUE(reporter.reported());
+}
+
+// Tests removing last animation will call report callback.
+TEST_F(TotalAnimationThroughputReporterTest, MAYBE_RemoveWhileAnimating) {
+  auto layer1 = std::make_unique<Layer>();
+  layer1->SetOpacity(0.5f);
+  root_layer()->Add(layer1.get());
+
+  TestReporter reporter(compositor());
+  {
+    LayerAnimator* animator = layer1->GetAnimator();
+
+    ScopedLayerAnimationSettings settings(animator);
+    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(100));
+    layer1->SetOpacity(1.0f);
+  }
+
+  Layer layer2;
+  layer2.SetOpacity(0.5f);
+  root_layer()->Add(&layer2);
+
+  {
+    LayerAnimator* animator = layer2.GetAnimator();
+
+    ScopedLayerAnimationSettings settings(animator);
+    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
+    layer2.SetOpacity(1.0f);
+  }
+  Advance(base::TimeDelta::FromMilliseconds(48));
+  EXPECT_FALSE(reporter.reported());
+  layer1.reset();
+  // Aborting will be processed in next frame.
+  Advance(base::TimeDelta::FromMilliseconds(16));
+  EXPECT_TRUE(reporter.reported());
+}
+
+// Make sure the reporter can start measuring even if the animation
+// has started.
+TEST_F(TotalAnimationThroughputReporterTest, MAYBE_StartWhileAnimating) {
+  Layer layer;
+  layer.SetOpacity(0.5f);
+  root_layer()->Add(&layer);
+
+  {
+    LayerAnimator* animator = layer.GetAnimator();
+
+    ScopedLayerAnimationSettings settings(animator);
+    settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(48));
+    layer.SetOpacity(1.0f);
+  }
+  Advance(base::TimeDelta::FromMilliseconds(16));
+
+  TestReporter reporter(compositor());
+  EXPECT_TRUE(reporter.IsMeasuringForTesting());
+  Advance(base::TimeDelta::FromMilliseconds(100));
+  EXPECT_TRUE(reporter.reported());
+}
+
+// Tests the reporter is called multiple times for persistent animation.
+TEST_F(TotalAnimationThroughputReporterTest, MAYBE_PersistedAnimation) {
+  Layer layer;
+  layer.SetOpacity(0.5f);
+  root_layer()->Add(&layer);
+
+  // Set a persisted animator to |layer|.
+  LayerAnimator* animator =
+      new LayerAnimator(base::TimeDelta::FromMilliseconds(48));
+  layer.SetAnimator(animator);
+
+  // |reporter| keeps reporting as long as it is alive.
+  TestReporter reporter(compositor());
+
+  // Report data for animation of opacity goes to 1.
+  layer.SetOpacity(1.0f);
+  Advance(base::TimeDelta::FromMilliseconds(100));
+  EXPECT_TRUE(reporter.reported());
+
+  // Report data for animation of opacity goes to 0.5.
+  reporter.reset();
+  layer.SetOpacity(0.5f);
+  Advance(base::TimeDelta::FromMilliseconds(100));
+  EXPECT_TRUE(reporter.reported());
+}
+
+// Make sure the once reporter is called only once.
+TEST_F(TotalAnimationThroughputReporterTest, MAYBE_OnceReporter) {
+  Layer layer;
+  layer.SetOpacity(0.5f);
+  root_layer()->Add(&layer);
+
+  // Set a persisted animator to |layer|.
+  LayerAnimator* animator =
+      new LayerAnimator(base::TimeDelta::FromMilliseconds(32));
+  layer.SetAnimator(animator);
+
+  TestReporter reporter(compositor(), /*should_delete=*/false);
+
+  // Report data for animation of opacity goes to 1.
+  layer.SetOpacity(1.0f);
+  Advance(base::TimeDelta::FromMilliseconds(100));
+  EXPECT_TRUE(reporter.reported());
+
+  // Report data for animation of opacity goes to 0.5.
+  reporter.reset();
+  layer.SetOpacity(1.0f);
+  Advance(base::TimeDelta::FromMilliseconds(100));
+  EXPECT_FALSE(reporter.reported());
+}
+
+// One reporter marked as "should_delete" should be deleted when
+// reported.
+TEST_F(TotalAnimationThroughputReporterTest, MAYBE_OnceReporterShouldDelete) {
+  class DeleteTestReporter : public TotalAnimationThroughputReporter {
+   public:
+    DeleteTestReporter(Compositor* compositor,
+                       ReportOnceCallback callback,
+                       bool* deleted)
+        : TotalAnimationThroughputReporter(compositor,
+                                           std::move(callback),
+                                           true),
+          deleted_(deleted) {}
+    ~DeleteTestReporter() override { *deleted_ = true; }
+
+   private:
+    bool* deleted_;
+  };
+
+  Layer layer;
+  layer.SetOpacity(0.5f);
+  root_layer()->Add(&layer);
+
+  // Set a persisted animator to |layer|.
+  LayerAnimator* animator =
+      new LayerAnimator(base::TimeDelta::FromMilliseconds(32));
+  layer.SetAnimator(animator);
+
+  // |reporter| keeps reporting as long as it is alive.
+  bool reported = false;
+  bool deleted = false;
+  new DeleteTestReporter(
+      compositor(),
+      base::BindLambdaForTesting(
+          [&](const cc::FrameSequenceMetrics::CustomReportData&) {
+            reported = true;
+          }),
+      &deleted);
+
+  // Report data for animation of opacity goes to 1.
+  layer.SetOpacity(1.0f);
+  Advance(base::TimeDelta::FromMilliseconds(100));
+  EXPECT_TRUE(reported);
+  EXPECT_TRUE(deleted);
+}
+
+}  // namespace ui
diff --git a/ui/file_manager/base/gn/js_test_gen_html.py b/ui/file_manager/base/gn/js_test_gen_html.py
index c64ca4b1..4a8b0894 100644
--- a/ui/file_manager/base/gn/js_test_gen_html.py
+++ b/ui/file_manager/base/gn/js_test_gen_html.py
@@ -44,6 +44,12 @@
 </html>
 """
 
+_ELEMENTS_BUNDLE_IMPORTED = False
+_ELEMENTS_BUNDLE = _IMPORT % (
+  'chrome://file_manager_test/ui/file_manager/file_manager/foreground/elements'
+  '/elements_bundle.html')
+
+
 
 def _process_deps(unique_deps, dep_type, target_name):
   """Processes all deps strings, yielding each HTML tag to include the dep.
@@ -72,6 +78,26 @@
       # just ignore other files files from /jstemplate/
       continue
 
+    # Ignoring Polymer files, because they're loaded by the HTML imports from
+    # other files.
+    if 'third_party/polymer/' in dep:
+      continue
+
+    # These files are loaded via HTML import. Don't load them again here: that
+    # would cause the tests to fail.
+    if 'parse_html_subset.js' in dep:
+      continue
+    if 'i18n_behavior.js' in dep:
+      continue
+
+    # Any JS from /elements/ will be HTML imported via the elements_bundle.html.
+    if 'file_manager/foreground/elements/' in dep and not'_unittest' in dep:
+      global _ELEMENTS_BUNDLE_IMPORTED
+      if not _ELEMENTS_BUNDLE_IMPORTED:
+        yield _ELEMENTS_BUNDLE
+        _ELEMENTS_BUNDLE_IMPORTED = True
+      continue
+
     # Map file_manager files:
     dep = dep.replace('ui/file_manager/',
                       'chrome://file_manager_test/ui/file_manager/', 1)
@@ -83,10 +109,6 @@
     # WebUI files (both Polymer and non-Polymer):
     dep = dep.replace('ui/webui/resources/', 'chrome://resources/', 1)
 
-    # Polymer Files:
-    dep = dep.replace('third_party/polymer/', 'chrome://resources/polymer/', 1)
-    dep = dep.replace('components-chromium/', '', 1)
-
     # Remove the relative because all replaces above map to an absolute path in
     # chrome://* and this URL scheme doesn't allow "..".
     dep = dep.replace('../', '')
@@ -150,8 +172,9 @@
   with open(output_filename, 'w') as out:
     out.write(_HTML_FILE)
 
-    if html_import:
-      out.write(_HTML_IMPORT_POLYFIL + '\n')
+    # Always add the HTML polyfil and the Polymer config.
+    out.write(_HTML_IMPORT_POLYFIL + '\n')
+    out.write(_IMPORT % ('chrome://resources/html/polymer.html') + '\n')
 
     dep_type = 'html_import' if html_import else 'classic_script'
     for dep in _process_deps(mocks, dep_type, target_name):
diff --git a/ui/file_manager/base/tools/modules.py b/ui/file_manager/base/tools/modules.py
deleted file mode 100755
index c7bcfcd..0000000
--- a/ui/file_manager/base/tools/modules.py
+++ /dev/null
@@ -1,744 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (c) 2020 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-import re
-import sys
-import subprocess
-from textwrap import dedent
-
-# TODO:
-# Add externs automatically.
-# Remove or ignore 'use strict'.
-# Handle Polymer elements conversion.
-
-
-def get_file_lines(file_path):
-    '''Returns list of lines from a file. '\n' at the end of lines are
-    removed.'''
-    with open(file_path, 'r') as f:
-        file_lines = f.readlines()
-    return [l.rstrip() for l in file_lines]
-
-
-def save_file_lines(file_path, file_lines):
-    '''Saves file_lines in file pointed by `file_path`, '\n' at the end of
-    lines are added back.'''
-    with open(file_path, 'w') as f:
-        f.write('\n'.join(file_lines) + '\n')
-
-
-def get_relative_dependency(path, dir_path):
-    '''Given a file path, returns formatted BUILD.gn dependency
-  (e.g. ":file_type.m", "//ui/file_manager/externs:volume_manager.m").'''
-    split_path = path.split('/')
-    file_name = split_path.pop().replace('.js', '.m')
-    split_dir_path = dir_path.split('/')
-    while (len(split_path) > 0 and len(split_dir_path) > 0
-           and split_path[0] == split_dir_path[0]):
-        del split_path[0]
-        del split_dir_path[0]
-    if len(split_dir_path) == 0:
-        # The dependency is within dir_path.
-        return '/'.join(split_path) + ':' + file_name
-    else:
-        return '//' + re.sub(r"\/[a-zA-Z0-9_]+\.js", ":", path) + file_name
-
-
-def get_index_substr(file_lines, substr):
-    '''Finds first occurence of `substr` and returns its index in
-    `file_lines`.'''
-    for i, line in enumerate(file_lines):
-        if substr in line:
-            return i
-    return -1
-
-
-def get_end_of_copyright(file_lines):
-    '''Get index of last line of copyright (after checking that the section
-    exists).'''
-    index = get_index_substr(file_lines, 'Copyright 20')
-    if index < 0:
-        return -1
-    while index < len(file_lines) and file_lines[index].startswith('// '):
-        index += 1
-    return index - 1
-
-
-def get_end_of_file_overview(file_lines):
-    '''Get index of last line of file_overview (after checking that the section
-    exists).'''
-    index = get_index_substr(file_lines, '@fileoverview')
-    if index < 0:
-        return -1
-    while index < len(file_lines) and file_lines[index] != ' */':
-        index += 1
-    return index
-
-
-def get_last_index_of_line_starting_with(file_lines, substr):
-    '''Get last line starting with the given `substr`.'''
-    last_index = -1
-    for i, line in enumerate(file_lines):
-        if line.startswith(substr):
-            last_index = i
-    return last_index
-
-
-def get_end_of_build_imports(file_lines):
-    '''In BUILD.gn, gets index of last 'import' line at the beginning of the
-    file.'''
-    index = get_index_substr(
-        file_lines, 'import("//third_party/closure_compiler/compile_js.gni")')
-    if index < 0:
-        return get_end_of_copyright(file_lines)
-    while 'import("' in file_lines[index]:
-        index += 1
-    return index - 1
-
-
-def add_js_library(file_lines, file_name, dir_path):
-    '''Adds js_library target in BUILD.gn.'''
-    # Check that the library does exist and hasn't already been converted.
-    if not 'js_library("%s") {' % file_name in file_lines:
-        print 'Unable to find js_library for {}'.format(file_name)
-        return False
-    if 'js_library("{}.m") {{'.format(file_name) in file_lines:
-        print 'js_library for {}.m already added'.format(file_name)
-        return False
-
-    # Find the end of the library definition.
-    i = file_lines.index('js_library("{}") {{'.format(file_name))
-    while i < len(file_lines) and file_lines[i] != '}':
-        i += 1
-    i += 1
-    if i == len(file_lines):
-        print 'reached end of file'
-        return False
-    new_lines = '''
-    js_library("%s.m") {
-      sources = [ "$root_gen_dir/%s/%s.m.js" ]
-
-      extra_deps = [ ":modulize" ]
-    }''' % (file_name, dir_path, file_name)
-    file_lines[i:i] = dedent(new_lines).split('\n')
-    return True
-
-
-def add_import_line(file_lines,
-                    variable,
-                    relative_path,
-                    is_unittest,
-                    is_wrapped,
-                    wrapped_variable=''):
-    # Construct import line.
-    import_line = 'import ' if is_unittest else '// #import '
-    if is_wrapped:
-        import_line += "* as %s from '%s'; const {%s} = %s;" % (
-            wrapped_variable, relative_path, variable, wrapped_variable)
-    else:
-        # Check: existing relative path.
-        i = get_index_substr(file_lines, relative_path)
-        if i >= 0 and '}' in file_lines[i]:
-            if variable + '}' in file_lines[i] or variable + ',' in file_lines[
-                    i]:
-                return
-            split_line = file_lines[i].split('}')
-            file_lines[i] = '%s, %s}%s' % (split_line[0], variable,
-                                           split_line[1])
-            return
-        import_line += "{%s} from '%s';" % (variable, relative_path)
-    if import_line in file_lines:
-        return
-
-    # Add clang-format off/on if necessary.
-    index = 0
-    if '// clang-format off' in file_lines:
-        index = file_lines.index('// clang-format off')
-    else:
-
-        # Go to the end of copyright and fileoverview.
-        index = get_end_of_file_overview(file_lines)
-        if index < 0:
-            index = get_end_of_copyright(file_lines)
-            if (index < 0):
-                index = 0
-        index += 1
-        if len(import_line) > 80:
-            index += 1
-            file_lines.insert(index, '// clang-format off')
-
-            # Go to the last existing import line.
-            last_import_line_index = get_last_index_of_line_starting_with(
-                file_lines, 'import ')
-            if last_import_line_index >= 0:
-                index = last_import_line_index
-            else:
-                file_lines.insert(index + 1, '')
-            file_lines.insert(index + 1, '// clang-format off')
-        elif 'import ' not in file_lines[index + 1]:
-            file_lines.insert(index, '')
-
-    # Add import line.
-    file_lines.insert(index + 1, import_line)
-
-
-def add_namespace_rewrite(build_gn_path):
-    build_file_lines = get_file_lines(build_gn_path)
-
-    # Add import("//ui/webui/resources/js/cr.gni").
-    if not 'import("//ui/webui/resources/js/cr.gni")' in build_file_lines:
-        modulizer_gni = ('import("//ui/webui/resources/tools/'
-                         'js_modulizer.gni")')
-        if not modulizer_gni in build_file_lines:
-            raise ValueError('"js_modulizer.gni" not found')
-        index = build_file_lines.index(
-            'import("//ui/webui/resources/tools/js_modulizer.gni")')
-        build_file_lines.insert(index,
-                                'import("//ui/webui/resources/js/cr.gni")')
-
-    # Add namespace_rewrites = cr_namespace_rewrites.
-    namespace_rewrite = '  namespace_rewrites = cr_namespace_rewrites'
-    if not namespace_rewrite in build_file_lines:
-        index = get_index_substr(build_file_lines,
-                                 'js_modulizer("modulize") {')
-        if index < 0:
-            print 'No modulize rule found'
-            return
-        while index < len(build_file_lines) and build_file_lines[index] != '':
-            index += 1
-        # Adding a ',' at the beginning to make `dedent` understand what the
-        # correct indentation is.
-        new_lines = '''\
-        ,
-          namespace_rewrites = cr_namespace_rewrites'''
-        index -= 1
-        build_file_lines[index:index] = dedent(new_lines).split('\n')[1:]
-
-    save_file_lines(build_gn_path, build_file_lines)
-
-
-def add_dependency(file_lines, section_first_line, list_name, dependency_line):
-    '''
-    Add dependency in BUILD.gn.
-    Parameters:
-        file_lines: lines of BUILD.gn file.
-        section_first_line: opening line of target to update.
-        list_name: name of the dependency list, deps', 'input_files' etc...
-        dependency_line: line to add to the dependency list to update.
-    '''
-    # Find a line that starts with deps.
-    if not section_first_line in file_lines:
-        print 'Unable to find ' + section_first_line
-        return False
-    first_index = file_lines.index(section_first_line)
-    sources_index = -1
-    i = first_index
-    index = i
-    while i < len(file_lines) and file_lines[i] != '}':
-        if file_lines[i].rstrip() == dependency_line:
-            # Return False if dependency already found.
-            return False
-        if 'sources = [' in file_lines[i]:
-            # Jump to the end of the 'sources' list.
-            while i < len(file_lines) and not ']' in file_lines[i]:
-                i += 1
-            sources_index = i
-        if (file_lines[i][:file_lines[i].find('[')] == '  {} = '.format(
-                list_name)):
-            index = i
-        i += 1
-    if index == first_index:
-        # Add dependency line, after sources if possible.
-        if sources_index > 0:
-            index = sources_index + 1
-        else:
-            index = first_index + 1
-        # Adding a ',' at the beginning to make `dedent` understand what the
-        # correct indentation is.
-        new_lines = '''\
-        ,
-          {} = [
-          ]'''.format(list_name)
-        file_lines[index:index] = dedent(new_lines).split('\n')[1:]
-    elif file_lines[index].endswith(']'):
-        # If one-line dependency is found, reformat.
-        existing_dependency = file_lines[index].split(' ')[-2]
-        file_lines[index] = '  {} = ['.format(list_name)
-        # Adding a ',' at the beginning to make `dedent` understand what the
-        # correct indentation is.
-        new_lines = '''\
-        ,
-            {},
-          ]'''.format(existing_dependency)
-        file_lines[index + 1:index + 1] = dedent(new_lines).split('\n')[1:]
-
-        # Check for already imported dependency after reformatting.
-        if file_lines[index + 1].rstrip() == dependency_line:
-            return False
-
-    # Insert dependency.
-    file_lines.insert(index + 1, dependency_line)
-    return True
-
-
-def update_build_gn_dependencies(dir_path, file_name, build_gn_path):
-    print 'Updating BUILD.gn'
-
-    # Get file contents.
-    file_lines = get_file_lines(build_gn_path)
-
-    # Edit file with modules-related targets.
-    import_gni = 'import("//ui/webui/resources/tools/js_modulizer.gni")'
-    if not import_gni in file_lines:
-        index = get_end_of_build_imports(file_lines) + 1
-        new_line = 'import("//ui/webui/resources/tools/js_modulizer.gni")'
-        file_lines.insert(index, new_line)
-        new_lines = '''
-        js_modulizer("modulize") {
-          input_files = [
-          ]
-        }
-        '''
-        file_lines.extend(dedent(new_lines).split('\n'))
-        if not add_dependency(file_lines, 'group("closure_compile") {', 'deps',
-                              '    ":closure_compile_jsmodules",'):
-            return
-
-        # Add closure_compile_jsmodules rule.
-        index = get_index_substr(file_lines,
-                                 'js_type_check("closure_compile_module") {')
-        if index < 0:
-            print 'js_type_check("closure_compile_module") not found'
-            return
-        new_lines = '''js_type_check("closure_compile_jsmodules") {
-          uses_js_modules = true
-          deps = [
-          ]
-        }
-        '''
-        file_lines[index:index] = dedent(new_lines).split('\n')
-    if not add_js_library(file_lines, file_name, dir_path):
-        return
-
-    # Add closure dependency.
-    if not add_dependency(
-            file_lines, 'js_type_check("closure_compile_jsmodules") {', 'deps',
-            '    ":{}.m",'.format(file_name)):
-        return
-
-    # Add 'modulize' dependency.
-    if not add_dependency(file_lines, 'js_modulizer("modulize") {',
-                          'input_files', '    "{}.js",'.format(file_name)):
-        return
-
-    # Save file contents.
-    save_file_lines(build_gn_path, file_lines)
-
-
-def convert_unittest(build_gn_path, js_file_path, file_name):
-    '''
-    Parameters:
-        build_gn_path: Path of BUILD.gn file used by the file be converted.
-        js_file_path: Path of the file to be converted
-                        (ui/file_manager/.../..._unittest.m.js)
-        file_name: Name of the file to be converted (..._unittest)
-    '''
-    print 'Converting ' + file_name
-    main_build_path = 'ui/file_manager/BUILD.gn'
-    file_manager_jstest_path = ('chrome/browser/chromeos/file_manager/'
-                                'file_manager_jstest.cc')
-
-    # Get file contents.
-    build_file_lines = get_file_lines(build_gn_path)
-    main_build_file_lines = get_file_lines(main_build_path)
-    file_manager_jstest_lines = get_file_lines(file_manager_jstest_path)
-
-    # Rename _unittest.js to _unittest.m.js.
-    original_js_file_path = js_file_path.replace('.m.js', '.js')
-    if not os.path.isfile(js_file_path):
-        if not os.path.isfile(original_js_file_path):
-            e = 'Could not find neither file {} or {}'.format(
-                js_file_path, original_js_file_path)
-            raise ValueError(e)
-        os.rename(original_js_file_path, js_file_path)
-
-    # Update chrome/browser/chromeos/file_manager/file_manager_jstest.cc
-    # by updating RunTestURL for the unittest being converted.
-    # [...]_unittest_gen.html -> [...]_unittest.m_gen.html.
-    index = get_index_substr(file_manager_jstest_lines, file_name + '.m')
-    if index < 0:
-        index = get_index_substr(file_manager_jstest_lines, file_name)
-        if index < 0:
-            print 'file_manager_jstest.cc: {} not found'.format(file_name)
-        file_manager_jstest_lines[index] = file_manager_jstest_lines[
-            index].replace(file_name, file_name + '.m')
-
-    # Add "js_test_gen_html_modules" target.
-    build_rule = 'js_test_gen_html("js_test_gen_html_modules") {'
-    if not build_rule in build_file_lines:
-        if 'js_test_gen_html("js_test_gen_html") {' in build_file_lines:
-            index = build_file_lines.index(
-                'js_test_gen_html("js_test_gen_html") {')
-            new_lines = '''js_test_gen_html("js_test_gen_html_modules") {
-              deps = [
-              ]
-              js_module = true
-
-              closure_flags =
-                  strict_error_checking_closure_args + [
-                    "js_module_root=./gen/ui",
-                    "js_module_root=../../ui",
-                    "browser_resolver_prefix_replacements=%s",
-                  ]
-            }
-            ''' % ('\\"chrome://test/=./\\"')
-            build_file_lines[index:index] = dedent(new_lines).split('\n')
-        else:
-            e = '"js_test_gen_html" build target not found on {}'.format(
-                build_gn_path)
-            raise ValueError(e)
-
-    # Add ":js_test_gen_html_modules_type_check_auto", in closure_compile deps.
-    index = get_index_substr(build_file_lines,
-                             ':js_test_gen_html_modules_type_check_auto')
-    if index < 0:
-        index = get_index_substr(build_file_lines,
-                                 ':js_test_gen_html_type_check_auto')
-        if index < 0:
-            e = '"js_test_gen_html_type_check_auto" dependency not found'
-            raise ValueError(e)
-        else:
-            new_line = '    ":js_test_gen_html_modules_type_check_auto",'
-            build_file_lines.insert(index, new_line)
-
-    # In BUILD.gn, update js_unittest target to .m
-    if 'js_unittest("{}") {{'.format(file_name) in build_file_lines:
-        index = build_file_lines.index(
-            'js_unittest("{}") {{'.format(file_name))
-        build_file_lines[index] = 'js_unittest("{}.m") {{'.format(file_name)
-        # Remove dependencies.
-        while index < len(
-                build_file_lines) and not 'deps =' in build_file_lines[index]:
-            index += 1
-        if ']' in build_file_lines[index]:
-            build_file_lines[index] = '  deps = ['
-            build_file_lines.insert(index, '  ]')
-        else:
-            index += 1
-            while index < len(
-                    build_file_lines) and not ']' in build_file_lines[index]:
-                del build_file_lines[index]
-    else:
-        if not 'js_unittest("{}.m") {{'.format(file_name) in build_file_lines:
-            print 'Unable to find "{}" target'.format(file_name)
-
-    # Move unittest dependency from js_test_gen_html to
-    # js_test_gen_html_modules.
-    index = get_index_substr(build_file_lines, '":{}",'.format(file_name))
-    if index >= 0:
-        del build_file_lines[index]
-    else:
-        single_line_deps = '  deps = [ ":{}" ]'.format(file_name)
-        if single_line_deps in build_file_lines:
-            index = build_file_lines.index(single_line_deps)
-            build_file_lines[index] = '  deps = []'
-    add_dependency(build_file_lines,
-                   'js_test_gen_html("js_test_gen_html_modules") {', 'deps',
-                   '    ":{}.m",'.format(file_name))
-    # Add dependency in ui/file_manager/BUILD.gn.
-    dir_path = os.path.dirname(js_file_path)
-    rel_dir_path = '/'.join(dir_path.split('/')[2:])
-    if not '    "{}:js_test_gen_html_modules",'.format(
-            rel_dir_path) in main_build_file_lines:
-        if not add_dependency(
-                main_build_file_lines, 'group("unit_test_data") {', 'deps',
-                '    "{}:js_test_gen_html_modules",'.format(rel_dir_path)):
-            print 'unable to update ui/file_manager/BUILD.gn'
-
-    # Save file contents.
-    save_file_lines(build_gn_path, build_file_lines)
-    save_file_lines(main_build_path, main_build_file_lines)
-    save_file_lines(file_manager_jstest_path, file_manager_jstest_lines)
-
-
-def parse_compiler_output(compiler_output, build_gn_path, file_name):
-    '''Parse closure compile output and return list of token that are
-    undefined/undeclared (no duplicate).'''
-    print "Parsing closure compiler output"
-    f = open(compiler_output, "r")
-    # Retrieve from the closure compile output the types that need to be
-    # imported.
-    variables_to_import = []
-    for line in f:
-        # Select from the output the lines that contain 'ERROR - []' and
-        # 'Unknown type '.
-        if 'ERROR - [' in line:
-            if not file_name in line:
-                print 'UNHANDLED ERROR (Error in other file): ' + line.rstrip()
-            elif 'Unknown type ' in line:
-                unknown_type = line.rstrip().split('Unknown type ')[1]
-                # Select the main type by removing what follows the dot:
-                # ThumbnailLoader.LoaderType -> ThumbnailLoader.
-                unknown_type = unknown_type.split('.')[0]
-                if not unknown_type in variables_to_import:
-                    variables_to_import.append(unknown_type)
-            elif 'variable ' in line and ' is undeclared' in line:
-                if ' cr ' in line:  # namespace rewrite.
-                    add_namespace_rewrite(build_gn_path)
-                    continue
-                unknown_type = line.split('variable ')[1]
-                unknown_type = unknown_type.split(' is undeclared')[0]
-                if not unknown_type in variables_to_import:
-                    variables_to_import.append(unknown_type)
-            else:
-                print 'UNHANDLED ERROR: ' + line.rstrip()
-    f.close()
-    return variables_to_import
-
-
-def find_dependencies(dir_path, build_gn_path, js_file_path,
-                      variables_to_import, is_unittest):
-    '''Finds dependencies and updates BUILD.gn and JS file to import these
-    dependencies.'''
-    # Get BUILD.gn and JS file contents.
-    build_file_lines = get_file_lines(build_gn_path)
-    js_file_lines = get_file_lines(js_file_path)
-
-    file_name = js_file_path.split('/').pop().replace('.js', '')
-
-    # Special case: classes that extend "cr.EventTarget".
-    index = get_index_substr(js_file_lines, ' extends cr.EventTarget')
-    if index >= 0:
-        if is_unittest:
-            js_file_lines[index] = js_file_lines[index].replace(
-                ' extends cr.EventTarget', ' extends EventTarget')
-            add_dependency(build_file_lines,
-                           'js_unittest("{}") {{'.format(file_name), 'deps',
-                           '    "//ui/webui/resources/js/cr:event_target.m",')
-        else:
-            add_dependency(build_file_lines,
-                           'js_library("{}.m") {{'.format(file_name), 'deps',
-                           '    "//ui/webui/resources/js/cr:event_target.m",')
-        add_import_line(js_file_lines, 'NativeEventTarget as EventTarget',
-                        'chrome://resources/js/cr/event_target.m.js',
-                        is_unittest, False)
-
-    # General case.
-    for variable in variables_to_import:
-        # First, handle special cases.
-        if is_unittest:
-            # "//chrome/test/data/webui:chai_assert".
-            out, _ = subprocess.Popen([
-                'egrep', '-R', 'export function {}\('.format(variable), '-l',
-                './chrome/test/data/webui/chai_assert.js'
-            ],
-                                      stdout=subprocess.PIPE).communicate()
-            if out.rstrip() != '':
-                add_dependency(build_file_lines,
-                               'js_unittest("{}") {{'.format(file_name),
-                               'deps',
-                               '    "//chrome/test/data/webui:chai_assert",')
-                add_import_line(js_file_lines, variable,
-                                'chrome://test/chai_assert.js', is_unittest,
-                                False)
-                continue
-        else:
-            # "//ui/webui/resources/js".
-            out, _ = subprocess.Popen([
-                'egrep', '-R', '\/\* #export \*\/ \w+ {}\W'.format(variable),
-                '-l', './ui/webui/resources/js'
-            ],
-                                      stdout=subprocess.PIPE).communicate()
-            path = out.rstrip()
-            if path != '':
-                path = path.replace('./', '//').replace('.js', '.m')
-                dependency = ':'.join(path.rsplit(
-                    '/', 1))  # //ui/webui/resources/js:assert.m.
-                add_dependency(build_file_lines,
-                               'js_library("{}.m") {{'.format(file_name),
-                               'deps', '    "{}",'.format(dependency))
-                path = path.replace('//ui/webui/', 'chrome://').replace(
-                    '.m', '.m.js')  # chrome://resources/js/assert.m.js.
-                add_import_line(js_file_lines, variable, path, is_unittest,
-                                False)
-                continue
-
-        # Look for exported variables.
-        is_wrapped = False
-        out, _ = subprocess.Popen([
-            'egrep', '-R', '\/\* #export \*\/ \w+ {}\W'.format(variable), '-l',
-            './ui/file_manager/'
-        ],
-                                  stdout=subprocess.PIPE).communicate()
-        path = out.rstrip()
-        if path == '':
-            # Look for variables exported as wrapped objects
-            out, _ = subprocess.Popen([
-                'egrep', '-R',
-                '\/\* #export \*\/ \{%s\}' % variable, '-l',
-                './ui/file_manager/'
-            ],
-                                      stdout=subprocess.PIPE).communicate()
-            path = out.rstrip()
-            if path == '':
-                continue
-            is_wrapped = True
-        if '\n' in path:
-            print '{}: export found in more than 1 file'.format(variable)
-            print path
-            continue
-
-        # Remove './' at the start.
-        path = path[2:]
-        wrapped_variable = 'wrapped' + variable[0].upper() + variable[1:]
-        relative_path = os.path.relpath(path, start=dir_path).replace(
-            '.js', '.m.js')
-        if not relative_path.startswith('../'):
-            relative_path = './' + relative_path
-        add_import_line(js_file_lines, variable, relative_path, is_unittest,
-                        is_wrapped, wrapped_variable)
-        if is_unittest:
-            add_dependency(
-                build_file_lines, 'js_unittest("{}") {{'.format(file_name),
-                'deps',
-                '    "{}",'.format(get_relative_dependency(path, dir_path)))
-        else:
-            add_dependency(
-                build_file_lines, 'js_library("{}.m") {{'.format(file_name),
-                'deps',
-                '    "{}",'.format(get_relative_dependency(path, dir_path)))
-
-    # Save BUILD.gn and JS file contents.
-    save_file_lines(build_gn_path, build_file_lines)
-    save_file_lines(js_file_path, js_file_lines)
-
-
-def add_exports(js_file_path):
-    file_lines = get_file_lines(js_file_path)
-    for i, line in enumerate(file_lines):
-        # Export class.
-        if line.startswith('class '):
-            # Extract class name.
-            class_name = line.split(' ')[1]
-            # Make sure this class is not used locally.
-            if get_index_substr(file_lines, 'new ' + class_name) >= 0:
-                # Export only if the class name is the name of the file.
-                snake_case_name = ''.join([
-                    '_' + c.lower() if c.isupper() else c for c in class_name
-                ]).lstrip('_')
-                if not snake_case_name + '.js' == js_file_path.split('/')[-1]:
-                    continue
-            file_lines[i] = '/* #export */ ' + line
-        # Export variable in global namespace.
-        elif line.startswith('const ') or line.startswith(
-                'let ') or line.startswith('var '):
-            # Extract variable name.
-            variable_name = line.split(' ')[1]
-
-            # Check if the variable is further defined/extended in the file. If
-            # so, export it.
-            export_variable = False
-            for l in range(len(file_lines)):
-                if file_lines[l].startswith(variable_name + '.'):
-                    export_variable = True
-                    break
-            if not export_variable:
-                continue
-
-            # Check if export already added.
-            if get_index_substr(file_lines, '/* #export */ {%s}' %
-                                (variable_name)) >= 0:
-                continue
-
-            # Export variable in wrapping object at the end of the file.
-            new_lines = '''
-            // eslint-disable-next-line semi,no-extra-semi
-            /* #export */ {%s};''' % (variable_name)
-            file_lines.extend(dedent(new_lines).split('\n'))
-
-            # Check if @suppress already added.
-            if get_index_substr(file_lines, ' @suppress {uselessCode}') >= 0:
-                continue
-            index = get_end_of_file_overview(file_lines)
-            if index < 0:
-                index = get_end_of_copyright(file_lines)
-                if index < 0:
-                    index = 0
-                index += 1
-                new_lines = '''
-                /**
-                 * @fileoverview
-                 * @suppress {uselessCode} Temporary suppress %s.
-                 */''' % ('because of the line exporting')
-                file_lines[index:index] = dedent(new_lines).split('\n')
-            else:
-                while ' */' not in file_lines[index]:
-                    index += 1
-                new_line = (' * @suppress {uselessCode} Temporary suppress '
-                            'because of the line exporting.')
-                file_lines.insert(index, new_line)
-        # Export function.
-        elif line.startswith('function '):
-            if not get_index_substr(file_lines, ' {}('.format(function_name)):
-                # The function has to be used outside the file, so has to be
-                # exported.
-                file_lines[i] = '/* #export */ ' + line
-
-    # Save file contents.
-    save_file_lines(js_file_path, file_lines)
-
-
-def add_exports_unittest(js_file_path):
-    file_lines = []
-    file_lines = get_file_lines(js_file_path)
-    for i, line in enumerate(file_lines):
-        if line[:16] == 'function setUp()':
-            file_lines[i] = line.replace('function setUp()',
-                                         'export function setUp()')
-        if line[:13] == 'function test':
-            file_lines[i] = line.replace('function test',
-                                         'export function test')
-
-    # Save file contents.
-    save_file_lines(js_file_path, file_lines)
-
-
-def main():
-    # Get command line arguments.
-    js_file_path = sys.argv[1]
-    action = sys.argv[2]
-    if not js_file_path.endswith('.js'):
-        e = "Argument 1 {} isn't a JS file (expected .js extension)".format(
-            js_file_path)
-        raise ValueError(e)
-    dir_path = os.path.dirname(js_file_path)
-    build_gn_path = dir_path + '/BUILD.gn'
-    file_name = os.path.basename(js_file_path).replace('.js', '')
-    is_unittest = file_name.endswith('_unittest')
-    if is_unittest:
-        js_file_path = js_file_path.replace('.js', '.m.js')
-
-    if (action == 'generate'):
-        if is_unittest:
-            convert_unittest(build_gn_path, js_file_path, file_name)
-            add_exports_unittest(js_file_path)
-        else:
-            update_build_gn_dependencies(dir_path, file_name, build_gn_path)
-            add_exports(js_file_path)
-    elif (action == 'parse'):
-        compiler_output = sys.argv[3]
-        variables_to_import = parse_compiler_output(compiler_output,
-                                                    build_gn_path, file_name)
-        if variables_to_import == []:
-            return
-        find_dependencies(dir_path, build_gn_path, js_file_path,
-                          variables_to_import, is_unittest)
-
-
-print "-----modules.py-----"
-main()
-print "--------------------"
diff --git a/ui/file_manager/base/tools/modules.sh b/ui/file_manager/base/tools/modules.sh
deleted file mode 100755
index 68ce308..0000000
--- a/ui/file_manager/base/tools/modules.sh
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2020 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Command usage:
-# ui/file_manager/base/tools/modules.sh out/Release ui/file_manager/
-#   file_manager/foreground/js/list_thumbnail_loader.js
-# ui/file_manager/base/tools/modules.sh out/Release ui/file_manager/
-#   file_manager/common/js/importer_common.js
-# ui/file_manager/base/tools/modules.sh out/Release ui/file_manager/
-#   file_manager/foreground/js/list_thumbnail_loader_unittest.js
-
-# Input: js file to convert.
-build_dir=$1;
-file_path=$2;
-dir=`dirname $file_path`;
-compiler_output="$build_dir/gen/ui/file_manager/base/tools/compiler_output.txt";
-
-# Create containing directory of `compiler_output` if doesn't exist.
-mkdir -p `dirname $compiler_output`;
-
-# Process files with Python.
-ui/file_manager/base/tools/modules.py $file_path 'generate';
-
-# Parse closure compiler output and update files until the message 'X error(s),
-# Y warning(s), Z% typed' doesn't change.
-prev_output=""
-new_output="."
-while [[ $prev_output != $new_output ]]; do
-  prev_output=$new_output;
-
-  # Run closure compiler and save output.
-  ninja -C $build_dir $dir:closure_compile 2>&1 | tee $compiler_output;
-
-  # Parse closure compiler output.
-  ui/file_manager/base/tools/modules.py $file_path 'parse' $compiler_output;
-
-  # Get number of errors from modules.txt.
-  new_output=$(cat $compiler_output | grep 'error(s)' );
-done;
-
-# Format files.
-git cl format --js;
-
-if [[ $new_output == "" ]]; then
-  echo "No closure compiler error found"
-else
-  echo "Final state: " $new_output;
-fi;
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js
index 42dc085..a8ad1ba 100644
--- a/ui/file_manager/file_manager/common/js/util.js
+++ b/ui/file_manager/file_manager/common/js/util.js
@@ -1427,7 +1427,7 @@
  * @return {boolean}
  */
 util.isFilesNg = () => {
-  return loadTimeData.getBoolean('FILES_NG_ENABLED');
+  return true;
 };
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/elements/files_message_unittest.js b/ui/file_manager/file_manager/foreground/elements/files_message_unittest.js
index 8e1e01fa..0c05347 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_message_unittest.js
+++ b/ui/file_manager/file_manager/foreground/elements/files_message_unittest.js
@@ -3,6 +3,18 @@
 // found in the LICENSE file.
 
 /**
+ * TODO(lucmult): Remove this when converting to JS modules.
+ * @suppress {checkTypes}
+ */
+chrome.fileManagerPrivate = {
+  FormatFileSystemType: {
+    VFAT: 'vfat',
+    EXFAT: 'exfat',
+    NTFS: 'ntfs',
+  },
+};
+
+/**
  * Adds a FilesMessage element to the page, initially hidden.
  */
 function setUpPage() {
@@ -17,7 +29,7 @@
 function setFilesMessageContent() {
   // Get the FilesMessage element.
   /** @type {!FilesMessage|!Element} */
-  let message = assert(document.querySelector('#test-files-message'));
+  const message = assert(document.querySelector('#test-files-message'));
 
   // Use the FilesMessage.setContent() method to assign all its settable
   // properties in one go.
diff --git a/ui/file_manager/file_manager/foreground/elements/files_password_dialog_unittest.js b/ui/file_manager/file_manager/foreground/elements/files_password_dialog_unittest.js
index a058190..6096d86 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_password_dialog_unittest.js
+++ b/ui/file_manager/file_manager/foreground/elements/files_password_dialog_unittest.js
@@ -16,6 +16,18 @@
 let unlock;
 
 /**
+ * TODO(lucmult): Remove this when converting to JS modules.
+ * @suppress {checkTypes}
+ */
+chrome.fileManagerPrivate = {
+  FormatFileSystemType: {
+    VFAT: 'vfat',
+    EXFAT: 'exfat',
+    NTFS: 'ntfs',
+  },
+};
+
+/**
  * Mock LoadTimeData strings.
  */
 function setUpPage() {
diff --git a/ui/file_manager/file_manager/foreground/elements/files_tooltip.js b/ui/file_manager/file_manager/foreground/elements/files_tooltip.js
index ec23eb1..a3716dbe 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_tooltip.js
+++ b/ui/file_manager/file_manager/foreground/elements/files_tooltip.js
@@ -102,6 +102,9 @@
    * is not dispatched. This method is used to handle these cases manually.
    */
   hideTooltip: function() {
+    if (this.showTooltipTimerId_) {
+      clearTimeout(this.showTooltipTimerId_);
+    }
     if (this.visibleTooltipTarget_) {
       this.initHidingTooltip_(this.visibleTooltipTarget_);
     }
diff --git a/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js b/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js
index 3c50965..2e605bce 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js
+++ b/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js
@@ -2,6 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+/**
+ * TODO(lucmult): Remove this when converting to JS modules.
+ * @suppress {checkTypes, constantProperty}
+ */
+chrome.fileManagerPrivate = {
+  FormatFileSystemType: {
+    VFAT: 'vfat',
+    EXFAT: 'exfat',
+    NTFS: 'ntfs',
+  },
+};
+
 /** @type {!DisplayPanel|!Element} */
 let displayPanel;
 
@@ -496,4 +508,4 @@
   assertEquals('expanded', summaryPanelItem.getAttribute('data-category'));
 
   done();
-}
\ No newline at end of file
+}
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index 5bc96c1..6da97f62 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -787,13 +787,8 @@
     metrics.recordInterval('Load.InitDocuments');
 
     metrics.startInterval('Load.InitUI');
-    if (util.isFilesNg()) {
-      this.document_.documentElement.classList.add('files-ng');
-      this.dialogDom_.classList.add('files-ng');
-    } else {
-      this.document_.documentElement.classList.remove('files-ng');
-      this.dialogDom_.classList.remove('files-ng');
-    }
+    this.document_.documentElement.classList.add('files-ng');
+    this.dialogDom_.classList.add('files-ng');
 
     this.dialogDom_.classList.toggle(
         'camera-folder-enabled', util.isFilesCameraFolderEnabled());
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index bf048d42..e152ca08 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -1129,10 +1129,15 @@
       dialog.showModalElement();
     }
 
-    dialog.show(message, () => {
+    const deleteCallback = () => {
       dialog.doneCallback && dialog.doneCallback();
+      document.querySelector('files-tooltip').hideTooltip();
+    };
+
+    dialog.show(message, () => {
+      deleteCallback();
       fileManager.fileOperationManager.deleteEntries(entries);
-    }, dialog.doneCallback, null);
+    }, deleteCallback, null);
   }
 
   /**
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller_unittest.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller_unittest.js
index 53c3e9d..54d07e5 100644
--- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller_unittest.js
@@ -36,6 +36,7 @@
     '  <div tabindex="0" id="directory-tree">',
     '  </div>',
     '  <div id="list-container">',
+    '    <files-spinner class="loading-indicator" hidden></files-spinner>',
     '    <div id="detail-table">',
     '      <list id="file-list" contextmenu="#file-context-menu" tabindex="0">',
     '      </list>',
@@ -49,7 +50,7 @@
     '  </div>',
     '  <div id="test-elements">',
     '    <input type="text" id="free-text">',
-    '    <cr-input id="test-input" tabindex="0">',
+    '    <cr-input id="test-input" tabindex="0"></cr-input>',
     '    <input type="button" id="button">',
     '</div>',
   ].join('');
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table.js b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
index 503de4e..4923a3af 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
@@ -14,10 +14,6 @@
 
     /** @private {?FileTableColumnModel.ColumnSnapshot} */
     this.snapshot_ = null;
-
-    if (util.isFilesNg()) {
-      FileTableColumnModel.MIN_WIDTH_ = 40;
-    }
   }
 
   /**
@@ -296,10 +292,9 @@
 /**
  * Minimum width of column. Note that is not marked private as it is used in the
  * unit tests.
- * TODO(lucmult): Revert back to const once FilesNg flag is removed.
- * @type {number}
+ * @const {number}
  */
-FileTableColumnModel.MIN_WIDTH_ = 10;
+FileTableColumnModel.MIN_WIDTH_ = 40;
 
 /**
  * A helper class for performing resizing of columns.
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table_unittest.js b/ui/file_manager/file_manager/foreground/js/ui/file_table_unittest.js
index da86a99..9cfe90f 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table_unittest.js
@@ -188,14 +188,32 @@
 }
 
 function testNormalizeWidth() {
-  const newContentWidth = 150;
-  const expectedWidths = [10, 20, 30, 40, 50];
+  let newContentWidth = 0;
+  const initialWidths = [
+    10 * 17,
+    20 * 17,
+    30 * 17,
+    40 * 17,
+    50 * 17,
+  ];
+  // The rounding technique used in the implementation doesn't match floor() or
+  // ceil(), it diverges by +/- 1. So hard coding here.
+  const expectedWidths = [
+    56,   // ~(17 * 10 / 3)
+    114,  // ~(17 * 20 / 3)
+    170,  // ~(17 * 30 / 3)
+    226,  // ~(17 * 40 / 3)
+    284,  // ~(17 * 50 / 3)
+  ];
 
   for (let i = 0; i < model.size; i++) {
-    model.setWidth(i, expectedWidths[i] * 17);
+    const colWidth = initialWidths[i];
+    model.setWidth(i, colWidth);
+    newContentWidth += colWidth;
   }
 
-  // Resizes columns proportionally
+  // Reduce total with to 1/3 to Resizes columns proportionally.
+  newContentWidth = newContentWidth / 3;
   model.normalizeWidths(newContentWidth);
 
   assertArrayEquals(expectedWidths, getColumnWidths(model));
diff --git a/ui/file_manager/gallery/js/slide_mode_unittest.js b/ui/file_manager/gallery/js/slide_mode_unittest.js
index 2626c0f..2dc1acd 100644
--- a/ui/file_manager/gallery/js/slide_mode_unittest.js
+++ b/ui/file_manager/gallery/js/slide_mode_unittest.js
@@ -3,6 +3,17 @@
 // found in the LICENSE file.
 
 /**
+ * @suppress {checkTypes, constantProperty}
+ */
+chrome.fileManagerPrivate = {
+  FormatFileSystemType: {
+    VFAT: 'vfat',
+    EXFAT: 'exfat',
+    NTFS: 'ntfs',
+  },
+};
+
+/**
  * Mock implementation of strf function.
  */
 function strf(id, var_args) {
diff --git a/ui/file_manager/integration_tests/file_manager/breadcrumbs.js b/ui/file_manager/integration_tests/file_manager/breadcrumbs.js
index 3f49a9d..7c1d9d1 100644
--- a/ui/file_manager/integration_tests/file_manager/breadcrumbs.js
+++ b/ui/file_manager/integration_tests/file_manager/breadcrumbs.js
@@ -18,7 +18,7 @@
 
     // Use the breadcrumbs to navigate back to Downloads.
     await remoteCall.waitAndClickElement(
-        appId, '#location-breadcrumbs .breadcrumb-path:nth-of-type(2)');
+        appId, ['bread-crumb', 'button:nth-last-of-type(2)']);
 
     // Wait for the contents of Downloads to load again.
     await remoteCall.waitForFiles(appId, TestEntryInfo.getExpectedRows(files));
@@ -29,33 +29,6 @@
   };
 
   /**
-   * Test that clicking on the current directory in the Breadcrumbs doesn't
-   * leave the focus in the breadcrumbs. crbug.com/944022
-   */
-  testcase.breadcrumbsLeafNoFocus = async () => {
-    const appId =
-        await setupAndWaitUntilReady(RootPath.DOWNLOADS, [ENTRIES.photos], []);
-
-    // Navigate to Downloads/photos.
-    await remoteCall.navigateWithDirectoryTree(
-        appId, '/Downloads/photos', 'My files');
-
-    // Focus and click on "photos" in the breadcrumbs.
-    const leafBreadCrumb =
-        '#location-breadcrumbs .breadcrumb-path.breadcrumb-last';
-    chrome.test.assertTrue(
-        !!await remoteCall.callRemoteTestUtil('focus', appId, [leafBreadCrumb]),
-        'focus failed: ' + leafBreadCrumb);
-    await remoteCall.waitAndClickElement(appId, leafBreadCrumb);
-
-    // Wait focus to not be on breadcrumb clicked.
-    await remoteCall.waitForElementLost(appId, leafBreadCrumb + ':focus');
-
-    // Focus should be on file list.
-    await remoteCall.waitForElement(appId, '#file-list:focus');
-  };
-
-  /**
    * Tests that Downloads is translated in the breadcrumbs.
    */
   testcase.breadcrumbsDownloadsTranslation = async () => {
@@ -130,44 +103,6 @@
   }
 
   /**
-   * Tests that breadcrumbs has to tooltip. crbug.com/951305
-   */
-  testcase.breadcrumbsTooltip = async () => {
-    // Build an array of nested folder test entries.
-    const nestedFolderTestEntries = createNestedTestFolders(8);
-
-    // Open FilesApp on Downloads containing the test entries.
-    const appId = await setupAndWaitUntilReady(
-        RootPath.DOWNLOADS, nestedFolderTestEntries, []);
-
-    // Navigate to deepest folder.
-    const breadcrumb = '/My files/Downloads/' +
-        nestedFolderTestEntries.map(e => e.nameText).join('/');
-    await navigateWithDirectoryTree(appId, breadcrumb);
-
-    // Get breadcrumb that is "collapsed" in the default window size.
-    const collapsedBreadcrumb =
-        await remoteCall.waitForElement(appId, '#breadcrumb-path-8');
-
-    // Check: Should have aria-label so screenreader announces the folder name.
-    chrome.test.assertEq(
-        'nested-folder6', collapsedBreadcrumb.attributes['aria-label']);
-    // Check: Should have collapsed attribute so it shows as "...".
-    chrome.test.assertEq('', collapsedBreadcrumb.attributes['collapsed']);
-
-    // Focus the search box.
-    chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
-        'fakeEvent', appId, ['#breadcrumb-path-8', 'focus']));
-
-    // Check: The tooltip should be visible and its content is the folder name.
-    const tooltipQueryVisible = 'files-tooltip[visible=true]';
-    const tooltip = await remoteCall.waitForElement(appId, tooltipQueryVisible);
-    const label =
-        await remoteCall.waitForElement(appId, [tooltipQueryVisible, '#label']);
-    chrome.test.assertEq('nested-folder6', label.text);
-  };
-
-  /**
    * Tests that the breadcrumbs correctly render a short (3 component) path.
    */
   testcase.breadcrumbsRenderShortPath = async () => {
diff --git a/ui/file_manager/integration_tests/file_manager/files_tooltip.js b/ui/file_manager/integration_tests/file_manager/files_tooltip.js
index 5e93ebc3..2cfbbf1 100644
--- a/ui/file_manager/integration_tests/file_manager/files_tooltip.js
+++ b/ui/file_manager/integration_tests/file_manager/files_tooltip.js
@@ -13,6 +13,9 @@
       '#read-only-indicator[has-tooltip][show-card-tooltip]';
   const fileList = '#file-list';
   const cancelButton = '#cancel-selection-button[has-tooltip]';
+  const deleteButton = '#delete-button[has-tooltip]';
+
+  const tooltipShowTimeout = 500;  // ms
 
   /**
    * $i18n{} labels used when template replacement is disabled.
@@ -259,4 +262,58 @@
     // The tooltip should be hidden.
     await remoteCall.waitForElement(appId, tooltipQueryHidden);
   };
+
+  /**
+   * Tests that the tooltip is hidden after the 'Delete' confirmation dialog is
+   * closed.
+   */
+  testcase.filesTooltipHidesOnDeleteDialogClosed = async () => {
+    const appId = await setupAndWaitUntilReady(
+        RootPath.DOWNLOADS, [ENTRIES.beautiful, ENTRIES.photos], []);
+
+    const fileListItemQuery = '#file-list li[file-name="Beautiful Song.ogg"]';
+    const okButtonQuery = '.cr-dialog-ok';
+    const cancelButtonQuery = '.cr-dialog-cancel';
+
+    // The tooltip should be hidden.
+    await remoteCall.waitForElement(appId, tooltipQueryHidden);
+
+    // Select file.
+    await remoteCall.waitAndClickElement(appId, [fileListItemQuery]);
+
+    // Focus delete button.
+    chrome.test.assertTrue(
+        await remoteCall.callRemoteTestUtil('focus', appId, [deleteButton]));
+
+    // Click delete button.
+    await remoteCall.waitAndClickElement(appId, [deleteButton]);
+
+    // Cancel deletion by clicking 'Cancel'.
+    await remoteCall.waitAndClickElement(appId, [cancelButtonQuery]);
+
+    // Leave time for tooltip to show.
+    await wait(tooltipShowTimeout);
+
+    // The tooltip should still be hidden.
+    await remoteCall.waitForElement(appId, tooltipQueryHidden);
+
+    // Select file.
+    await remoteCall.waitAndClickElement(appId, [fileListItemQuery]);
+
+    // Focus delete button.
+    chrome.test.assertTrue(
+        await remoteCall.callRemoteTestUtil('focus', appId, [deleteButton]));
+
+    // Click the delete button.
+    await remoteCall.waitAndClickElement(appId, [deleteButton]);
+
+    // Confirm deletion by clicking 'Delete'.
+    await remoteCall.waitAndClickElement(appId, [okButtonQuery]);
+
+    // Leave time for tooltip to show.
+    await wait(tooltipShowTimeout);
+
+    // The tooltip should be hidden.
+    await remoteCall.waitForElement(appId, tooltipQueryHidden);
+  };
 })();
diff --git a/ui/file_manager/integration_tests/file_manager/my_files.js b/ui/file_manager/integration_tests/file_manager/my_files.js
index 4f76ff6..8d0f4f5 100644
--- a/ui/file_manager/integration_tests/file_manager/my_files.js
+++ b/ui/file_manager/integration_tests/file_manager/my_files.js
@@ -62,15 +62,12 @@
   // Select Downloads folder.
   await remoteCall.callRemoteTestUtil('selectVolume', appId, ['downloads']);
 
-  // Get the breadcrumbs elements.
-  const breadcrumbsQuery = ['#location-breadcrumbs .breadcrumb-path'];
-  const breadcrumbs = await remoteCall.callRemoteTestUtil(
-      'queryAllElements', appId, breadcrumbsQuery);
+  // Get the breadcrumbs element.
+  const breadcrumbs = await remoteCall.waitForElement(appId, ['bread-crumb']);
 
   // Check that My Files is displayed on breadcrumbs.
-  const expectedBreadcrumbs = 'My files > Downloads';
-  const resultBreadscrubms = breadcrumbs.map(crumb => crumb.text).join(' > ');
-  chrome.test.assertEq(expectedBreadcrumbs, resultBreadscrubms);
+  const expectedBreadcrumbs = 'My files/Downloads';
+  chrome.test.assertEq(expectedBreadcrumbs, breadcrumbs['attributes']['path']);
 };
 
 /**
diff --git a/ui/file_manager/integration_tests/file_manager/tab_index.js b/ui/file_manager/integration_tests/file_manager/tab_index.js
index f2eb3ac..8a3646b9 100644
--- a/ui/file_manager/integration_tests/file_manager/tab_index.js
+++ b/ui/file_manager/integration_tests/file_manager/tab_index.js
@@ -46,43 +46,24 @@
   chrome.test.assertEq('list', element.attributes['class']);
 
   // Send Tab key events to cycle through the tabable elements.
-  if (await isFilesNg(appId)) {
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'directory-tree'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'search-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'view-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'sort-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'gear-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'welcome-dismiss'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'drive-welcome-link'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'offline-learn-more'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'file-list'));
-  } else {
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'search-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'view-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'sort-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'gear-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'directory-tree'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'welcome-dismiss'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'drive-welcome-link'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'file-list'));
-  }
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'directory-tree'));
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'search-button'));
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'view-button'));
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'sort-button'));
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'gear-button'));
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'drive-welcome-link'));
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'welcome-dismiss'));
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'offline-learn-more'));
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'file-list'));
 };
 
 /**
@@ -100,62 +81,20 @@
   chrome.test.assertEq('list', element.attributes['class']);
 
   // Send Tab key events to cycle through the tabable elements.
-  if (await isFilesNg(appId)) {
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'directory-tree'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'breadcrumbs'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'search-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'view-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'sort-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'gear-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'file-list'));
-  } else {
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'breadcrumb-path-0'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'search-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'view-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'sort-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'gear-button'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'directory-tree'));
-    chrome.test.assertTrue(
-        await remoteCall.checkNextTabFocus(appId, 'file-list'));
-  }
-};
-
-/**
- * Tests for background color change when breadcrumb has focus.
- */
-testcase.tabindexFocusBreadcrumbBackground = async () => {
-  // Open Files app on Downloads.
-  const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
-
-  // Get background color for breadcrumb with no focus.
-  const unfocused = await remoteCall.waitForElementStyles(
-      appId, '#breadcrumb-path-0', ['background-color']);
-
-  // Press the tab key.
-  const result = await sendTestMessage({name: 'dispatchTabKey'});
-  chrome.test.assertEq(result, 'tabKeyDispatched', 'Tab key dispatch failure');
-
-  // Get background color for breadcrumb with focus.
-  const focused = await remoteCall.waitForElementStyles(
-      appId, '#breadcrumb-path-0:focus', ['background-color']);
-
-  // Check that background colour has changed.
-  chrome.test.assertFalse(
-      focused.styles['background-color'] ===
-      unfocused.styles['background-color']);
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'directory-tree'));
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'breadcrumbs'));
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'search-button'));
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'view-button'));
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'sort-button'));
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'gear-button'));
+  chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'file-list'));
 };
 
 /**
@@ -366,7 +305,7 @@
 /**
  * Tests the tab focus behavior of Open Dialog (Downloads).
  */
-testcase.tabindexOpenDialogDownloadsFilesNg = async () => {
+testcase.tabindexOpenDialogDownloads = async () => {
   return tabindexFocus(
       {type: 'openFile'}, 'downloads', BASIC_LOCAL_ENTRY_SET,
       async (appId) => {
@@ -379,21 +318,6 @@
       ]);
 };
 
-/**
- * Tests the tab focus behavior of Open Dialog (Downloads).
- */
-testcase.tabindexOpenDialogDownloads = async () => {
-  return tabindexFocus(
-      {type: 'openFile'}, 'downloads', BASIC_LOCAL_ENTRY_SET,
-      async (appId) => {
-        await remoteCall.callRemoteTestUtil('selectFile', appId, ['hello.txt']);
-      },
-      ['#ok-button:not([disabled])'], [
-        'cancel-button', 'ok-button', 'breadcrumb-path-0', 'search-button',
-        'view-button', 'sort-button', 'gear-button', 'directory-tree',
-        'file-list'
-      ]);
-};
 
 /**
  * Tests the tab focus behavior of Open Dialog (Drive).
@@ -413,7 +337,7 @@
 /**
  * Tests the tab focus behavior of Save File Dialog (Downloads).
  */
-testcase.tabindexSaveFileDialogDownloadsFilesNg = async () => {
+testcase.tabindexSaveFileDialogDownloads = async () => {
   return tabindexFocus(
       {
         type: 'saveFile',
@@ -428,38 +352,6 @@
       ]);
 };
 
-/**
- * Tests the tab focus behavior of Save File Dialog (Downloads).
- */
-testcase.tabindexSaveFileDialogDownloads = async () => {
-  return tabindexFocus(
-      {
-        type: 'saveFile',
-        suggestedName: 'hoge.txt'  // Prevent showing a override prompt
-      },
-      'downloads', BASIC_LOCAL_ENTRY_SET, null, ['#ok-button:not([disabled])'],
-      [
-        'cancel-button', 'ok-button', 'breadcrumb-path-0', 'search-button',
-        'view-button', 'sort-button', 'gear-button', 'directory-tree',
-        'file-list', 'new-folder-button', 'filename-input-textbox'
-      ]);
-};
-
-/**
- * Tests the tab focus behavior of Save File Dialog (Drive).
- */
-testcase.tabindexSaveFileDialogDriveFilesNg = async () => {
-  return tabindexFocus(
-      {
-        type: 'saveFile',
-        suggestedName: 'hoge.txt'  // Prevent showing a override prompt
-      },
-      'drive', BASIC_DRIVE_ENTRY_SET, null, ['#ok-button:not([disabled])'], [
-        'cancel-button', 'ok-button', 'directory-tree', 'search-button',
-        'view-button', 'sort-button', 'gear-button', 'offline-learn-more',
-        'file-list', 'new-folder-button', 'filename-input-textbox'
-      ]);
-};
 
 /**
  * Tests the tab focus behavior of Save File Dialog (Drive).
@@ -471,8 +363,8 @@
         suggestedName: 'hoge.txt'  // Prevent showing a override prompt
       },
       'drive', BASIC_DRIVE_ENTRY_SET, null, ['#ok-button:not([disabled])'], [
-        'cancel-button', 'ok-button', 'search-button', 'view-button',
-        'sort-button', 'gear-button', 'directory-tree', 'file-list',
-        'new-folder-button', 'filename-input-textbox'
+        'cancel-button', 'ok-button', 'directory-tree', 'search-button',
+        'view-button', 'sort-button', 'gear-button', 'offline-learn-more',
+        'file-list', 'new-folder-button', 'filename-input-textbox'
       ]);
 };
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index eb945083..3b99a1d 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -512,15 +512,6 @@
   if (use_ozone) {
     deps += [ "//ui/ozone" ]
   }
-
-  public_configs = []
-
-  # If the run-time search path isn't set properly when we use ANGLE with its
-  # Vulkan backend, it may end up finding the system libvulkan.so rather than
-  # the one built in the output directory
-  if ((is_linux || is_chromeos) && !is_component_build) {
-    public_configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
-  }
 }
 
 source_set("run_all_unittests") {
diff --git a/ui/platform_window/x11/x11_window.cc b/ui/platform_window/x11/x11_window.cc
index 45e4235..61c355f 100644
--- a/ui/platform_window/x11/x11_window.cc
+++ b/ui/platform_window/x11/x11_window.cc
@@ -864,15 +864,17 @@
     suggested_operations |= DragDropTypes::DRAG_COPY;
   }
 
+  XDragDropClient* source_client =
+      XDragDropClient::GetForWindow(target_current_context->source_window());
   if (!notified_enter_) {
-    drop_handler->OnDragEnter(
-        gfx::PointF(screen_point), std::move(data), suggested_operations,
-        GetKeyModifiers(target_current_context->source_client()));
+    drop_handler->OnDragEnter(gfx::PointF(screen_point), std::move(data),
+                              suggested_operations,
+                              GetKeyModifiers(source_client));
     notified_enter_ = true;
   }
-  drag_operation_ = drop_handler->OnDragMotion(
-      gfx::PointF(screen_point), suggested_operations,
-      GetKeyModifiers(target_current_context->source_client()));
+  drag_operation_ = drop_handler->OnDragMotion(gfx::PointF(screen_point),
+                                               suggested_operations,
+                                               GetKeyModifiers(source_client));
   return drag_operation_;
 }
 
@@ -909,8 +911,8 @@
   // should have it since then.
   auto* target_current_context = drag_drop_client_->target_current_context();
   DCHECK(target_current_context);
-  drop_handler->OnDragDrop(
-      {}, GetKeyModifiers(target_current_context->source_client()));
+  drop_handler->OnDragDrop({}, GetKeyModifiers(XDragDropClient::GetForWindow(
+                                   target_current_context->source_window())));
   notified_enter_ = false;
   return drag_operation_;
 }
diff --git a/ui/views/controls/menu/menu_runner_impl_cocoa.mm b/ui/views/controls/menu/menu_runner_impl_cocoa.mm
index 08f92a2..f9deec4 100644
--- a/ui/views/controls/menu/menu_runner_impl_cocoa.mm
+++ b/ui/views/controls/menu/menu_runner_impl_cocoa.mm
@@ -26,6 +26,10 @@
 
 namespace {
 
+constexpr CGFloat kNativeCheckmarkWidth = 18;
+constexpr CGFloat kNativeMenuItemHeight = 18;
+constexpr CGFloat kIPHDotSize = 6;
+
 NSImage* NewTagImage() {
   // 1. Make the attributed string.
 
@@ -92,47 +96,116 @@
       }];
 }
 
-}  // namespace
+NSImage* IPHDotImage() {
+  // Embed horizontal centering space as NSMenuItem will otherwise left-align
+  // it.
+  return [NSImage
+       imageWithSize:NSMakeSize(2 * kIPHDotSize, kIPHDotSize)
+             flipped:NO
+      drawingHandler:^(NSRect dest_rect) {
+        NSBezierPath* dot_path = [NSBezierPath
+            bezierPathWithOvalInRect:NSMakeRect(kIPHDotSize / 2, 0, kIPHDotSize,
+                                                kIPHDotSize)];
+        NSColor* dot_color = skia::SkColorToSRGBNSColor(
+            ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor(
+                ui::NativeTheme::kColorId_ProminentButtonColor));
+        [dot_color set];
+        [dot_path fill];
 
-@interface MenuControllerDelegate : NSObject <MenuControllerCocoaDelegate>
-@end
+        return YES;
+      }];
+}
 
-@implementation MenuControllerDelegate
-
-- (void)controllerWillAddItem:(NSMenuItem*)menuItem
-                    fromModel:(ui::MenuModel*)model
-                      atIndex:(NSInteger)index {
-  static const bool feature_enabled =
-      base::FeatureList::IsEnabled(views::features::kEnableNewBadgeOnMenuItems);
-  if (!feature_enabled || !model->IsNewFeatureAt(index))
-    return;
-
-  NSTextAttachment* attachment =
-      [[[NSTextAttachment alloc] initWithData:nil ofType:nil] autorelease];
-  attachment.image = NewTagImage();
-  NSSize newTagSize = attachment.image.size;
-  attachment.bounds = NSMakeRect(0, views::NewBadge::kNewBadgeBaselineOffsetMac,
-                                 newTagSize.width, newTagSize.height);
-
-  // Starting in 10.13, if an attributed string is set as a menu item title, and
-  // NSFontAttributeName is not specified for it, it is automatically rendered
-  // in a font matching other menu items. Prior to then, a menu item with no
-  // specified font is rendered in Helvetica. In addition, while the
-  // documentation says that -[NSFont menuFontOfSize:0] gives the standard menu
-  // font, that doesn't actually match up. Therefore, specify a font that
+NSMutableAttributedString* MutableAttributedStringForMenuItemTitleString(
+    NSString* string) {
+  // Starting in 10.13, if an attributed string is set as a menu item title,
+  // and NSFontAttributeName is not specified for it, it is automatically
+  // rendered in a font matching other menu items. Prior to then, a menu item
+  // with no specified font is rendered in Helvetica. In addition, while the
+  // documentation says that -[NSFont menuFontOfSize:0] gives the standard
+  // menu font, that doesn't actually match up. Therefore, specify a font that
   // visually matches.
   NSDictionary* attrs = nil;
   if (base::mac::IsAtMostOS10_12())
     attrs = @{NSFontAttributeName : [NSFont menuFontOfSize:14]};
 
-  base::scoped_nsobject<NSMutableAttributedString> attrTitle(
-      [[NSMutableAttributedString alloc] initWithString:menuItem.title
-                                             attributes:attrs]);
-  [attrTitle
-      appendAttributedString:[NSAttributedString
-                                 attributedStringWithAttachment:attachment]];
+  return [[[NSMutableAttributedString alloc] initWithString:string
+                                                 attributes:attrs] autorelease];
+}
 
-  menuItem.attributedTitle = attrTitle;
+}  // namespace
+
+// --- Private API begin ---
+
+@interface NSCarbonMenuImpl : NSObject
+- (void)highlightItemAtIndex:(NSInteger)index;
+@end
+
+@interface NSMenu ()
+- (NSCarbonMenuImpl*)_menuImpl;
+@end
+
+// --- Private API end ---
+
+@interface MenuControllerDelegate : NSObject <MenuControllerCocoaDelegate> {
+  id<NSObject> _menuOpenObserver;
+}
+@end
+
+@implementation MenuControllerDelegate
+
+- (void)dealloc {
+  if (_menuOpenObserver)
+    [[NSNotificationCenter defaultCenter] removeObserver:_menuOpenObserver];
+
+  [super dealloc];
+}
+
+- (void)controllerWillAddItem:(NSMenuItem*)menuItem
+                    fromModel:(ui::MenuModel*)model
+                      atIndex:(NSInteger)index {
+  static const bool newBadgeFeatureEnabled =
+      base::FeatureList::IsEnabled(views::features::kEnableNewBadgeOnMenuItems);
+  if (newBadgeFeatureEnabled && model->IsNewFeatureAt(index)) {
+    NSTextAttachment* attachment =
+        [[[NSTextAttachment alloc] initWithData:nil ofType:nil] autorelease];
+    attachment.image = NewTagImage();
+    NSSize newTagSize = attachment.image.size;
+    attachment.bounds =
+        NSMakeRect(0, views::NewBadge::kNewBadgeBaselineOffsetMac,
+                   newTagSize.width, newTagSize.height);
+
+    NSMutableAttributedString* attrTitle =
+        MutableAttributedStringForMenuItemTitleString(menuItem.title);
+    [attrTitle
+        appendAttributedString:[NSAttributedString
+                                   attributedStringWithAttachment:attachment]];
+
+    menuItem.attributedTitle = attrTitle;
+  }
+
+  if (model->IsAlertedAt(index)) {
+    NSImage* iphDotImage = IPHDotImage();
+    menuItem.onStateImage = iphDotImage;
+    menuItem.offStateImage = iphDotImage;
+    menuItem.mixedStateImage = iphDotImage;
+
+    DCHECK(!_menuOpenObserver);
+    _menuOpenObserver = [[NSNotificationCenter defaultCenter]
+        addObserverForName:NSMenuDidBeginTrackingNotification
+                    object:menuItem.menu
+                     queue:nil
+                usingBlock:^(NSNotification* note) {
+                  NSMenu* menu = note.object;
+                  if ([menu respondsToSelector:@selector(_menuImpl)]) {
+                    NSCarbonMenuImpl* menuImpl = [menu _menuImpl];
+                    if ([menuImpl respondsToSelector:@selector
+                                  (highlightItemAtIndex:)]) {
+                      [menuImpl highlightItemAtIndex:index];
+                    }
+                  }
+                }];
+  }
 }
 
 @end
@@ -141,9 +214,6 @@
 namespace internal {
 namespace {
 
-constexpr CGFloat kNativeCheckmarkWidth = 18;
-constexpr CGFloat kNativeMenuItemHeight = 18;
-
 // Returns the first item in |menu_controller|'s menu that will be checked.
 NSMenuItem* FirstCheckedItem(MenuControllerCocoa* menu_controller) {
   for (NSMenuItem* item in [[menu_controller menu] itemArray]) {
diff --git a/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html b/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html
index 31727bd..6e93129 100644
--- a/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html
+++ b/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html
@@ -58,6 +58,7 @@
         -webkit-mask-position: center;
         -webkit-mask-repeat: no-repeat;
         -webkit-mask-size: var(--cr-icon-button-icon-size);
+        -webkit-transform: var(--cr-icon-image-transform, none);
         background-color: var(--cr-icon-button-fill-color);
         height: 100%;
         transition: background-color var(--cr-icon-button-transition);